Excel process still runs in background - c#

I'm reading some data from a sheet of an excel file using interop library. I get the data just fine by using Microsoft.Office.Interop.Excel and then reading all data in the sheet.
Application ExcelApp = new Excel.Application();
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath);
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
Range excelRange = excelWorksheet.UsedRange;
//...for loops for reading data
ExcelApp.Quit();
But after my application terminates, I tried to edit my excel file and had some problems while opening. Apparently the excel process keeps on running in the background even though I called ExcelApp.Quit(). Is there a way to properly close the excel file that the application uses? I'm new to c# so i'm probably missing something here.
Edit: Solved! Apparently there's a rule for com objects that discourages using 2 dots.
Excel.Application ExcelApp2 = new Excel.Application();
Excel.Workbooks excelWorkbooks = ExcelApp2.Workbooks;
Excel.Workbook excelWorkbook = excelWorkbooks.Open(excelFileName);
Excel._Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
//...
excelWorkbook.Close();
Marshal.ReleaseComObject(excelWorkbook);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(excelRange);
ExcelApp2.Quit();

There was another similar question - and answer (https://stackoverflow.com/a/17367570/3063884), in which the solution was to avoid using double-dot notation. Instead, define variables for each object used along the way, and individually use Marshal.ReleaseComObject on each one.
Copying straight from the linked solution:
var workbook = excel.Workbooks.Open(/*params*/)
---> instead use -->
var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)
Then, when done, release each COM object:
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);

Long time no answer but what worked for me was to call the GC.Collect(); from the caller,
i.e. instead of
main()
{
...
doexcelstuff();
...
}
void doexcelstuff()
{
Excel.Application ExApp2 = new Excel.Application();
Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
//...
excelWb.Close();
ExApp2.Quit();
Marshal.ReleaseComObject(excelWb);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(ExApp2);
excelWb = null;
excelWorksheet= null;
ExApp2= null;
GC.Collect();
}
Using above Excel does not die
but a very small change, to where the GC is called from
main()
{
...
doexcelstuff();
GC.Collect(); // <<-- moved the GC to here (the caller)
...
}
void doexcelstuff()
{
Excel.Application ExApp2 = new Excel.Application();
Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
//...
excelWb.Close();
ExApp2.Quit();
Marshal.ReleaseComObject(excelWb);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(ExApp2);
excelWb = null;
excelWorksheet= null;
ExApp2= null;
// removed the GC from here
}
My guess is the garbage collector needs to also quietly clean up internally created temp values (including refs/pointers) from the heap - some of which I guess in this case are pointing to COM objects.
(Just takes a smidgen of understanding of how machines work underneath the source code.)

You are not closing your workbook. Close it and then release it before quitting the Excel application:
excelWorkbook.close();
Marshal.ReleaseComObject(excelWorkbook);
ExcelApp.Quit();

For me this worked!
//Initializing
Application excelApp = new Application();
Workbook excelWorkbook = excelApp.Workbooks.Open(pathExcelFile, 0, true, 5, "", "",
true, XlPlatform.xlWindows, "\t", false, false, 0,
true, 1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];
//closing
excelWorksheet = null;
excelWorkbook.Close();
excelWorkbook = null;
excelApp.Quit();
excelApp = null;

Interop is notoriously buggy... I use the following method after saving my workbook, and no longer have issues with Excel remaining open when I exit my applications:
while (Marshal.ReleaseComObject(wb) > 0);
while (Marshal.ReleaseComObject(xl) > 0);
wb = null;
xl = null;
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
wb is my workbook object, and xl is my Excel.Application object.

For me this worked :
//opening
var excelFile = new Application();
Workbook workBook1 = excelFile.Workbooks.Open(goldenCopy_path);
Workbook workBook2 = excelFile.Workbooks.Open(new_path);
Worksheet goldWorkSheet, newWorkSheet;
goldWorkSheet = workBook1.Worksheets[1];
newWorkSheet = workBook2.Worksheets[1];
//closing
//it will release the workbook from visual studio
goldWorkSheet = null;
newWorkSheet = null;
workBook1.Close();
workBook2.Close();
workBook1 = null;
workBook2 = null;
excelFile.Quit();
excelFile = null;

This code worked on me.
Excel.Application excelApp = null;
Excel.Workbooks excelWorkbooks = null;
Excel.Workbook excelWorkbook = null;
Excel._Worksheet xlWorkSheet = null;
Excel.Range range = null;
excelApp = new Excel.Application();
excelWorkbooks = excelApp.Workbooks;
excelWorkbook = excelWorkbooks.Open(excelName);
xlWorkSheet = (Excel.Worksheet)excelWorkbook.ActiveSheet;
range = xlWorkSheet.Range["C3"] ;
range.Value = "Update Data";
Marshal.ReleaseComObject(range);
xlWorkSheet.SaveAs(path);
Marshal.ReleaseComObject(xlWorkSheet);
excelWorkbook.Close();
Marshal.ReleaseComObject(excelWorkbook);
excelWorkbooks.Close();
Marshal.ReleaseComObject(excelWorkbooks);
excelApp.Quit();
Marshal.ReleaseComObject(excelApp);

