Discussion of Marshal.ReleaseComObject and its dangers

David Mortenson sent this on an internal Distribution List. I'm sure you'll find it useful if you do any COM Interop:

This is a good time to discuss the risks of using Marshal.ReleaseComObject. This API does indeed allow you to force the release to happen precisely when you want it to. However when you call this on a RCW that represents a COM component, if any other managed code in the AppDomain is holding on to this RCW, it will be unable to use it once you release it (it will get an InvalidComObjectException).

And even worse, if a call is in flight on the RCW while it is released, the behavior is undefined. There are good chances the thread making the call will AV, however it’s possible it will just corrupt process memory instead and the process will continue limping along until it later crashes for mysterious and very hard to debug reasons.

This risk is compounded when the COM component that is being used is a singleton since CoCreateInstance (which is how the CLR activates COM components under the covers) will return the same interface pointer every time it is called for singleton COM components. So separate and independent pieces of managed code in an AppDomain can be using the same RCW for a singleton COM component and if either one of them calls ReleaseComObject on the COM component, the other will be broken.

And this is why I strongly recommend against using ReleaseComObject unless you absolutely have to!

On a separate note, if you absolutely need to call ReleaseComObject to make sure a COM component gets released at a determined time, you should instead use Marshal.FinalReleaseComObject in Whidbey. This API will release the underlying COM component regardless of how many times it has re-entered the CLR. Comparatively, ReleaseComObject only decrements the internal ref count of the RCW (which is incremented by one every time the COM component re-enters the CLR) and only if it falls to 0 will the underlying COM component be released. On previous versions of the CLR, you can accomplish the same thing that FinalReleaseComObject does by calling ReleaseComObject in a loop until the value returned is 0.