Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"COM object that has been separated from its underlying RCW cannot be used" with .NET 4.0

I've a class in my .NET 3.5 C# WinForms application which has five methods. Each method uses different sets of C++ COM interfaces. Am using Marshal.FinalReleaseCOMObject for cleaning up these COM objects. This code works fine on this .NET platform without any issues. But when I move this application to .NET 4.0, I start getting this error in one of these methods at a line where I cast a variable from ICOMInterface1 to ICOMInterface2, i.e.:

ICOMInterface1  myVar= obj as ICOMInterface2; 

COM object that has been separated from its underlying RCW cannot be used.

And if I remove the line where am using Marshal.FinalReleaseCOMObject, I don't get this error.

What am I missing here? And how do I clean up these unmanaged COM objects from the memory on .NET 4.0 platform?

like image 683
user74042 Avatar asked Apr 11 '12 16:04

user74042


1 Answers

The simple answer is to never use Marshal.FinalReleaseComObject unless you absolutely must. And if you do, there are some additional rules you must follow.

When a COM object is used in .NET, the runtime creates what's known as a "RCW" or "runtime callable wrapper" for that object. This RCW is just a normal object that holds a COM reference on the object. When this object is garbage collected, it will call IUnknown::Release() on the COM object, as you'd expect. What this means is unless your COM object requires that the last Release() is done at a very certain moment in time, just let the garbage collector take care of it. Many COM objects fall into this case, so absolutely verify that you must manage the call to Release() carefully.

So when you're calling FinalReleaseComObject, that is essentially decrementing the reference the RCW has on the COM object until it hits zero and the RCW then releases the COM object. At this point, this RCW is now zombied, and any use of it will give the exception you've seen. The CLR (by default) only creates a single RCW for any underlying COM object, so this means if the COM API you're using returned the same object twice, it's just going to have a single RCW. Calling FinalReleaseComObjectwould mean that suddenly all uses of that RCW are toast.

The only way to guarantee you have a unique Marshal.GetUniqueObjectForIUnknown, which prevents any RCW sharing. But like I said earlier, in most COM APIs this isn't neccessary to do in the first place, so just don't do it.

Paul Harrington wrote up a good blog post about [Final]ReleaseComObject and it's evils. It's a dangerous weapon that unless needed will only hurt you. Since you're asking this question, I'd suspect you don't actually need to be calling it at all. :-)

like image 127
Jason Malinowski Avatar answered Oct 17 '22 10:10

Jason Malinowski