在進行用戶端程式設計時,經常需要進行office自動化操作,其中對于Excel使用大概又是其中最為頻繁的。不過,讓大家頗為郁悶的是,經常會有excel程序不能被正常關閉。不論大家怎樣小心或者是單步跟蹤來找問題,總是會有未被釋放的com object 。我個人感覺這不能不說是office自動化的一個瑕疵,功能已經很傻瓜了,而其使用卻又需要這麼謹小慎微。
以前在使用VC++6.0時,就經常會遇到這個問題,最近更新到VS2010,改玩C#了,本以為由于自帶的GC功能而能自動解決這個問題,沒想到,還是會出現。看來是com設計的問題了。
從google的搜尋結果來看,主要的解決方法無外乎兩種:一種是謹小慎微,對于每個變量都予以儲存,到最後記得釋放;另一種則是比較野蠻了,直接kill掉殘留excel程序。
方法1從理論上固然可取,我想各位肯定想正确的使用并最終完全釋放掉所有涉及資源,但是由于實際操作中涉及的對象衆多,難免挂一漏萬,是以實際上還是會出問題。有人甚至對excel中的主要對象進行了再封裝,可以自動釋放對于com object的引用。
方法2看起來野蠻,但是操作簡單。我在網上也看到了有些kill程序的方法,這些方法對excel程序不加區分,格殺勿論,會導緻使用者體驗問題。但是隻要提前儲存自己所調用excel程序的句柄則可以不必濫殺無辜。具體實施方案如下:
using System.Runtime.InteropServices;
using System.Diagnostics;
[ DllImport ( "user32.dll" )]
private static extern uint GetWindowThreadProcessId ( IntPtr hWnd , out uint lpdwProcessId );
/// <summary> Tries to find and kill process by hWnd to the main window of the process.</summary>
/// <param name="hWnd">Handle to the main window of the process.</param>
/// <returns>True if process was found and killed. False if process was not found by hWnd or if it could not be killed.</returns>
public static bool TryKillProcessByMainWindowHwnd(int hWnd)
{
uint processID;
GetWindowThreadProcessId((IntPtr)hWnd,out processID);
if(processID ==0)
return false;
try
{
Process.GetProcessById((int)processID).Kill();
}
catch(ArgumentException)
{
return false;
}
catch(Win32Exception)
{
return false;
}
catch(NotSupportedException)
{
return false;
}
catch(InvalidOperationException)
{
return false;
}
return true;
}
使用示例:
int hWnd = xl.Application.Hwnd;
// ...
// here we try to close Excel as usual, with xl.Quit(),
// Marshal.FinalReleaseComObject(xl) and so on
// ...
TryKillProcessByMainWindowHwnd(hWnd);
最後,給出上述解決方案的原連結:
http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects-in-c