tags:

views:

76

answers:

5

We use Excel interop in numerous places in our code, however I have one function which doesn't ever seem to close down the Excel process it uses.. I've simplified the code down, and it just seems like whenever I open a workbook in this function it stays hanging around. I've included the code below, I've made sure every object is defined, released and nulled, and yet Excel stays running.

        System.Data.DataTable dtExcelSheet = new System.Data.DataTable();
        Microsoft.Office.Interop.Excel.Application excelObject = new Microsoft.Office.Interop.Excel.Application();

        dtExcelSheet.Columns.Add("SheetName", typeof(string));
        dtExcelSheet.Columns["SheetName"].ReadOnly = false;
        dtExcelSheet.Columns["SheetName"].Caption = "Sheet Name";


        Workbooks wbs = excelObject.Workbooks;

        Workbook excelWorkbook = wbs.Add(excelFile);

        excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
        wbs.Close();
        excelObject.Quit();

        int i1 = Marshal.FinalReleaseComObject(excelWorkbook);
        int i2 = Marshal.FinalReleaseComObject(wbs);
        int i3 = Marshal.FinalReleaseComObject(excelObject);


        excelWorkbook = null;
        wbs = null;
        excelObject = null;

        GC.GetTotalMemory(false);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.GetTotalMemory(true);       
+1  A: 

Make sure you're not calling Excel on a background thread. I had a similar problem where I was cleaning up all the COM objects, but Excel still wasn't dying and that turned out to be the problem.

I wrote up my experiences and a solution here.

Samuel Jack
+1  A: 

Complete guess, but does this row:

dtExcelSheet.Columns.Add("SheetName", typeof(string));

return the column that is created?

If so you'd probably need to store that reference and clean that up at the end.

Edit: Also, I don't think you should be setting the variables to null at the end, I think that just accesses them again.

And you shouldn't have to tell the GC to collect etc, but I assume that might be your test code.

ho1
The anonymous column would be my guess, too.
Mathias
Thats a column in a data table, nothing connected to the Excel Sheet....
Rick Harby
@Rick: You're right, I misread it. The only thing left of my answer then would be to not set them to null at the end, which even though it sounds pointless might be worth trying.
ho1
+1  A: 

It's been a while since I've mucked around with this stuff, so nothing jumps out at me.

My usual recommendation in these cases is to set your excel application object to Visible = true to see if there's not a dialog popping up on you. Excel/Word will sometimes refuse to shut down if they think there's a modal dialog open no matter what else you may do. It's the first thing to check anyway.

Jim Leonardo
If that's happening you just need to set DisplayAlerts = false
Andrew Koester
A: 

I tried running your code, but I could not reproduce the issue. If I step through it with a debugger, the Excel process terminates after the last call to FinalReleaseComObject. Is it possible that the culprit lies in some code not present in your listing?

When using COM interop, I have found that it is all too easy to increment the reference count on COM objects in very subtle ways. For example, let's say you do something like this:

excelWorkbook.Foo.Bar();

This can increment the reference count on the Foo object, leaving you with no means of releasing it afterwards...and leaving the Excel process lingering around until you shut down your app. You can re-write the above line of code like this:

Foo foo = excelWorkbook.Foo;
foo.Bar();
Marshal.ReleaseComObject(foo);

It's not as pretty, but it will decrement the reference count on the Foo object after you are done using it.

Jim Killingsworth
A: 

Same thing happened to me the other day. See my question on Excel Automation as to the fix (question deals with multiple row deletion mostly but I also had the same problem as you turns out it has to do with releasing all the COM objects properly).

0A0D