Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

interop

com

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?

like image 569
jeffora Avatar asked Feb 23 '11 01:02

jeffora


2 Answers

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.

like image 165
Logan Capaldo Avatar answered Oct 14 '22 07:10

Logan Capaldo


I think I've found a truly legitimate circumstance for using Marshal.ReleaseComObject. When writing excel addins in C# using ExcelDNA, I tend to use COM interop from worker threads, and access excel automation objects like "Application", "Workbook" etc.

If I waited for the garbage collector to finalize these objects, what I would have is an invisible excel "zombie" instance remaining in the task manager after the user exits excel. This is because those RCW's keep excel alive, and they can stay running for quite some time.

like image 8
Ismail Degani Avatar answered Oct 14 '22 05:10

Ismail Degani