tags:

views:

43

answers:

1

The following code sample worked just fine in Excel 2007, but when I installed Excel 2010 (32bit) it would leave the excel.exe process open unless I added the GC.Collect(). My simple question is am I doing something wrong? It looks like to me like I am releasing everything I use.

    public override void Update()
    {

        StatusBox.AddStatus("Opening File " + ImportPath);

        Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbook wb = app.Workbooks.Open(ImportPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
        Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1];

        Range rng = ws.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);

        int LastRow = rng.Row;

        StatusBox.AddStatus(LastRow.ToString() + " Rows Found in File");


        StatusBox.AddStatus("Closing File " + ImportPath);

        System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
        rng = null;

        System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
        ws = null;

        wb.Close(true, ImportPath, null);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
        wb = null;

        GC.Collect();

        app.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
        app = null;
    }
A: 

You need to call both GC.Collect / GC.WaitForPendingFinalizers and Marshall.FinalReleaseComObject.

See my answer here for details:

http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects-in-c/159419#159419

Note that the advice (and apparently the more popular answer) to "never use two dots" in any given command is valid, but virtually impossible to enforce in practice. If you make any mistake anywhere in your code, the Excel application will hang and there is no profiling tool on the planet that can help you -- you'd have to review all your code by eye. For a large code base, this is essentially impossible.

In your code, you do not have a call to GC.WaitForPendingFinalizers after your call to GC.Collect. This is necessary to ensure that your garbage collection calls are synchronous. (GC.Collect operates on a different thread, if you don't wait for it, the collection could occur out of order with respect to your subseqent object releases and you want to release minor COM objects, like Ranges, first, and the major COM objects like Workbooks and the Application, last.) After calling GC.Collect and GC.WaitForPendingFinalizers, you would then want to call Marshall.FinalReleaseComObject on your named references.

So, in short, the strategy is to call GC.Collect and GC.WaitForPendingFinalizers to release the COM objects to which you do not hold a reference and call Marshall.FinalReleaseComObject to release the COM objects to which you do hold a named reference.

-- Mike

Mike Rosenblum
While Hans listed correctly if was my reference to "ws.Cells." that was the problem (although I am unsure why it was not a problem in Excel 2007) I am marking this as the answer because it is a better explanation. There are also situations where I might pass my excel references to other libraries, while those are also under my control, theoretically they might not be.
Matthew Bierman
Glad that WS.Cells did the trick, but, yes, it is odd that different versions of Excel behave differently here. It could even be that memory pressure is different in each version so that GC.Collect is being implicitly called at the right time more or less by luck in one version but not the other. Your discussion of third party libraries, though, is the real problem -- some of them simply do not release their references properly, whether your code interacts with them or not. In these cases you have no choice but to use Process.Kill after calling Application.Close (or don't use the add-ins).
Mike Rosenblum