I am using COM Excel Application class in C#. I handled the WorkbookBeforeClose
. But now I can't release the COM objects properly.
Note that I managed to release the COM objects properly before handling this event and when commenting that part of code, my application works properly.
What COM object is not released from memory and how to release it properly?
Edit: What I've done:
public void Init()
{
...
application = new Excel.Application();
application.WorkbookBeforeClose += new Excel.AppEvents_WorkbookBeforeCloseEventHandler(application_WorkbookBeforeClose);
}
...
void applica开发者_开发技巧tion_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;
}
Application pauses In line process.WaitForExit()
.
Memory management is automatic in .NET. Explicitly calling Marshal.ReleaseComObject() yourself is a mistake. Not just because you can easily crash the RCW when you do so too early, but especially because the reference counts are often hidden. Indexers and events are the tricky ones. One missing ReleaseComObject call is enough to make it fall back to the garbage collector taking care of it. That the GC takes some time to get around to releasing memory (and reference counts) is a feature, not a bug.
If you really, really want the COM server to quit on demand instead of letting the garbage collector take care of it then set all the references you have to null, unsubscribe the event handlers and call GC.Collect(). No ReleaseComObject calls required. Check this blog post for insight from the pros.
I fixed my code by modifying these lines of code in closeExcel
method:
if (application != null)
{
application.WorkbookBeforeClose -= new Excel.AppEvents_WorkbookBeforeCloseEventHandler(application_WorkbookBeforeClose);
application.Quit();
Marshal.ReleaseComObject(application);
GC.Collect();
GC.WaitForPendingFinalizers();
process.WaitForExit(100);
}
I think the problem was something about Garbage Collection. My Object didn't collect completely.
精彩评论