天天看點

Visual C# Office自動化Excel程序殘留問題

       在進行用戶端程式設計時,經常需要進行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