此错误发生在以下行中:
_guideData = _transportInformationFilter as IGuideData;
_transportInformationFilter类型为IBaseFilter,它是先前通过DirectShow.Net实用功能分配的COM对象.
我假设错误是由于_transportInformationFilter以某种方式提前释放,我将其跟踪到以下方法(删除错误处理):
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); } }
据我所知,connPointContainer = _transportInformationFilter,因为IConnectionPointContainer应该导致在_transportInformationFilter COM对象上调用QueryInterface,因此需要单独释放.但是,对Marshal.ReleaseComObject(connPointContainer)的调用是导致_transportInformationFilter与其RCW分离的祸害;删除此调用修复了问题.
鉴于此,在什么情况下,我需要在C#中显式释放COM对象(使用Marshal.ReleaseComObject)以避免资源泄漏?
解决方法
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.
从http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx
FYI,调用IUnknown.Release的方式直接是Marshal.Release
,而不是ReleaseComObject.