2011-07-06 29 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