3
votes

I am using the below methods. After this code block executes, I find that Microsoft Excel is still running in the background via checking Task Manager.

Edit: Exactly one Microsoft Excel background process remains live. I am just adding this because when I first began working with Excel and Interop COM objects, sometimes many processes would stay running after the functions finished executing.

How do I ensure that Excel is not running in the background after my current function is executed?


I declare these variables with global scope because several functions end up needing them:

private Excel.Application xls = null;
private Excel.Workbooks workBooks = null;
private Excel.Workbook workBook = null;
private Excel.Sheets sheets = null;
private Excel.Worksheet workSheet = null;

This method is for checking if a sheet exists in a given workbook:

private bool sheetExists(string searchString)
{
    xls = new Excel.Application();
    workBooks = xls.Workbooks;
    workBook = workBooks.Open(workbookPath); // <- Where the workbook is saved
    sheets = workBook.Sheets;

    bool isFound = false;

    foreach (Excel.Worksheet sheet in sheets)
    {
        // Check the name of the current sheet
        if (sheet.Name == searchString)
        {
            Marshal.ReleaseComObject(sheet);
            isFound = true;
            break;
        }

        Marshal.ReleaseComObject(sheet);
    }

    cleanUp(true, xls, workBooks, workBook, sheets);

    return isFound;
}

This function is for releasing the COM objects:

private void cleanUp(bool saveTrueFalse, params object[] comObjects)
{
    workBook.Close(saveTrueFalse);

    xls.Application.Quit();
    xls.Quit();

    foreach (object o in comObjects)
    {
        Marshal.ReleaseComObject(o);
    }

    workSheet = null;
    sheets = null;
    workBook = null;
    workBooks = null;
    xls = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
1
Yet another case of not understanding how the garbage collector works. Covered many times here already, like here.Hans Passant

1 Answers

-1
votes

I'd like to see a proper solution but this hack was the only way I could get it to work. It seems that the interop library is not good at all at shutting the process down when told. If running in threads, you'll get processes started for each thread. I would keep track of the process id after one started by scanning processes by name and keeping track of new processes. I was doing this on a server so I knew all processes were interop started and not started by an actual user. After I was done with the logic, I would start a timer that would try to kill the process every minute or so. Eventually it would shut it down. I also had some code that would kill any Excel processes on startup in case they weren't killed properly the last time the app was running.

Let me know if you want sample code for killing processes by name or id. I don't have it readily available, or a quick SO search should bring some good samples.