Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

.NET and COM interop story

0.00/5 (No votes)
2 Jun 2009 1  
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.

C#
// IHTMLDocument2 doc;
foreach (IHTMLElement elem in doc.all)
{
    IHTMLAnchorElement anchor = elem as IHTMLAnchorElement;
    if (anchor != null)
    {
        elem.style.color = "red";
    }
}

This first approach leaves the task of releasing COM objects to garbage collector. Let's manually release COM objects now:

C#
// IHTMLDocument2 doc;
IHTMLElementCollection allCollection = doc.all;
foreach (IHTMLElement crntElem in allCollection)
{
   IHTMLAnchorElement anchor = crntElem as IHTMLAnchorElement;
   if (anchor != null)
   {
       IHTMLStyle style = crntElem.style;
       style.color = "red";

       Marshal.ReleaseComObject(style);
       Marshal.ReleaseComObject(anchor);
   }

   Marshal.ReleaseComObject(crntElem);
}

Marshal.ReleaseComObject(allCollection);

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here