我一直在使用一些DirectShow界面来使用C#和DirectShow.Net播放数字电视(DVB-T)。我最近遇到了运行时错误COM object that has been separated from its underlying RCW cannot be used.
此错误发生在以下行:
_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 as IConnectionPointContainer
应该导致QueryInterface
COM对象上的_transportInformationFilter
调用,因此需要单独发布。但是,对Marshal.ReleaseComObject(connPointContainer)
的调用是导致_transportInformationFilter
与其RCW分离的罪魁祸首;删除此调用解决了问题。
鉴于此,在什么情况下我需要在C#中显式释放COM对象(使用Marshal.ReleaseComObject
)以避免资源泄漏?
答案 0 :(得分:10)
几乎没有。 ReleaseComObject管理RCW的引用计数,而不是基础对象,并且不直接类似于IUnknown.Release
。您应该让CLR管理其QueryInterface
和Release
'。
RCW的引用计数在每次COM接口指针映射到它时递增。 ReleaseComObject方法减少RCW的引用计数。当引用计数达到零时,运行时将释放其对非托管COM对象的所有引用,如果您尝试进一步使用该对象,则抛出System.NullReferenceException。如果从非托管代码到托管代码多次传递相同的COM接口,则包装器上的引用计数每次都会递增,并且调用ReleaseComObject将返回剩余引用的数量。
...
此方法使您可以强制RCW引用计数释放,以便在您需要时准确发生。但是,不恰当地使用ReleaseComObject可能会导致应用程序失败,或者可能导致访问冲突。
来自http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx
仅供参考,直接致电IUnknown.Release
的方式是Marshal.Release
,而不是ReleaseComObject
。
答案 1 :(得分:5)
我认为我找到了使用Marshal.ReleaseComObject的真正合法的情况。使用ExcelDNA在C#中编写excel插件时,我倾向于使用来自工作线程的COM互操作,并访问excel自动化对象,如“应用程序”,“工作簿”等。
如果我等待垃圾收集器完成这些对象,那么在用户退出excel之后,我将拥有一个看不见的excel“zombie”实例。这是因为那些RCW保持活力,他们可以保持运行一段时间。