views:

58

answers:

1

Until recently, I believed that the .NET runtime only increases the reference count of COM objects by 1 when creating a runtime-callable wrapper, and that only one such runtime-callable wrapper is created for any given COM object.

If I'm not mistaken, the above implies that Marshal.FinalReleaseComObject and Marshal.ReleaseComObject do the same thing in practice.

However, today I was writing some tests to verify that COM objects are properly released by my code. I do this by invoking the supposedly released object and checking for the expected InvalidComObjectException. It turns out that there are cases where the exception is thrown after a FinalReleaseComObject, but not after a ReleaseComObject.

Does this mean that the .NET 2.0 runtime can hold more than one reference to a COM object? If so, when does it do this?

+2  A: 

There's an extra level of indirection here. Yes, the RCW keeps a single reference count on the native COM interface pointers. But the RCW has a reference count too, it is incremented every time a COM interface pointer is mapped to the RCW. Which may happen if a COM method returns an interface pointer. The finalizer of the corresponding .NET wrapper class decrements it.

You can tinker with that reference count directly through Marshal.ReleaseComObject(), which decrements it by one like the finalizer does, and Marshal.FinalReleaseComObject(), which zaps it to zero, guaranteeing that the IUnknown::Release() method is called. They of course fall in the "better know what you're doing" category. Getting it wrong produces the ugly and undebuggable "COM object separated from its underlying RCW" exception.

Hans Passant
Does this mean multiple `System.__ComObject` can actually represent the same RCW? And that it is the finalizer of these objects that decreases the RCW reference count? (Until now, I thought that `System.__ComObject` was actually the same thing as the RCW.)
Wim Coenen