If you have ever worked with Excel in the .Net environment, you likely have run across the occasional orphan and they can be a pain to clean up
Recently I was doing just this, and my Task Manager was filling up with orphans fast. I was calling for the Excel Process to close, but that wasn't working most of the time. So I came up with a more elaborate way to make them disappear. Basically I found out that in order to close the application, you have to close the workbooks, and in order to close the workbooks, you have to close each workbook individually, and to close those, you have to close each worksheet in those workbooks individually. I also included COM management, so we are hitting this with multiple attacks to make sure they stay dead! So the super-overkill-do-everything process is:
- Collect each worksheet individually
- Collect each workbook individually
- Delete the worksheets
- Release the worksheets
- Null the worksheets
- Delete the workbooks
- Release the workbooks
- Null the workbooks
- Close the workbooks collection
- Quit the application
- Release the application
- Null the application
- Collect garbage
Here's how
After your work is done, you are left with a Microsoft.Office.Interop.Excel.Application named 'exc', call killExcel(exc):
protected void killExcel(Microsoft.Office.Interop.Excel.Application exc)
{
try
{
List<Microsoft.Office.Interop.Excel.Workbook> wbs = new List<Microsoft.Office.Interop.Excel.Workbook>();
List<Microsoft.Office.Interop.Excel.Worksheet> wss = new List<Microsoft.Office.Interop.Excel.Worksheet>();
foreach (Microsoft.Office.Interop.Excel.Workbook wb in exc.Workbooks)
{
foreach (Microsoft.Office.Interop.Excel.Worksheet ws in wb.Worksheets)
wss.Add(ws); // collect worksheets
wbs.Add(wb); // collect workbooks
}
for (int i = 0; i < wss.Count; i++)
{
wss[i].Delete();
System.Runtime.InteropServices.Marshal.ReleaseComObject(wss[i]); // release it
wss[i] = null; // null it
}
for (int i = 0; i < wbs.Count; i++)
{
wbs[i].Close(null, null, null);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wbs[i]); // release it
wbs[i] = null; // null it
}
exc.Workbooks.Close(); // so you can close this
exc.Quit(); // so you can quit this
System.Runtime.InteropServices.Marshal.ReleaseComObject(exc); // release it
exc = null;
GC.Collect(); // this sets up the finalizers
GC.WaitForPendingFinalizers();
GC.Collect(); //apparently this kills it
GC.WaitForPendingFinalizers();
}
catch (Exception ex)
{
// deal with it fool!
}
}
Yes this is overkill, but I think I covered all possible ways to kill you processes, so they should be more dead than Elvis; no more orphans - yay for iteration!
Some useful links:
http://www.thescarms.com/dotnet/ExcelObject.aspx
http://www.devcity.net/Articles/239/3/article.aspx
http://krgreenlee.blogspot.com/...ting-excel_10.html