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?
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With