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

时间:2012-01-17 12:05:25

标签: c# com delegates event-handling

我在我的类中定义了COMObject

的新成员
protected COMObject.Call call_ = null;

此类具有我订阅的以下事件处理程序

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

正在使用

Marshal.ReleaseComObject(call_) 

等于

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

1 个答案:

答案 0 :(得分:2)

完全没有。创建COM对象时,将在其RCW上创建引用计数为1的对象。当您订阅一个事件时,引用计数会增加,因为该对象也通过CCW引用其连接点容器,另一个包装器用于将对象中的调用返回给您的事件处理程序。

Marshal.ReleaseComObject()将RCW上的计数器减1,因此您声明无意再调用该对象。但该对象仍然可以调用您的事件处理程序。即使您多次调用Marshal.ReleaseComObject()(直到它返回0),或者调用Marshal.FinalReleaseComObject(),这实际上也是如此,这实际上释放了对象,直到RCW 上的引用计数减少为止RCW已经发布,你不能再调用该对象,但是CCW仍然存在,所以它仍然可以发起事件。

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

因此,释放COM对象的安全方法是从所有订阅的事件中仔细取消订阅,然后调用Marshal.FinalReleaseComObject()来释放RCW,并通过这样做,对象本身。即使您从事件处理程序内部执行此操作,COM对象也不会立即死亡,因为如果正确写入,它可能会在调用期间保留其自身的附加引用。

另见:
Runtime-Callable Wrappers
COM-Callable Wrappers
IConnectionPointContainer在未管理的世界中。