Excel can be quite a pain when automating, it's difficult to keep track of all the COM references since much of the access is collection based.
Rule of thumb: When accessing a collection property on an Excel reference, first take a reference to the collection, don't access it by it's parent property.
e.g. instead of doing...
ExcelApplication excel = new ExcelApplication();
excel.Workbooks[0].Worksheets...
etc etc..use as follows..
ExcelApplication excel = new ExcelApplication(rm);
ExcelWorkbooks xlBooks = excel.Workbooks();
ExcelWorkbook xlBook = xlBooks.Open("c:\\sales.xls");
ExcelWorksheets xlSheets = xlBook.Worksheets();
ExcelWorksheet xlSheet = xlSheets.Item(1);
ExcelRange xlRange = xlSheet.Cells();
Each one of these increments a COM reference and you need to release them all in order for excel to be correctly disposed at the end of your interop. Otherwise, you'll end of with hanging Excel processes.
I can see in the code you've posted that you're not doing this and it's probably what's caused the hanging process.
Something you may want is to use an Excel Wrapper. While I still say make sure you use Excel carefully and follow the rules for COM interop, the Excel Wrapper class offers a solution to make sure there are no orphaned Excel objects
Usage of this class is as follows...
using (var wrapper = new ExcelWrapper())
{
var application = wrapper.Application;
}
When the using block is finished, Excel will be terminated. Look at the Dispose method for implementation
namespace Excel.Helpers
{
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Microsoft.Office.Interop.Excel;
internal class ExcelWrapper : IDisposable
{
private class Window
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr ProcessId);
public static IntPtr GetWindowThreadProcessId(IntPtr hWnd)
{
IntPtr processId;
IntPtr returnResult = GetWindowThreadProcessId(hWnd, out processId);
return processId;
}
public static IntPtr FindExcel(string caption)
{
System.IntPtr hWnd = FindWindow("XLMAIN", caption);
return hWnd;
}
}
private Application excel;
private IntPtr windowHandle;
private IntPtr processId;
private const string ExcelWindowCaption = "MyUniqueExcelCaption";
public ExcelWrapper()
{
excel = CreateExcelApplication();
windowHandle = Window.FindExcel(ExcelWindowCaption);
processId = Window.GetWindowThreadProcessId(windowHandle);
}
private Application CreateExcelApplication()
{
Application excel = new Application();
excel.Caption = ExcelWindowCaption;
excel.DisplayAlerts = false;
excel.AlertBeforeOverwriting = false;
excel.AskToUpdateLinks = false;
return excel;
}
public Application Excel
{
get { return this.excel; }
}
public int ProcessId
{
get { return this.processId.ToInt32(); }
}
public int WindowHandle
{
get { return this.windowHandle.ToInt32(); }
}
#region IDisposable Members
public void Dispose()
{
if (excel != null)
{
excel.Workbooks.Close();
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
excel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
try
{
Process process = Process.GetProcessById(this.ProcessId);
if (process != null)
{
process.Kill();
}
}
catch
{
}
}
}
#endregion
}
}