2014-02-26 212 views
4

我正在使用interop庫從excel文件的工作表中讀取一些數據。我通過使用Microsoft.Office.Interop.Excel獲得數據,然後讀取表單中的所有數據。Excel進程仍在後臺運行

Application ExcelApp = new Excel.Application(); 
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath); 
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName]; 
Range excelRange = excelWorksheet.UsedRange; 
//...for loops for reading data 
ExcelApp.Quit(); 

但經過我的應用程序終止,我想修改我的excel文件,不得不同時開放了一些問題。顯然,即使我打電話給ExcelApp.Quit(),excel進程仍會繼續在後臺運行。有沒有辦法正確關閉應用程序使用的excel文件?我是c#的新手,所以我可能在這裏錯過了一些東西。

編輯:解決!顯然有一個rule COM對象,不鼓勵使用2點。

Excel.Application ExcelApp2 = new Excel.Application(); 
Excel.Workbooks excelWorkbooks = ExcelApp2.Workbooks; 
Excel.Workbook excelWorkbook = excelWorkbooks.Open(excelFileName); 
Excel._Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName]; 
//... 
excelWorkbook.Close();  
Marshal.ReleaseComObject(excelWorkbook); 
Marshal.ReleaseComObject(excelWorksheet); 
Marshal.ReleaseComObject(excelRange); 
ExcelApp2.Quit(); 
+0

在看一看:http://stackoverflow.com/questions/9962157/safely-disposing-excel-interop-objects -in-c – CJBS

+0

你有沒有試過這個:http://support.microsoft。com/kb/Q317109 –

+0

@CJBS他們也沒有找到答案!但我會嘗試實施其中的一個建議。謝謝! – rrh

回答

9

還有另一個類似的問題 - 和答案(https://stackoverflow.com/a/17367570/3063884),其中解決方案是避免使用雙點符號。相反,請爲沿途使用的每個對象定義變量,並在每個對象上單獨使用Marshal.ReleaseComObject

從鏈接的溶液直複製:

var workbook = excel.Workbooks.Open(/*params*/) 

--->改用 - >

var workbooks = excel.Workbooks; 
var workbook = workbooks.Open(/*params*/) 

然後,在完成時,釋放每個COM對象:

Marshal.ReleaseComObject(workbook); 
Marshal.ReleaseComObject(workbooks); 
Marshal.ReleaseComObject(excel); 
+0

我剛剛發現同樣的問題,它的工作!謝謝。 – rrh

+0

不客氣。 COM可能很混亂。 – CJBS

1

您沒有關閉您的工作簿。關閉它,然後退出Excel應用程序之前釋放它:

excelWorkbook.close(); 
Marshal.ReleaseComObject(excelWorkbook); 
ExcelApp.Quit(); 
+0

錯誤仍然彈出。它說「名稱爲...的文檔已經打開」 – rrh

0

互操作是出了名的越野車......我用我的節能工作簿,不再有使用Excel時保持打開,我離開我的應用程序的問題後,下面的方法:

while (Marshal.ReleaseComObject(wb) > 0); 
while (Marshal.ReleaseComObject(xl) > 0); 

wb = null; 
xl = null; 

GC.WaitForPendingFinalizers(); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

wb是我的工作簿對象,而xl是我的Excel.Application對象。

+0

這似乎也不起作用。我可以看到它現在是多麼的怪異,這太令人討厭了! – rrh

+0

在調用上面的代碼之前,你正在保存並關閉你的東西嗎? 我這樣做: wb.SaveAs( \t _saveFile, \t Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, \t Type.Missing, \t Type.Missing, \t假, \t假的, \t Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, \t Type.Missing, \t Type.Missing, \t Type.Missing, \t Type.Missing, \t Type.Missing ); wb.Saved = true; – John

1

長時間沒有答案,但是對我來說有效的就是調用GC.Collect();從呼叫者即,

代替

main() 
{ 
    ... 
    doexcelstuff(); 
    ... 
} 

void doexcelstuff() 
{ 
    Excel.Application ExApp2 = new Excel.Application(); 
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName); 
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName]; 
    //... 
    excelWb.Close(); 
    ExApp2.Quit();  
    Marshal.ReleaseComObject(excelWb); 
    Marshal.ReleaseComObject(excelWorksheet); 
    Marshal.ReleaseComObject(ExApp2); 
    excelWb = null; 
    excelWorksheet= null; 
    ExApp2= null; 
    GC.Collect(); 
} 

使用上述Excel不會死

而是一個非常小的變化,其中GC從

main() 
{ 
    ... 
    doexcelstuff(); 
    GC.Collect();  // <<-- moved the GC to here (the caller) 
    ... 
} 

void doexcelstuff() 
{ 
    Excel.Application ExApp2 = new Excel.Application(); 
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName); 
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName]; 
    //... 
    excelWb.Close(); 
    ExApp2.Quit();  
    Marshal.ReleaseComObject(excelWb); 
    Marshal.ReleaseComObject(excelWorksheet); 
    Marshal.ReleaseComObject(ExApp2); 
    excelWb = null; 
    excelWorksheet= null; 
    ExApp2= null; 
    // removed the GC from here 
} 

稱爲我的猜測是垃圾收集器還需要靜靜地清理堆內部創建的臨時值(包括refs/pointers) - 一些我猜在這種情況下,它指向COM對象。

(只是需要的機器的源代碼下面是如何工作的理解點點。)