Reputation: 10516
I have an Excel add-in that needs a lot of long running references to Excel native objects. Every now and then when a user closes Excel it 'hangs' keeping an Excel process live in the background.
There's quite been some debate between trusting the GC and doing manual cleanup. Orignially I trusted the GC, also doing this when the add-in unloads for good measure:
do {
GC.Collect();
GC.WaitForPendingFinalizers();
}
while (Marshal.AreComObjectsAvailableForCleanup());
but now the issue keeps popping up at random and I'm finding it hard to figure out what it could be. Also inserted Marshal.ReleaseComObject
everywhere but every now and then it still hangs.
So I was thinking, if I can ask Marshal.AreComObjectsAvailableForCleanup
then apparently there's a central list of RCW's being kept by Marshal
?
Is there a way to get to this list and display information about the native objects being held? That would be really helpful in finding the offender. I looked over the public methods but there does not seem to be anything available. Looking at the source the trail goes dead at this call:
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int InternalReleaseComObject(Object o);
But maybe someone here knows a way to continue and list the objects?
Any other suggestions to get Excel to shut down properly also welcome of course.
Upvotes: 1
Views: 134
Reputation: 73
I had a similar problem with Excel crashing after being closed and for me it was also related to COM Objects not being released properly on shutdown.
I have followed Goverts suggestion to use the OnDisconnection (here using the Ribbon deriving from ExcelComAddIn which implents IDTExtensibility2) method (Functions.StatusCollection and DBModifDefColl are collections of dynamically allocated objects containing references to excel ranges, which are then explicitly released using Marshal.ReleaseComObject):
Public Class MenuHandler
Inherits CustomUI.ExcelRibbon
Public Overrides Sub OnDisconnection(RemoveMode As ExcelDna.Integration.Extensibility.ext_DisconnectMode, ByRef custom As Array)
For Each aKey As String In Functions.StatusCollection.Keys
Dim clearRange As Excel.Range = Functions.StatusCollection(aKey).formulaRange
If Not IsNothing(clearRange) Then Marshal.ReleaseComObject(clearRange)
Next
For Each DBmodifType As String In DBModifDefColl.Keys
For Each dbmapdefkey As String In DBModifDefColl(DBmodifType).Keys
Dim clearRange As Excel.Range = DBModifDefColl(DBmodifType).Item(dbmapdefkey).getTargetRange()
If Not IsNothing(clearRange) Then Marshal.ReleaseComObject(clearRange)
Next
Next
Do
GC.Collect()
GC.WaitForPendingFinalizers()
Loop While (Marshal.AreComObjectsAvailableForCleanup())
End Sub
...
Once this was implemented I had no more crashes on excel shutdown...
Upvotes: 1