Related

How to open, read and close excel interop processes (C#)

I have to do a program which reads an excel xlsx file and stores the data in to the database. This my actual simple code, I don't even take the values from the excel file, but I'm not able to kill the process. I've googled a lot and I've tried many things, but the excel process stays alive.
public void readFile(path)
{
try
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlWorksheet = xlWorkbook.Sheets[1];
xlRange = xlWorksheet.UsedRange;
//------Here is where I will read the data
xlWorkbook.Close();
workbooks.Close();
xlApp.Quit();
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRange = null;
xlWorksheet = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
catch (Exception e)
{
}
}
And the process stays alive. I hope you can help me.
I've tried many things... The code below seems to work.
public void readFile(path)
{
try
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Sheets xlsheets = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlsheets = xlWorkbook.Sheets;
xlWorksheet = xlsheets[1];
xlRange = xlWorksheet.UsedRange;
//--------------------------------------------------------------------
xlWorkbook.Close();
workbooks.Close();
xlApp.Quit();
Marshal.FinalReleaseComObject(xlRangeColumns);
Marshal.FinalReleaseComObject(xlRangeRows);
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlsheets);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRangeColumns = null;
xlRangeRows = null;
xlRange = null;
xlWorksheet = null;
xlsheets = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
catch (Exception e)
{
}
}
There are very little differences. A month ago I would tell you that both codes are the same. Can someone tell me why this code works, while the first code doesn't?
Try putting this at the end of your code and it will kill your excel
foreach (var process in Process.GetProcessesByName("myExcelFilename"))
{
process.Kill();
}
You need either to put the objects into using blocks, or put the closing statements into a finally.
Whenever your application throws an exception, it will leave the interop open. What you should do instead is put your shutdown code in a finally block, which means that code will always be run. Like so:
public void readFile(string path)
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
try
{
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlWorksheet = xlWorkbook.Sheets[1];
xlRange = xlWorksheet.UsedRange;
//------Here is where I will read the data
}
catch (Exception e)
{
}
finally
{
xlWorkbook?.Close();
workbooks?.Close();
xlApp?.Quit();
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRange = null;
xlWorksheet = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
}
Another option is not to screw around with interop and use another library, such as EPPlus (available on NuGet), to handle the reading of excel files, which would close when the program closes.

Deleting a sheet in Excel

I tried almost everything that I could find here on StackOverflow but my code keeps throwing the following error:
Exception from HRESULT: 0x800A03EC
on the line with delete(). I was hoping you people could help me out.
Here's my current code
var xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook book =
xlApp.Workbooks.Open(File_name);
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
book.Worksheets.Add();
xlApp.DisplayAlerts = true;
book.Save();
book.Close();
xlApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(book);
Marshal.ReleaseComObject(xlApp);
And here's the other code i tried:
oXL.DisplayAlerts = false;
worksheet = (Excel.Worksheet)theWorkbook.Sheets[i];
((Excel.Worksheet)theWorkbook.Sheets[i]).Delete();
oXL.DisplayAlerts = true;
oWB.Save();
oWB.Close(false, missing, missing);
oSheet = null;
oWB = null;
oXL.Quit();
And some more variations
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Workbooks oMWB;
and i'm using this reference:
using Excel = Microsoft.Office.Interop.Excel;
Working with the Excel Interop libraries, I encountered this error many times. The main cause of this problem (a generic COM exception), most of the times, is that Excel tries to find something you've asked for, but Excel isn't able to find it. See this answer, it helped me a lot.
Reading these lines:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
I think that you're trying to delete a worksheet that's not existing. Check your Excel document.
I just made the most stupid mistake ever..... the excel file was a shared file, that's why i couldn't delete it..
Sorry for making such a stupid mistake, and thanks to everybody who tried to help me!
HRESULT: 0x800A03EC is an unknown COM error. This usually happens when Excel throws some error because your input or parameters were wrong.
This example provide msdn: Programmatically Deleting Worksheets from Workbooks
((Excel.Worksheet)this.Application.ActiveWorkbook.Sheets[4]).Delete();
So try next:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Sheets[2];
worksheet.Delete();
instead of:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
Try this:
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
xlApp.DisplayAlerts = true;
Also important to keep in mind, interop starts to count from 1, not from 0. so deleting item [0] or deleting the only sheet will throw you an exception. if you plan to remove the [2] worksheet, the third one will take its place. So make sure to remove from the last to the first.
this is code i have used to delete the excel sheet
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
return;
}
xlApp.DisplayAlerts = false;
string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Sample.xlsx";
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open(filePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Sheets worksheets = xlWorkBook.Worksheets;
worksheets[4].Delete();
worksheets[3].Delete();
xlWorkBook.Save();
xlWorkBook.Close();
releaseObject(worksheets);
releaseObject(xlWorkBook);
releaseObject(xlApp);
and use this
static void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
throw ex;
}
finally
{
GC.Collect();
}
}

