2011-07-06 32 views
2

我在C#中使用COM Excel應用程序類。我處理了WorkbookBeforeClose。但是現在我無法正確釋放COM對象。如何在.NET中處理事件時釋放所有COM對象

請注意,我在處理此事件之前設法正確地釋放了COM對象,並且在註釋該部分代碼時,我的應用程序正常工作。

哪些COM對象沒有從內存中釋放,以及如何正確釋放它?

編輯: 我做了什麼:

public void Init() 
{ 
    ... 
    application = new Excel.Application(); 
    application.WorkbookBeforeClose += new Excel.AppEvents_WorkbookBeforeCloseEventHandler(application_WorkbookBeforeClose); 
} 
... 
void application_WorkbookBeforeClose(Excel.Workbook Wb, ref bool Cancel) 
    { 
     if (WorkbookBeforeClose != null) 
     { 
      ExcelCloseEventArgs args = new ExcelCloseEventArgs(); 
      WorkbookBeforeClose(this, args); 
      Cancel = args.Cancel; 
     } 
     else 
      Cancel = false; 
    } 
... 
private void closeExcel() 
    { 
     try 
     { 
      if (workbook != null) 
      { 
       workbook.Close(false); 
      } 
     } 
     catch (Exception e) { } 
     finally 
     { 
      if (workbooks != null) 
       Marshal.ReleaseComObject(workbooks); 
      if (workbook != null) 
       Marshal.ReleaseComObject(workbook); 
     } 

     try 
     { 
      if (application != null) 
      { 
       application.WorkbookBeforeClose -= handler; 
       application.Quit(); 
       Marshal.ReleaseComObject(application); 
       Marshal.ReleaseComObject(handler); 
       process.WaitForExit(); 
      } 
     } 
     catch (Exception e) { throw; } 
     finally 
     { 

     } 

     workbook = null; 
     workbooks = null; 
     application = null; 
     if (process != null && !process.HasExited) 
      process.Kill(); 
     if (threadCulture != null) 
      Thread.CurrentThread.CurrentCulture = threadCulture; 
     initialized = false; 
    } 

應用停留在行process.WaitForExit()

+0

你能告訴我們你做了什麼嗎?所以我們可以看到有什麼問題? –

回答

3

內存管理在.NET中是自動的。顯式調用Marshal.ReleaseComObject()是一個錯誤。這不僅僅是因爲當你這麼做的時候你可以很容易地崩潰RCW,而是因爲引用計數通常是隱藏的。索引和事件是棘手的。一個丟失的ReleaseComObject調用足以讓它回退到垃圾收集器處理它。 GC需要一些時間來解決釋放內存(和引用計數)是一個功能,而不是一個錯誤。

如果確實需要COM服務器按需退出,而不是讓垃圾回收器處理它,則將所有引用設置爲null,取消訂閱事件處理程序並調用GC.Collect()。不需要ReleaseComObject調用。請查看this blog post瞭解專業人士的見解。

0

我固定我的代碼在closeExcel法修改這些代碼:

if (application != null) 
{ 
    application.WorkbookBeforeClose -= new Excel.AppEvents_WorkbookBeforeCloseEventHandler(application_WorkbookBeforeClose); 
    application.Quit(); 
    Marshal.ReleaseComObject(application); 
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 
    process.WaitForExit(100); 
} 

我認爲這個問題是一些關於垃圾收集。我的對象沒有完全收集。

+0

查看[這個答案](http://stackoverflow.com/a/17131389/17034)瞭解。 –

+0

謝謝!你的建議對我很好。所以我改變了你的正確答案。 – alisabzevari