Stats

.NET and COM interop story

Let's see a short example using COM objects exposed by Internet Explorer. The code below changes the color of every link in an HTML document.

.NET allows programmers to reuse COM components in their managed code. To make this possible, a managed wrapper object around the native object is needed. Besides that, one can use the COM object like any other managed object. Even if it sounds simple, you have to be aware of the differences between the CLR's object lifetime management and the COM version of object lifetime management.

COM programmers have to call Release on every interface that has been AddRef'ed. For C# programmers using COM objects, that means AddRef is called when:

a COM object is created

a COM object is returned by calling a method or a property

a COM object is cast'ed to another COM interface type

To release a COM object in C#, there are two options:

Leave the GC to collect managed wrappers and to call their finalizers that will call Release on native COM object

Manually call Marshal.ReleaseComObject on every interface used in the code

Let's see a short example using COM objects exposed by Internet Explorer. The code below changes the color of every link in an HTML document.

As you can see, the number of code lines doubles! I personally prefer to leave the task of releasing COM objects to GC even if they will be eventually released after some time when GC comes into action.

Some might be tempted to call GC.Collect after a large chunk of code that works with COM objects but this could be even worse because other managed objects could be promoted to next GC generation and their lifespan is therefore longer than necessary.

In theory, it is possible to create a lot of large COM objects that will exceed the native heap while the managed heap has a lot of available memory because managed wrappers are smaller in size. GC won't be called in this scenario so the native heap won't be freed.

If your application suffers from this kind of memory allocation problem, maybe using COM objects from managed code is not the best approach for you.

Comments and Discussions

This approach can be a nightmare when using large COM libraries from .NET. I know, I used it a lot.

And there are scenarious where it is impossible to use at all. It is when you have dependent objects that expose events via COM Connection Points. Their release must be matched with that of the containing objects, because otherwise the objects still won't be released. In combination with keeping some object as single instance this creates even furhter problems with asyncronous access to such objects.

Basically, your article is good when using small COM libraries when you create one-two interfaces, preferably without event handlers, so you know what is going on. Otherwise you just have to leave it to the garbage collector, which in my experience never fails, if your COM object was written correctly.

I personally found this approach useful only when working with a DCOM server, for which i needed it to shut down as quickly as possible.

You are absolutely right! I used COM inter-op mostly for IE add-ons/automation programming and I prefer to let the GC to release COM objects. Manually releasing is useful sometimes for performance tuning (but when performance is an issue there is always VC++.net and we can mix native/managed code).

I've just found an interesting example in Jeffrey Richter's book (CLR via C#, Second Edition page 507) about using GC with native resources. He is talking about AddMemoryPressure and RemoveMemoryPressure methods of GC class but I'm not sure how to use them with COM inter-op.