2016-04-25 70 views
1

我很難確定我的COM對象正在關閉,所以我不會離開在後臺運行的EXCEL.EXE進程。我瞭解到,雙點和聲明的鏈接是不好的,因爲這可能會導致COM對象掛起。我應該如何聲明一個Microsoft.Office.Interop.Excel.Worksheet,以便在C#中關閉它?

有誰知道如何修復這段代碼,以便我可以正確關閉並釋放工作表COM對象?

worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[strName]; 

編輯:我已經當我執行完這條線將關閉當前打開Excel對象使用app.Quit()試過了,但是這是行不通的。但是,如果我在這行之前調用它,app.Quit()會起作用。

回答

4

首先,爲了讓EXCEL.EXE進程退出,您不必顯式釋放所使用的所有COM對象。當您獲取對COM對象的另一個引用時,由.NET運行時隱式爲您創建的運行時可調用包裝程序(RCW)由GC收集,這將釋放基礎COM對象。

您所要做的就是調用Quit方法,釋放RCWs引用並讓GC收集它們。

//This runs the EXCEL.EXE process. 
Microsoft.Office.Interop.Excel.Application app = 
    new Microsoft.Office.Interop.Excel.Application(); 
//This locks the excel file either for reading or writing 
//depending on parameters. 
Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Open(...); 

... 

//Explicitly closing the book is a good thing. EXCEL.EXE is alive 
//but the excel file gets released. 
book.Close(); 

//This lets the EXCEL.EXE quit after you release all your references to RCWs 
//and let GC collect them and thus release the underlying COM objects. 
//EXCEL.EXE does not close immediately after this though. 
app.Quit(); 
app = null; 

二,如果你離開所謂的雙點代碼行,你不會造成任何內存泄漏。垃圾收集器將收集RCW並在某個時候釋放COM對象,即當它找到它時。

最後,如果您希望顯式地釋放RCW和相應的COM對象以最大限度地減少內存壓力,可以在釋放引用之後顯式調用GC來收集RCW,甚至顯式釋放底層COM對象在GC收集RCW之前。但要小心。這最後一種方式會讓您承擔在此之後從未使用剩餘的RCW或者您將有例外的情況。

using Microsoft.Office.Interop.Excel; 
using System.Runtime.InteropServices; 

Application app = new Application(); 
Workbooks books = clsExcelApplication.Workbooks; 
Workbook book = books.Open("..."); 
Sheets sheets = book.Sheets; 
Worksheet sheet = sheets["..."]; 

... 

//Trying to be as explicit as we can. 
book.Сlose(); 

//Revese order. Using FinalReleaseComObject is even more dangerous. 
//You might release an object used inside excel 
//code which might lead to some dreadful internal exceptions. 
int remainingRefCount; 
remainingRefCount = Marshal.ReleaseComObject(sheet); 
remainingRefCount = Marshal.ReleaseComObject(sheets); 
remainingRefCount = Marshal.ReleaseComObject(book); 
remainingRefCount = Marshal.ReleaseComObject(books); 
app.Quit(); 
remainingRefCount = Marshal.ReleaseComObject(app); 

請記住。如果你手動釋放COM引用超過EXCEL.EXE一輩子不依賴於的RCW,當你喜歡,你可以抵消他們...

sheet = null; 
sheets = null; 
book = null; 
books = null; 
app = null; 

在最明確的情況下,不要忘記檢查從返回Marshal.ReleaseComObject的。如果它不是零,除了剛剛發佈的RCW之外,其他人都持有對基礎COM對象的COM引用。

+0

我發現只要你確定你關閉了你處理的所有東西併發布excelapp.Quit它確實去了 - 我發現了一些premade exporttoexcel代碼中的一些問題,但是在最後設置excelapp = null時,這個確保沒有東西掛在任何東西上 – BugFinder

+0

GC不會釋放COM組件。你必須明確地做到這一點。 – Enigmativity

+1

@Enigmativity GC不發佈通過某些API獲取的純COM對象,但它釋放通過Runtime Callable Wrappers獲得的COM對象。在excel的情況下,它確實釋放它們。 –

相關問題