[Solved] COM Interop, Garbage Collection, and Runtime Callable Wrapper object management [Answered]
Essentially, this question is going to boil down to: when is it appropriate to call
Marshal.FinalReleaseComObject()
and should it be manually called or should the Garbage Collector handle it? (I'm fully expecting an $itdepends answer for this question.)
Background: Apps at work interop with MS Excel and AutoCAD to drive these programs in-process and out-of-process. The .NET API around AutoCAD was written to function within the same process, not out-of-process. This forces any out of process .NET applications to utilize the ActiveX library to interop with AutoCAD. When application exits, the Excel and AutoCAD application processes are left open, visible to Task Manager., even though the application calls the .Quit();
method equivalents in each library.
COM and RCWs: From my understanding, the runtime will create a Runtime Callable Wrapper overtop COM interfaces so that it is treated as a managed object. I'm working with public static
fields within this code base, which makes them GC roots (?). If I'm understanding correctly, this means that the GC will not collect these instances until they are eligible for cleanup, effectively when nothing else is referencing them. Does this only happen when these variables are set to null
? (See https://www.add-in-express.com/creating-addins-blog/2013/11/05/release-excel-com-objects/) Is this essentially the reason why, my COM objects are never dereferenced and released by the process?
Excel Interop: The references to Excel.Worksheet
, Excel.Workbook
, and Excel.Application
are marked as public static
fields in the application code. When the application process exits, the application leaves the Excel process running in the background. If I call Marshal.FinalReleaseComObject
on my Excel COM variables, the process will exit normally when running the application. What here actually "holds" the live Excel process captive from being released? The .NET application that launched Excel should have been cleaned up by the .NET Garbage collector and any unmanaged objects would be cleaned up by the Windows operating system, right?
What exactly is the best practice? The Visual Studio team and some other users on sites like StackOverflow seem to state that manually releasing COM objects is something that shouldn't be done by the user and only handled by the garbage collector; but, others state that you must release COM objects when you are finished with them.
Against:
https://devblogs.microsoft.com/visualstudio/marshal-releasecomobject-considered-dangerous/#marshal-releasecomobject-a-problem-disguised-as-a-solution
https://stackoverflow.com/a/25135685
For:
https://www.add-in-express.com/creating-addins-blog/2013/11/05/release-excel-com-objects/
I've always read / have been told that COM Objects should always be manually released by the developer using Marshal.ReleaseComObject
and Marshal.FinalReleaseComObject
to ensure that the called application exits cleanly. And I feel like this is probably what should be done, but I'm wondering what side effects or gotchas I might end up encountering.24 Replies
thank you modix
I hope this makes sense to whoever ends up reading this
@ LowLevel
Ah yes
It's that on a phone?
Yeah
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
I have thought about doing that, but I didn't want to crosspost anything, but I'm not really getting any answers either lol
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Nice formatting, Discord
What's the question?
Xymanek has the same issue with formatting
I've been working on some COM interop and doing some research on it and I've come across some conflicting information. Essentially, this question is going to boil down to: when is it appropriate to call
Marshal.FinalReleaseComObject()
and should it be manually called or should the Garbage Collector handle it? Some people you must release COM objects with ReleaseComObject
and others are saying don't release anything because the garbage collector will handle it
I've always been on the side of releasing it with Marshal.FinalReleaseComObject
/ ReleaseComObject
Mmmh not familiar with that API. The class and name kinda makes me think it probably should never be used also missing context here. How exactly are you doing COM interop? Using safe handles? Using COM interfaces? Using ComWrappers? Manually?
COM Interfaces; the COM libraries that I'm working with are the
Excel.Application
, Workbook
, Worksheet
objects, and there's some AutoCAD COM Interfaces from their DLLs that are referenced in the project
It's not safe handles and not ComWrappers. I think it's COM Interfaces that are exposed in the DLLs from the Excel COM librariesIn that case in pretty sure you're not supposed to do anything. The underlying type will have a finalizer and just do its thing
If the host application, that calls the COM libraries to create a new Excel application, workbook, etc, and ends up exiting after everything is complete, then the garbage collector will run and clean up the resources as the process is exiting, right?
Windows also keeps track of memory that's allocated during the process lifespan and should free that memory when the process exits too, correct?
No, the GC isn't guaranteed to run during process teardown
Yes, if you terminate a process, all its memory goes away. Technically one could not free memory ever and as long as you have enough RAM, everything will work fine, then you can just close the process and poof, gone
Ah, ok, interesting. What I was finding out through fixing one of our applications, is that the app would create an
Excel.Application
object and they didn't dispose of it or release the COM object. The object and the Excel process persisted even after the host application exited.
Just remembering from working with COM a couple of years ago, that the recommendation at that time was to always release the COM object. So I added those lines of code and now the Excel application exits correctly. So I got curious and started researching again and ran into some different articles and conflicting information about how exactly COM objects should be handled, and now we are here lol
If it's manual COM interop and / or the underlying type does not container a finalizer, then the allocated resources are not released?Yeah, if you're doing manual COM interop you are responsible for properly tracking ref counts to every COM object
Ah, sorry. Then I'm pretty sure it's all manual COM interop, as using
Marshal.ReleaseComObject
decrements the ref count in the runtime callable wrapper
This is one of the articles that caused me to bring this up: https://stackoverflow.com/a/25135685. They're basically advocating for not using Marshal.ReleaseComObject
and instead calling GC.Collect()
& GC.WaitForPendingFinalizers()
to release the resourcesUnknown User•3y ago
Message Not Public
Sign In & Join Server To View
If I have to use COM interop, are using the other methods Sergio mentioned, like Safe Handles or COM Wrappers typically preferred?
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
✅ This post has been marked as answered!