Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does the .NET runtime hold a reference count > 1 for COM objects?

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?

like image 424
Wim Coenen Avatar asked Apr 02 '10 14:04

Wim Coenen


People also ask

How do you find the reference count of a COM object?

You can do this by putting break points or using print(CFGetRetainCount(CFTypeRef!)) function in your code . You can also increment the reference count of an Object using the CFRetain function, and decrement the reference count using the CFRelease function. CFRetain(CFTypeRef cf);CFRelease(CFTypeRef cf);

When to use marshal ReleaseComObject?

You should use this method to free the underlying COM object that holds references to resources in a timely manner or when objects must be freed in a specific order. Every time a COM interface pointer enters the common language runtime (CLR), it is wrapped in an RCW.

What is RCW in C#?

The common language runtime exposes COM objects through a proxy called the runtime callable wrapper (RCW). Although the RCW appears to be an ordinary object to . NET clients, its primary function is to marshal calls between a . NET client and a COM object.


1 Answers

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.

like image 178
Hans Passant Avatar answered Sep 28 '22 07:09

Hans Passant