Sometimes when I end the application and it tries to release some COM objects, I receive a warning in the debugger:
RaceOnRCWCleanUp was detected
If I write a class which uses COM objects, do I need to implement IDisposable and call Marshal.FinalReleaseComObject on them in IDisposable.Dispose to properly release them? If Dispose is not called manually then, do I still need to release them in the finalizer or will the GC release them automatically? Now I call Dispose(false) in the finalizer but I wonder if this is correct. The COM object I use also have an event handler which the class listens to. Apparently the event is raised on another thread, so how do I correctly handle it if it is fired when disposing the class?
1 1 1 silver badge asked Mar 31, 2013 at 10:56 Alvin Wong Alvin Wong 12.3k 5 5 gold badges 53 53 silver badges 77 77 bronze badgesThat is a reminder that manual memory management isn't such a great idea. That MDA warns because of potential hard crashes in the COM server. Trying to dispose anything at app shutdown is pointless, it will be finalized a millisecond later. The GC already knows how to do this, avoid helping.
Commented Mar 31, 2013 at 11:24First - you never have to call Marshal.ReleaseComObject(. ) or Marshal.FinalReleaseComObject(. ) when doing Excel interop. It is a confusing anti-pattern, but any information about this, including from Microsoft, that indicates you have to manually release COM references from .NET is incorrect. The fact is that the .NET runtime and garbage collector correctly keep track of and clean up COM references.
Second, if you want to ensure that the COM references to an out-of-process COM object is cleaned up when your process ends (so that the Excel process will close), you need to ensure that the Garbage Collector runs. You do this correctly with calls to GC.Collect() and GC.WaitForPendingFinalizers() . Calling twice is safe, end ensures that cycles are definitely cleaned up too.
Third, when running under the debugger, local references will be artificially kept alive until the end of the method (so that local variable inspection works). So a GC.Collect() calls are not effective for cleaning object like rng.Cells from the same method. You should split the code doing the COM interop from the GC cleanup into separate methods.
The general pattern would be:
Sub WrapperThatCleansUp() ' NOTE: Don't call Excel objects in here. ' Debugger would keep alive until end, preventing GC cleanup ' Call a separate function that talks to Excel DoTheWork() ' Now Let the GC clean up (twice, to clean up cycles too) GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.WaitForPendingFinalizers() End Sub Sub DoTheWork() Dim app As New Microsoft.Office.Interop.Excel.Application Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add() Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1") app.Visible = True For i As Integer = 1 To 10 worksheet.Cells.Range("A" & i).Value = "Hello" Next book.Save() book.Close() app.Quit() ' NOTE: No calls the Marshal.ReleaseComObject() are ever needed End Sub
There is a lot of false information and confusion about this issue, including many posts on MSDN and on StackOverflow.