0

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.

gjvdkamp
  • 9,929
  • 3
  • 38
  • 46
  • The problem is really neither a pure COM nor a .NET/RCW issue, everything is properly done by .NET and the GC (first link). The difficult here is you're talking to an out-of-process COM server (an .EXE) which basically can live its own, show UI, etc. if it wants to and there's nothing "smart" you can do against it. If your issue is to make sure no Excel.exe process keeps living, you could try to terminate them. These processes are started with "/automation -Embedding" in the command line, and their parent should be svchost.exe (DComLaunch aka "DCOM Server Process Launcher" service) – Simon Mourier Jun 24 '22 at 10:30
  • 1
    https://stackoverflow.com/questions/53001928/difference-between-sos-rcw-and-sos-dumprcw-output – Hans Passant Jun 24 '22 at 10:43
  • @SimonMourier yeah that was a fallback plan, just call Environment.Exit(0)) after a timer has expired to allow it to try to shutdown on it's own first. Maybe a bit crude but it might get the job done. – gjvdkamp Jun 24 '22 at 12:35
  • @HansPassant ah interesting, seems like a bit of homework to wrap my head around but I could run this on my box if it does hang there. Thx. – gjvdkamp Jun 24 '22 at 12:37
  • 1
    Here is a (undocumented) trick to get exact Excel process id if things went wrong: https://pastebin.com/raw/ZtEbmfBJ – Simon Mourier Jun 24 '22 at 14:40
  • 1
    For an in-process Excel add-in, it is crucial that you only access the COM object model from the main Excel thread (ManagedId == 1). If you try any kind of access from another thread, task, async method, message or network callback, you end up in the bad place eventually. Excel-DNA has a helper called `ExcelAsyncUtil.QueueAsMacro` that lets you run code on the main thread again - this is safe to call any time from any thread. Then do your COM stuff inside the macro / delegate which runs on the main thread. If you follow this rule, you need not invoke the GC for cleanup and Excel closes OK. – Govert Jun 24 '22 at 20:15

0 Answers0