xlApp.ActiveWorkbook returns null

I have a 2010 Excel ribbon add-in. When you press a button it simply writes some lines of data into the excel app. In order to write this data I need to get the active worksheet. And in order to get the active worksheet I need the activeWorkBook. I can get the xlApp fine with
xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
And it retrieves the xlApp fine But whenever I try to get the active workbook it returns null. No matter what. Unless I restart my computer. Then it works, but only the first time. Below is the whole block of code in context. I'm wondering how to fix the xlApp.ActiveWorkBook being null. So that I can get the active worksheet. And then write data to the active worksheet.
public void sendData()
{
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
Excel.Workbooks xlWorkBooks = null;
Excel.Worksheet xlWorkSheet = null;
object misValue = System.Reflection.Missing.Value;
try
{
xlApp = new Excel.Application();
//xlWorkBooks = xlApp.Workbooks;
//xlWorkBook = xlWorkBooks.Add(Properties.Settings.Default.FileToSend);
//xlWorkSheet = xlWorkBook.Sheets[1];
xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
xlWorkBook = (Excel.Workbook)xlApp.ActiveWorkbook;
xlWorkSheet = (Excel.Worksheet)xlWorkBook.ActiveSheet;
}
catch (Exception ex)
{
// handle error...
}
finally
{
if (xlWorkSheet != null)
Marshal.ReleaseComObject(xlWorkSheet);
if (xlWorkBook != null)
Marshal.ReleaseComObject(xlWorkBook);
if (xlWorkBooks != null)
Marshal.ReleaseComObject(xlWorkBooks);
if (xlApp != null)
Marshal.ReleaseComObject(xlApp);
}
Thanks in advance!
You're probably getting hold of the wrong Excel instance with your call to GetActiveObject. Use the Application reference passed into your COM add-in's OnConnection (or however your ribbon code is bootstrapped).
If you're using the Excel-DNA framework to make your managed Excel add-in, then you get hold of the right Application object with a call to ExcelDnaUtil.Application.

CleanUp excel interop c#

I'm saving links to excel file, but once i saved it the excel process is still runnning.
How i should relase this excel com object?
Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Add(1);
Microsoft.Office.Interop.Excel.Worksheet sheet = (Microsoft.Office.Interop.Excel.Worksheet)book.Worksheets[1];
for (int i = 0; i < Links.Count; i++)
{
sheet.Cells[i + 1, 1] = Links[i];
}
book.SaveAs("test.xlsx");
Marshal.ReleaseComObject(sheet);
sheet = null;
book.Close(true, null, null);
Marshal.ReleaseComObject(book);
book = null;
app.Quit();
Marshal.ReleaseComObject(app);
app = null;
Maybe "sheet.Cells" is a reference that you have to release:
var cells = sheet.Cells;
...
Marshal.ReleaseComObject(cells);

How to open a Template WorkBook and load its WorkSheets?

Hi i have written code using the Microsoft.Office.Interop.Excel dll but it is not supported online when i published my website. I then found the EPPlus dll witch is supported online but i am having troubles converting the code to use this new dll.
Old Code useing Interop.Excel:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet[] xlWorkSheet = new Excel.Worksheet[8];
public void ToSpreadSheet()
{
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(tempFolderPathAlt + "dvforms\\InvestecTemplate.xlsx", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet[0] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xlWorkSheet[1] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(2);
xlWorkSheet[2] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(3);
xlWorkSheet[3] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(4);
xlWorkSheet[4] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(5);
xlWorkSheet[5] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(6);
xlWorkSheet[6] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(7);
xlWorkSheet[7] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(8);
}
This worked great but now i need to use the EPPlus dll and i'm having problems.
using Excel = OfficeOpenXml;
Excel.ExcelPackage xlApp;
Excel.ExcelWorkbook xlWorkBook;
Excel.ExcelWorksheet[] xlWorkSeet = new Excel.ExcelWorksheet[8];
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(tempFolderPathAlt + "dvforms\\InvestecTemplate.xlsx");
Excel.ExcelPackage xlApp = new Excel.ExcelPackage(stream);
//This is where the problems begin, xlWorkBook.Worksheets.Add(1) is all underlined in red.
xlWorkSeet[0] = (Excel.ExcelWorksheet)xlWorkBook.Worksheets.Add(1);
How do i load the work sheets from my Excel template? I am unsure if i have done the above correctly, Please help i need it badly.
Thanks in advance.
FileInfo existingFile = new FileInfo(filePath);
using (var package = new ExcelPackage(existingFile))
{
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
int i = 0;
foreach(ExcelWorksheet worksheet in workBook.Worksheets)
{
xlWorkSeet1[i] = worksheet;
i = i + 1;
}
}
}
The function Add() takes in a string parameter that's the name of your worksheet. Try:
xlWorkSeet[0] = (Excel.ExcelWorksheet)xlWorkBook.Worksheets.Add("Sheet1");

Categories