2010-10-27 43 views
3

下面的代碼示例在Excel 2007工作得很好,但是當我安裝了Excel 2010(32位),它會離開Excel.exe進程打開的,除非我添加了GC.Collect的()。我的簡單問題是我做錯了什麼?它看起來像我釋放我使用的一切。Excel 2010中的COM對象的引用不釋放

public override void Update() 
    { 

     StatusBox.AddStatus("Opening File " + ImportPath); 

     Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application(); 
     Microsoft.Office.Interop.Excel.Workbook wb = app.Workbooks.Open(ImportPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); 
     Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1]; 

     Range rng = ws.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing); 

     int LastRow = rng.Row; 

     StatusBox.AddStatus(LastRow.ToString() + " Rows Found in File"); 


     StatusBox.AddStatus("Closing File " + ImportPath); 

     System.Runtime.InteropServices.Marshal.ReleaseComObject(rng); 
     rng = null; 

     System.Runtime.InteropServices.Marshal.ReleaseComObject(ws); 
     ws = null; 

     wb.Close(true, ImportPath, null); 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(wb); 
     wb = null; 

     GC.Collect(); 

     app.Quit(); 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(app); 
     app = null; 
    } 
+0

我用Excel和MapPoint做了一些COM互操作。我不認爲我曾經需要使用ReleaseComObject。清除所有空引用並調用相關的關閉/關閉方法已足夠。任何人都可以在這些Office類型的情況下確認/詳細說明ReleaseComObject()的可能需求嗎? – winwaed 2010-10-27 15:45:07

+0

我在第一次編寫Excel 2003代碼時遇到掛起excel引用的問題時添加了ReleaseComObject。實際上,我已經閱讀了var = null;可能是不必要的。 – 2010-10-27 20:30:06

回答

1

您需要同時調用GC.Collect的/ GC.WaitForPendingFinalizers Marshall.FinalReleaseComObject。

見我的答案查看詳情:

How do I properly clean up Excel interop objects?

注意,建議(顯然更受歡迎的答案)在任何給定的命令「從不使用兩個點」是有效的,但幾乎不可能在實踐中執行。如果你在代碼中的任何地方犯了錯誤,Excel應用程序將會掛起,並且這個星球上沒有可以幫助你的分析工具 - 你必須仔細檢查你所有的代碼。對於大型代碼庫來說,這基本上是不可能的。

在你的代碼,你沒有你的電話到GC.Collect的後GC.WaitForPendingFinalizers通話。這對確保你的垃圾收集調用是同步的是非常必要的。 (GC.Collect在另一個線程上運行,如果您不等待它,則收集可能會出現與後續對象版本相關的錯誤,並且您想要釋放次要的COM對象,如範圍,首先,主要像工作簿和應用程序的COM對象,最後。)在調用GC.Collect和GC.WaitForPendingFinalizers之後,您將想要在您的命名引用上調用Marshall.FinalReleaseComObject。

因此,簡而言之,策略是調用GC.Collect和GC.WaitForPendingFinalizers以釋放不包含引用的COM對象,並調用Marshall.FinalReleaseComObject以釋放您持有的COM對象命名參考。

- Mike

+0

雖然漢斯正確地列出,如果我提到「ws.Cells」。這是問題所在(雖然我不確定爲什麼它不是Excel 2007中的問題),我將其標記爲答案,因爲它是更好的解釋。還有一些情況是我可能會把我的excel引用傳遞給其他庫,而這些庫也在我的控制之下,理論上他們可能不會。 – 2010-10-28 13:31:22

+0

很高興WS.Cells做到了這一點,但是,不錯,不同版本的Excel在這裏的表現有所不同。甚至可能是因爲每個版本的內存壓力都不同,所以GC.Collect在某個版本中或多或少被運氣所暗中調用,而不是其他版本。然而,你對第三方庫的討論是真正的問題 - 它們中的一些根本不會正確地釋放它們的引用,無論你的代碼是否與它們交互。在這些情況下,你別無選擇,只能在調用Application.Close(或不使用加載項)後使用Process.Kill。 – 2010-10-28 22:06:38