2013-11-02 79 views
1

我知道很多類似的問題,在這裏提出,我已經通過其中大部分都沒有找到解決方案來滿足我的好奇心(我認爲我的案例有點多具體)。
我想從我的WPF應用程序中的Excel工作簿的命名範圍的名稱填充集合。結果是即使在我的應用程序關閉後仍在運行的Excel進程。我已將問題本地化爲以下代碼片段。沒有它,一切正常:無法關閉C#代碼中的Excel進程

foreach (Excel.Name name in names) 
{ 
     namedRanges.Add(name.Name);        
} 

所以,顯然這裏的東西不會被釋放。我還沒有找到像其他Excel對象一樣關閉/處理/退出「Excel.Name」的方法。請建議如何做到這一點。我使用的解決方法是殺死特定的進程,但我寧願瞭解背後的問題,並嘗試提出更相關的解決方案。下面是完整的代碼片段:

 Excel.Application excel = new Excel.Application(); 
    excel.Visible = false; 
    Excel.Workbooks wbooks = excel.Workbooks; 
    Excel.Workbook wbook = wbooks.Open(Proc.ExpenseFullPath); 

    ObservableCollection<string> namedRanges = new ObservableCollection<string>(); 
    Excel.Names names = wbook.Names; 

    foreach (Excel.Name name in names) 
    { 
      namedRanges.Add(name.Name);        
    }       

    wbook.Close(); 
    wbooks.Close(); 
    excel.Quit(); 

編輯: 我發現瞭如何使其發揮作用。我更換了有問題 「的foreach」 有:

for (int i = 1; i <= names.Count; i++) 
{ 
    namedRanges.Add(names.Item(i).Name); 
    Marshal.FinalReleaseComObject(names.Item(i)); 
} 
+0

有一個COM迭代器在你的foreach循環中使用。你不能到達它,excel.Quit()不會停止運行Excel,直到迭代器被垃圾回收。當你的程序退出時,肯定會發生這種情況,這迫使最後一次通過所有終結器。你需要找出你的程序爲什麼沒有正常退出。例如,不要使用Debug + Stop Debugging。 –

+0

感謝您的想法。我必須照顧每個Excel.Name,因爲它們也是COM。不知道爲什麼,但ReleaseComObject不起作用,而FinalReleaseComObject沒有工作。 – Hoodahelll

回答

0

補充一點:

Marshal.ReleaseComObject(wbook); 
Marshal.ReleaseComObject(excel); 
1

Here is an excellent post約沒有得到正確釋放在你們這樣的情況下COM對象。該項目的

  1. 更改的構建模式,以「釋放」(在調試模式下,COM對象有一個困難時期他們引用的處置。
  2. 刪除了所有雙點表達式(所有的COM對象應掛鉤一個變量,這樣他們可以被釋放)
  3. 調用GC.Collect的(),GC.WaitForPendingFinalizers(),和Marshal.FinalReleaseComObject()明確地在finally塊

你可能想試試這個:

Marshal.ReleaseComObject(names); 

對不起,我可以離開這個作爲一個評論,因爲我沒有足夠的聲譽呢。

0

幾年前,我遇到過類似的問題,並使用了一些技術來對付它。我們的用例可能與您的用例有所不同 - 我們有一個長期運行的服務,它產生了多個excel實例,以便在之前(嘗試)關閉它們。

我從這裏發現了有關Win32作業api的信息http://www.xtremevbtalk.com/showpost.php?p=1335552&postcount=22,並且幾乎將代碼逐字複製。它的Excel實例註冊到你的主機應用程序的PID,如果您的應用程序死了那麼Excel中與它死 - 即使主機崩潰,我們使用它,如下所示:

uint pid = 0; 
GetWindowThreadProcessId(new IntPtr(_excel.Hwnd), out pid); 
_job = new Job(); 
_job.AddProcess(Process.GetProcessById((int) pid).Handle); 

其次,我們運行一個名爲「NAR功能「對用Excel分配的任何東西:

private static void NAR(object o) 
{ 
    if (o == null) return; 
    try 
    { 
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o);     
    } 
    catch { } 
    finally 
    { 
     o = null; 
    } 
} 

終於有垃圾收集的咒語,你會要執行爲你關閉了:

private static void GcCleanup() 
{ 
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(); 
} 

我不記得爲什麼它做了兩次,我記得有一個原因。我不能說這些技術都是馴服Excel的好方法,但它對我有用!