C# 什么时候我需要在C中通过COM查询的接口上调用Marshal.ReleaseComObject#
我一直在使用一些DirectShow接口,使用C#和。我最近遇到运行时错误C# 什么时候我需要在C中通过COM查询的接口上调用Marshal.ReleaseComObject#,c#,com,interop,C#,Com,Interop,我一直在使用一些DirectShow接口,使用C#和。我最近遇到运行时错误COM对象,该对象已与其基础RCW分离,无法使用。 此错误发生在以下行中: \u guideData=\u transportInformationFilter作为IGuideData \u transportInformationFilter属于IBaseFilter类型,是以前通过DirectShow.Net实用程序函数分配的COM对象 我假设该错误是由于\u transportInformationFilter提前发
COM对象,该对象已与其基础RCW分离,无法使用。
此错误发生在以下行中:
\u guideData=\u transportInformationFilter作为IGuideData代码>
\u transportInformationFilter
属于IBaseFilter类型,是以前通过DirectShow.Net实用程序函数分配的COM对象
我假设该错误是由于\u transportInformationFilter
提前发布造成的,我将其追溯到以下方法(已删除错误处理):
据我所知,connPointContainer=\u transportInformationFilter As IConnectionPointContainer
应该导致调用\u transportInformationFilter
COM对象上的QueryInterface
,因此需要单独释放。但是,调用封送.ReleaseComObject(connPointContainer)
是导致\u transportInformationFilter
与其RCW分离的罪魁祸首;删除此呼叫修复了此问题
鉴于此,在什么情况下,我需要在C#中显式释放COM对象(使用Marshal.ReleaseComObject
),以避免资源泄漏?几乎从不。ReleaseComObject管理RCW的引用计数,而不是底层对象,并且与IUnknown.Release不直接类似。您应该让CLR管理其查询接口
'ing和发布
'ing
RCW有一个引用计数,每次COM接口指针映射到它时,该计数都会递增。ReleaseComObject方法减少RCW的引用计数。当引用计数达到零时,运行时将释放非托管COM对象上的所有引用,如果您试图进一步使用该对象,则会抛出System.NullReferenceException。如果同一COM接口多次从非托管代码传递到托管代码,则包装上的引用计数每次都会增加,并且调用ReleaseComObject将返回剩余引用的数量
此方法使您能够强制释放RCW引用计数,以便它在您希望的时候准确地发生。但是,不正确使用ReleaseComObject可能会导致应用程序失败,或者导致访问冲突
从
仅供参考,直接调用IUnknown.Release
的方法是,而不是ReleaseComObject
我想我已经找到了使用Marshal.ReleaseComObject的真正合法的环境。使用ExcelDNA在C#中编写excel加载项时,我倾向于从工作线程使用COM互操作,并访问excel自动化对象,如“应用程序”、“工作簿”等
如果我等待垃圾收集器完成这些对象,那么在用户退出excel后,任务管理器中会有一个不可见的excel“僵尸”实例。这是因为这些RCW保持了excel的活力,它们可以在相当长的一段时间内保持运行。感谢您提供的信息。如果MSDN文档说调用方专门负责释放返回的接口(例如),那么运行时是否会在对象超出范围时为我管理释放调用,或者我应该使用ReleaseComObject?当对象“超出范围”时,它不会运行但是,当RCW的终结器运行时,对于connPoint的情况,它不会有任何影响。需要记住的重要一点是,ReleaseComObject
在RCW上运行,它就像调用Dispose
,并且由于与IFoo类似的原因而中断;a、 处置()_member.DoSomething()
可能会崩溃。非常感谢您的反馈,这很有意义。@Logan:您是否有一些关于“几乎从未”的参考资料似乎我的同事无法忍受这种不确定性(他是.NET新手)@Daniel这个答案可以写得更清楚。如果您试图管理COM对象的引用计数(AddRef/Release),则不应这样做,如果您希望确定地释放COM对象,则最有可能使用FinalReleaseComObject。参考资料几乎就是我一直链接到的ReleaseComObject的文档。“…因此,仅当绝对需要时才使用ReleaseComObject。”
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);
}
}