I have a web page in ASP.NET C# that opens an Excel file with Microsoft.Office.Interop.Excel classes.
The excel file has VBA code that runs on the Workbook_BeforeClose event.
When opening and closing the file with Excel, the code runs fine, with a prompt to save the changes after the code is run.
But when doing the same on the webpage with C#, the page just loads indefenitly. Debugging shows that it stops(waits?) at the line myExcelWorkbook.Close(true);
Here is what the C# code looks like:
using Excel = Microsoft.Office.Interop.Excel;
public string getExcelInfo(string value1, string value2, string mapPath)
{
Excel.Application myExcelApp;
Excel.Workbooks myExcelWorkbooks;
Excel.Workbook myExcelWorkbook;
object misValue = System.Reflection.Missing.Value;
myExcelApp = new Excel.Application();
myExcelWorkbooks = myExcelApp.Workbooks;
//Copy file to allow simultaneous executions
Random rnd = new Random();
int rand = rnd.Next(1000000);
File.Copy(mapPath+"/App_Data/ConfigAQNX01.xlsm", mapPath+"/App_Data/ConfigAQNX01"+rand.ToString() + ".xlsm");
//Open file, workbook and sheet
String fileName = mapPath+"/App_Data/ConfigAQNX01" + rand.ToString() + ".xlsm";
myExcelWorkbook = myExcelWorkbooks.Open(fileName, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue);
Excel.Worksheet myExcelWorksheet = (Excel.Worksheet)myExcelWorkbook.ActiveSheet;
//insert values
myExcelWorksheet.Cells[3, 2] = value1;
myExcelWorksheet.Cells[6, 2] = value2;
//Save so formulaes are executed
myExcelWorkbook.Save();
myExcelWorksheet = (Excel.Worksheet)myExcelWorkbook.ActiveSheet;
//read value in excel
Excel.Range currentRange = (Excel.Range)myExcelWorksheet.Cells[7, 4];
string Cost_Cad_Unit = currentRange.Value2.ToString();
//Close Excel
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.ReleaseComObject(currentRange);
Marshal.ReleaseComObject(myExcelWorksheet);
//Set SaveChange to true on close
myExcelWorkbook.Close(true); //This line is where processing takes forever, literraly
Marshal.ReleaseComObject(myExcelWorkbook);
Marshal.ReleaseComObject(myExcelWorkbooks);
myExcelApp.Quit();
Marshal.ReleaseComObject(myExcelApp);
currentRange = null;
myExcelWorksheet = null;
myExcelWorkbook = null;
myExcelWorkbooks = null;
myExcelApp = null;
return Cost_Cad_Unit;
}
Are there options that can be set to get the VBA code to run, or ways to know what makes it hang? Or are there limitations with Microsoft.Office.Interop.Excel to get Workbook_BeforeClose code to run?
Thank you,
Here is the VBA code:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim FileName, CalcSheet As String
Dim English As Boolean
Worksheets("Drawing").Activate
Worksheets("Drawing OE").Activate
Worksheets("Interface").Activate
Worksheets("Parameters").Range("Closing").Formula = "O"
If Worksheets("Parameters").Range("CreateDrawing").Value = "N" Then Exit Sub
If Worksheets("Interface").Range("digit_oper").Value = 4 Then
Sheets(Array("Drawing", "Drawing OE")).Select
Else
Sheets(Array("Drawing")).Select
End If
Worksheets("Drawing").Activate
FileName = ActiveSheet.Range("Drawingpdf").Value
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=FileName, _
Quality:=xlQualityStandard, IncludeDocProperties:=False, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
Worksheets("Calc").Activate
FileName = ActiveSheet.Range("Calcpdf").Value
English = Worksheets("Drawing").Range("English").Value
If English Then CalcSheet = "Calc EN" Else CalcSheet = "Calc"
Sheets(Array(CalcSheet)).Select
Worksheets(CalcSheet).Activate
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=FileName, _
Quality:=xlQualityStandard, IncludeDocProperties:=False, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
Worksheets("Parameters").Range("Closing").Formula = "N"
Worksheets("Interface").Activate
End Sub
I created a new method, GenerateFiles(), moved the code from Workbook_BeforeClose to this method and changing the C# code to :
...
myExcelWorkbook.Save();
myExcelApp.Run("GenerateFiles");
myExcelWorkbook.Close(false);
...
Now works.
It's as if myExcelWorkbook.Close creates an infinite loop with Workbook_BeforeClose when the Workbook_BeforeClose method doesn't execute "fast enough"...
Related
I am trying to save the data table values into excel. I have a Load Report button from which I am getting data into a grid view.
Load Report Button Code
private void BtnInvHD_Click(object sender, EventArgs e)
{
string dir = #"C:\Output\Log\HavingDuesLog";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
string location = Path.Combine(dir, "HavingDues_log_"+name+"_" + DateTime.Now.ToString("dd-MM-yy_hh:mm:ss") + ".xls");
string cs = LoginForm.cs;
date = dtPicker.Value.ToString("yyyy-MM-dd");
if (cnn.State == ConnectionState.Closed)
{
cnn.Open();
}
sqlCmd = new SqlCommand("RptIV030", cnn);
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#DateFrom", date);
SqlDataAdapter sqlSda = new SqlDataAdapter(sqlCmd);
sqlSda.Fill(dtData);
dGInvHD.DataSource = dtData;
writeExcelFile(location,dtData);
btnExport.Enabled = true;
//return dtData;
}
Write to Excel Function
public void writeExcelFile(string location, DataTable read)
{
//Create excel app object
Microsoft.Office.Interop.Excel.Application xlSamp = new Microsoft.Office.Interop.Excel.Application();
if (xlSamp == null)
{
MessageBox.Show("Excel is Not Installed");
//Console.WriteLine("Excel is not Insatalled");
//Console.ReadKey();
return;
}
//Create a new excel book and sheet
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlWorkBook = xlSamp.Workbooks.Add(misValue);
// get the reference of first sheet.
// store its reference to worksheet
xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xlWorkSheet = xlWorkBook.ActiveSheet;
// changing the name of active sheet
xlWorkSheet.Name = "Having Dues-" + name + "-Till-" + date;
// column headings
for (var i = 0; i < read.Columns.Count; i++)
{
xlWorkSheet.Cells[1, i + 1] = read.Columns[i].ColumnName;
}
// rows
for (var i = 0; i < read.Rows.Count; i++)
{
// to do: format datetime values before printing
for (var j = 0; j < read.Columns.Count; j++)
{
xlWorkSheet.Cells[i + 2, j + 1] = read.Rows[i][j];
}
}
//Save the opened excel book to custom location
//Dont forget, you have to add to exist location
xlWorkBook.SaveAs(location, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue,
Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlSamp.Quit();
//release Excel Object
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSamp);
xlSamp = null;
}
catch (Exception ex)
{
xlSamp = null;
MessageBox.Show(ex.ToString());
}
finally
{
GC.Collect();
}
}
When I execute my code am I able to view data into gridview but unable to write it into an excel file.
I am getting error at xlWorkBook.SaveAs(location, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
Error Message
The file could not be accessed. Try one of the following:
Make sure the specified folder exists.
Make sure the folder that contains the file is not read-only.
Make sure the filename and folder path do not contain any of the following characters: < > ? [ ] : | or *
Make sure the filename and folder path do not contain more than 218 characters.
Any help would be highly appreciated.
Use something Like this I think its useful:
xlSamp.ActiveWorkbook.SaveAs(filepath, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
xlSamp.ActiveWorkbook.Close(true, missing, missing);
xlSamp.Quit();
Make sure the filename and folder path do not contain more than 218 characters.
This error comes when your location path will be to long reduce path
Make sure the specified folder exists.
Make sure the folder that contains the file is not read-only.
Make sure your location folder must exists on that location and give
read write permission to that folder
Make sure the filename and folder path do not contain any of the following characters: < > ? [ ] : | or *
give folder name and filename proper format
I'm creating a windows service that will create excel sheets, I've used Microsoft.Office.Interop.Excel but got this Exception
Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE
I've attached a photo here
Exception photo attached
public void insertIntoSheet(string Name, DataTable dt)
{
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
//MessageBox.Show("Excel is not properly installed!!");
return;
}
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
for (int i = 1, j = 0; j < dt.Rows.Count; i++, j++)
{
xlWorkSheet.Cells[i, 1] = dt.Rows[j][0].ToString();
xlWorkSheet.Cells[i, 2] = dt.Rows[j][1].ToString();
xlWorkSheet.Cells[i, 3] = dt.Rows[j][2].ToString();
xlWorkSheet.Cells[i, 4] = dt.Rows[j][3].ToString();
xlWorkSheet.Cells[i, 5] = dt.Rows[j][4].ToString();
xlWorkSheet.Cells[i, 6] = dt.Rows[j][5].ToString();
}
//xlWorkSheet.Cells[1, 1] = "Sheet 1 content";
xlWorkBook.SaveAs(String.Format("d:\\{0}.xls", Name), Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
Class_Library.WriteErrorLog("Inserting the sheet method finished");
//MessageBox.Show("Excel file created , you can find the file d:\\csharp-Excel.xls");
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
Class_Library.WriteErrorLog(ex.Message);
//MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
NOTES: I've used the same code as a test in windows application and it worked as expected.
I've tried to write Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application(); and also tried to use the Name Excel only like Excel.Application xlApp = new Excel.Application();
Try Edit DCOMConfig
1.In DCOMCNFG, right click on the My Computer and select properties.
2.Go to Component /MyComputer/DCOMConfig
3.Go to Microsoft Excel Application property Security
4.In launch and Activation Permissions, click "Custamize" and add Network
Service to it and give it "Local launch" and "Local Activation" permission. give same As Acess Permissions and cofiguration Permissions Press OK and thats it. You can run my application now.
Go to Excel's options / trust center / Macro settings and check "Trust access to the VBA project object model"
I have wrote the following code for exporting my local database data to an excel file. The fact is that it is working properly, but I'd only like to export it with the actual date, or just month, like august, or something like that. Besides that, the problem that really matters is that it replaces every time the previously exported excel file. How can I change this thing? Thanks !
private void button3_Click_1(object sender, EventArgs e)
{
var connString = (#"Data Source=" + System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)) + #"\Angajati.sdf");
using (var conn = new SqlCeConnection(connString))
{
try
{
conn.Open();
var query = "SELECT * FROM info ";
var command = new SqlCeCommand(query, conn);
var dataAdapter = new SqlCeDataAdapter(command);
var dataTable = new DataTable();
dataAdapter.Fill(dataTable);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
Int16 i, j;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
for (i = 0; i <= dataGridView1.RowCount - 2; i++)
{
for (j = 0; j <= dataGridView1.ColumnCount - 1; j++)
{
xlWorkSheet.Cells[i + 2, j + 1] = dataGridView1[j, i].Value.ToString();
}
}
//adds column names to excel
string[] colNames = new string[dataGridView1.Columns.Count];
int col = 0;
foreach (DataGridViewColumn dc in dataGridView1.Columns)
colNames[col++] = dc.HeaderText;
char lastColumn = (char)(65 + dataGridView1.Columns.Count - 1);
xlWorkSheet.get_Range("A1", lastColumn + "1").Value2 = colNames;
xlWorkSheet.get_Range("A1", lastColumn + "1").Font.Bold = true;
xlWorkSheet.get_Range("A1", lastColumn + "1").VerticalAlignment
= Excel.XlVAlign.xlVAlignCenter;
xlWorkBook.SaveAs(#"C:\Users\Andrei\Documents\Visual Studio 2010\Projects\Stellwag\Stellwag\db.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
MessageBox.Show("Salvat cu succes");
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
If you don't want it to overwrite the same workbook every time then you'll need to specify a different file name rather than hard coding it in.
Something simple like creating the filename with the current datetime would normally be sufficient (you can change the format to suit you):
string fileName = #"db " + DateTime.Now.ToString("dd-MM-yyyy HH-mm-ss") + #".xls";
string filePath = Path.Combine(#"C:\Users\Andrei\Documents\Visual Studio 2010\Projects\Stellwag\Stellwag", fileName);
xlWorkBook.SaveAs(filePath, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
This would produce a file like this:
db 01-09-2015 10-32-35.xls
There is still not explicit check to see if the file exists, but unless you're clicking it every second it's unlikely to overwrite.
Am trying to put in some data into excel cells. I get HResult rnge exception. below is the code. And also am not able to wrap the text in the cell [1,B] . am a fresher in using Office apps and not able to find a solution .
myExcelApp = new Excel.Application();
myExcelApp.Visible = true;
myExcelWorkbooks = myExcelApp.Workbooks;
String fileName1 = "D:\\book1.xlsx";
myExcelWorkbook = myExcelWorkbooks.Open(fileName1, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue);
Excel.Worksheet myExcelWorksheet = (Excel.Worksheet)myExcelWorkbook.ActiveSheet;
String cellFormulaAsString = myExcelWorksheet.get_Range("A2", misValue).Formula.ToString();
Microsoft.Office.Interop.Excel.Range range = myExcelWorksheet.UsedRange;
myExcelWorksheet.Cells[1, "A"] = text;
myExcelWorksheet.Cells[1, "B"] = commentText;
// myExcelWorksheet.Cells[1, "C"] = OccuranceList;
Excel.Range r = myExcelWorksheet.get_Range("B7", "A");
r.EntireRow.AutoFit();
Excel.Range r = myExcelWorksheet.get_Range("B7", "A");
You are missing a row number for Cell A
Something like this?
Excel.Range r = myExcelWorksheet.get_Range("B7", "A1");
FOLLOWUP
I just want to wrap text in cell[1,"B"] as the string is very large. – user1665707 59 mins ago
I dont get any error now. But the text wrapping is not happening. a part of the text is not visible. – user1665707 17 mins ago
Yes, it will not autofit. See this link for the reason.
I am trying to export query result sets into an excel sheet. I need to run 8 queries, each of which will be a different sheet in the excel file. I also need to add a bit of formatting around the sheet (adding a header, making the report look nice, etc).
Currently, my code is just running a single query (so only a single sheet of data). This takes a LONG time to fill out 4000 rows with 7 columns and thats a tiny sample. Is there are better way to do this? Thanks so much!
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
string data = null;
int i = 0;
int j = 0;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
string cs = "oracle connection string filtered for online posting";
DataSet ds = new DataSet();
OracleConnection oconn = new OracleConnection(cs);
oconn.Open();
Model_Netstat netstat = new Model_Netstat();
OracleCommand oc = new OracleCommand(netstat.queryNetstatAll(session.caseName), oconn);
oc.CommandType = CommandType.Text;
OracleDataAdapter oda = new OracleDataAdapter(oc);
try
{
oda.Fill(ds);
} catch(Exception ex)
{
Console.Write(ex.Message);
}
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
for (j = 0; j <= ds.Tables[0].Columns.Count - 1; j++)
{
data = ds.Tables[0].Rows[i].ItemArray[j].ToString();
xlWorkSheet.Cells[i + 1, j + 1] = data;
}
}
xlWorkBook.SaveAs("test.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
Check the free OpenXML SDK 2 from Microsoft out, it does what you need without automation and that's much faster and is usable in ASP.NET too (automation is not supported there)...