2012-01-23 26 views
6

我遇到了一些我正在調試的代碼問題。 Excel interop用於從工作簿中提取一些值;但是,Excel在程序退出後仍然保持打開狀態。我已經嘗試了傳統的解決方案,但它仍保持在所有機器上打開一個參考到Excel,其中代碼運行互操作後,Excel進程保持打開狀態;傳統方法不起作用

private void TestExcel() 
    { 
     Excel.Application excel = new Excel.Application(); 
     Excel.Workbooks books = excel.Workbooks; 
     Excel.Workbook book = books.Open("C:\\test.xlsm"); 

     book.Close(); 
     books.Close(); 
     excel.Quit(); 

     Marshal.ReleaseComObject(book); 
     Marshal.ReleaseComObject(books); 
     Marshal.ReleaseComObject(excel); 
    } 

即使這個簡單的代碼保持與多個文件在運行過程中(XLSM,XLSX, XLS)。現在我們有一個解決方法來殺死我們已經打開的Excel進程,但我更願意爲了我自己的理智而努力工作。

我應該補充一點,我已經縮小到Workbook變量。如果我刪除對books.Open()的呼叫以及對book的所有引用,則它將成功關閉。

+0

當我測試它時,你的代碼工作,你可能會在運行時得到異常導致該問題? – msmucker0527

回答

11

這已經成功地爲我工作:

 xlApp.Quit(); 

     //release all memory - stop EXCEL.exe from hanging around. 
     if (xlWorkBook != null) { Marshal.ReleaseComObject(xlWorkBook); } //release each workbook like this 
     if (xlWorkSheet != null) { Marshal.ReleaseComObject(xlWorkSheet); } //release each worksheet like this 
     if (xlApp != null) { Marshal.ReleaseComObject(xlApp); } //release the Excel application 
     xlWorkBook = null; //set each memory reference to null. 
     xlWorkSheet = null; 
     xlApp = null; 
     GC.Collect(); 
+2

標記爲答案,因爲這是正確的。雖然它仍然不能在我的開發機器上工作,但它可以在乾淨的安裝或家用電腦上運行。奇。 – bradenb

3

我是一名COM業餘愛好者,很久以前在一個項目中用它做了一件小事,但這裏有一段我​​在那裏使用的片段。我可能在網上找到它,不記得了。在任何情況下,我將其粘貼黃袍加身;)

public static class ComBlackBox 
{ 
    public static void ReleaseObject(object obj) 
    { 
     try 
     { 
      System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
      obj = null; 
     } 
     catch (ArgumentException ex) 
     { 
      obj = null; 
      MessageBox.Show("Unable to release the Object " + ex.Message); 
     } 
     finally 
     { 
      GC.Collect(); 
     } 
    } 
} 

我無法現在嘗試一下,但它可能工作(我真的不記得任何細節)。也許它會幫助你。隨意點出這個代碼的任何明顯的問題,我真的很遠未COM素養;)

+1

這個工作部分是因爲你在最後的try try catch中有GC.Collect()。然而,它並沒有真正接近excel,直到它到達最後的部分。爲什麼?因爲你的對象是按值傳遞的,如果你將表單/工作表或工作簿或Excel傳遞給函數。無論你如何處理對象本身,它們的COM值都會保持不變。除非你可以通過引用傳遞這些COM對象,但我試過了,它不會讓我。 –

2

這是我解決這個問題如何得到:

// Store the Excel processes before opening. 
Process[] processesBefore = Process.GetProcessesByName("excel"); 

// Open the file in Excel. 
Application excelApplication = new Application(); 
Workbook excelWorkbook = excelApplication.Workbooks.Open(Filename); 

// Get Excel processes after opening the file. 
Process[] processesAfter = Process.GetProcessesByName("excel"); 

// Now find the process id that was created, and store it. 
int processID = 0; 
foreach (Process process in processesAfter) 
{ 
    if (!processesBefore.Select(p => p.Id).Contains(process.Id)) 
    { 
     processID = process.Id; 
    } 
} 

// Do the Excel stuff 

// Now close the file with the COM object. 
excelWorkbook.Close(); 
excelApplication.Workbooks.Close(); 
excelApplication.Quit(); 

// And now kill the process. 
if (processID != 0) 
{ 
    Process process = Process.GetProcessById(processID); 
    process.Kill(); 
} 
0

此代碼適用於我。

//Declare separate object variables 
Excel.Application xlApp = new Excel.Application(); 
Excel.Workbooks xlWorkbooks = xlApp.Workbooks; 
Excel.Workbook xlWorkbook = xlWorkbooks.Add(Missing.Value); 
Excel.Worksheet xlWorksheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(1); 

//Create worksheet 

xlWorkbook.Close(false, Missing.Value, Missing.Value); 
xlWorkbooks.Close(); 
xlApp.Quit(); 

Marshal.FinalReleaseComObject(xlWorksheet); 
Marshal.FinalReleaseComObject(xlWorkbook); 
Marshal.FinalReleaseComObject(xlWorkbooks); 
Marshal.FinalReleaseComObject(xlApp); 

xlWorksheet = null; 
xlWorkbook = null; 
xlWorkbooks = null; 
xlApp = null; 

GC.Collect(); 

This article from Microsoft有關於這個問題的一些很好的信息。

相關問題