ReleaseComObject是否等于取消订阅事件处理程序



我在类中定义了COMObject 的新成员

protected COMObject.Call call_ = null;

这个类有下面的事件处理程序,我订阅了

call_.Destructed += new COMObject.DestructedEventHandler(CallDestructedEvent);

正在使用

Marshal.ReleaseComObject(call_) 

等于

call_.Destructed -= new COMObject.DestructedEventHandler(CallDestructedEvent);

一点也不。创建COM对象时,该对象的RCW引用计数为1。订阅事件时,引用计数会增加,因为CCW也会通过其连接点容器引用对象,CCW是另一个包装器,用于将源自对象的调用返回到事件处理程序。

Marshal.ReleaseComObject()将RCW上的计数器减少一,因此您声明不再打算调用该对象。但是该对象仍然可以调用您的事件处理程序。即使您多次调用Marshal.ReleaseComObject()(直到它返回0),或者调用Marshal.FinalReleaseComObject()(它本质上释放对象,直到RCW上的引用计数减少到0),也是如此。RCW被释放,您不能再调用该对象,但CCW仍然存在,因此它仍然可以发起事件。

现在,即使您设法释放了对象,这也不安全:如果对事件处理程序的调用已经在进行中,该怎么办?这将导致对象在活动堆栈中的代码被释放。在这种情况下,行为是未定义的。

因此,释放COM对象的安全方法是小心地取消订阅所有订阅的事件,然后调用Marshal.FinalReleaseComObject()来释放RCW,并通过这样做来释放对象本身。即使在事件处理程序内部执行此操作,COM对象也不会立即死亡,因为如果编写正确,它在调用中可能会在自身上保留一个额外的引用。

另请参阅:
运行时可调用包装
COM可调用包装器
非托管世界中的IConnectionPointContainer。

相关内容

  • 没有找到相关文章

最新更新