Search code examples
c#cominterop

When am I required to call Marshal.ReleaseComObject on an interface queried through COM in C#


I have been working with some DirectShow interfaces for playing Digital TV (DVB-T) using C# and DirectShow.Net. I recently encountered the runtime error COM object that has been separated from its underlying RCW cannot be used.

This error occurred in the following line:

_guideData = _transportInformationFilter as IGuideData;

_transportInformationFilter is of type IBaseFilter, a COM object previously assigned via a DirectShow.Net utility function.

I assumed the error was due to _transportInformationFilter somehow being prematurely released, and I traced it to the following method (error handling removed):

private void AttachGuideDataEvent()
{
    IConnectionPoint connPoint = null;
    IConnectionPointContainer connPointContainer = null;
    try
    {
        connPointContainer = _transportInformationFilter as IConnectionPointContainer;
        if (connPointContainer == null) /* error */

        var guideDataEventGuid = typeof (IGuideDataEvent).GUID;
        connPointContainer.FindConnectionPoint(ref guideDataEventGuid, out connPoint);
        if (connPoint == null) /* error */

        int cookie;
        connPoint.Advise(this, out cookie);
        if (cookie == 0) /* error */    
        _persistIGuideDataEventCookie = cookie;
    }
    finally
    {
        if (connPointContainer != null)
            Marshal.ReleaseComObject(connPointContainer);
        if (connPoint != null)
            Marshal.ReleaseComObject(connPoint);
    }
}

As I understood it, connPointContainer = _transportInformationFilter as IConnectionPointContainer should have resulted in a call to QueryInterface on the _transportInformationFilter COM object, and thus would need to be released separately. However, the call to Marshal.ReleaseComObject(connPointContainer) was the culprit causing _transportInformationFilter to be separated from its RCW; removing this call fixed the issue.

Given this, in what situations am I required to explicitly release COM objects (using Marshal.ReleaseComObject) in C# to avoid leaking resources?


Solution

  • Almost never. ReleaseComObject manages the reference count of the RCW, not the underlying object and is not directly analogous to IUnknown.Release. You should let the CLR manage its QueryInterface'ing and Release'ing.

    The RCW has a reference count that is incremented every time a COM interface pointer is mapped to it. The ReleaseComObject method decrements the reference count of an RCW. When the reference count reaches zero, the runtime releases all its references on the unmanaged COM object, and throws a System.NullReferenceException if you attempt to use the object further. If the same COM interface is passed more than one time from unmanaged to managed code, the reference count on the wrapper is incremented every time, and calling ReleaseComObject returns the number of remaining references.

    ...

    This method enables you to force an RCW reference count release so that it occurs precisely when you want it to. However, improper use of ReleaseComObject may cause your application to fail, or may cause an access violation.

    From http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx

    FYI, the way to call IUnknown.Release directly is Marshal.Release, not ReleaseComObject.