Proper way of closing Excel application

2019-03-05 17:57发布

问题:

I'm writing an application, which accesses Excel file with this code:

RBTApplication = new Excel.Application();
RBTWorkbooks = RBTApplication.Workbooks;
RBTWorkbook = RBTApplication.Workbooks.Open(
    RBTDataSet.Instance.FilePath, 0, true, 5, "", "", true,
    Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
    "\t", true, false, 0, true, 1, 0 );
RBTWorksheet = (Excel.Worksheet)RBTWorkbook.Worksheets.get_Item( 1 );
RBTRange = RBTWorksheet.UsedRange;

After I load data that I need, I try to close Excel application with this piece of code:

RBTWorkbook.Close();
RBTApplication.Quit();
RBTWorksheet.ReleaseComObject();
RBTWorkbook.ReleaseComObject();
RBTWorkbooks.ReleaseComObject();
RBTApplication.ReleaseComObject();

My problem is that EXCEL.EXE process is still running. Simple solution like killing all Excel processes doesn't sound great, as my process can be one of many spreadsheets used at the same time. This one also affects opening new excel spreadsheets - every opens as read only until I don't kill this process.

So ... how to close this application properly OR kill this specific process (is there any way to get PID from COM object ?). I think I've found one (haven't tried) - get list of excell processes before and after opening new ExcellApp, compare lists (get difference), kill specific process knowing its PID. But this solution doesn't seem like a proper way of handling COM objects and other applications from within my app.

回答1:

You are not releasing all your COM objects.

For example:

RBTApplication.Workbooks.Open

Will instantiate a Workbooks object, as will:

RBTWorkbook.Worksheets.get_Item

Instead, use the Worksheets object you have already created:

RBTWorkbooks = ...
...
RBTWorkbooks.Open(...)
RBTWorkbooks.get_Item(...)

If your interop requirements are simple, and the interop code is localized, you can get away with carefully making sure you release all COM objects you reference, ideally using try/finally to make sure they are released even if an exception is thrown.

However it's very easy for you or a maintenance programmer down the line to forget one, so you might want to look at forcing garbage collection, for example see the answers to this question.