【问题标题】:Does ReleaseComObject equal to unsubscribe from event handler?ReleaseComObject 是否等于取消订阅事件处理程序?
【发布时间】:2012-01-17 12:05:24
【问题描述】:

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

protected COMObject.Call call_ = null;

这个类有以下我订阅的事件处理程序

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

正在使用

Marshal.ReleaseComObject(call_) 

等于

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

【问题讨论】:

  • 它可能是。这个事件很奇怪,除非所有对它的接口引用计数都减为零,否则不能破坏 COM 对象。只要您订阅了一个事件,该计数就不会达到零。反正不应该。设计是非常可疑的。

标签: c# com delegates event-handling


【解决方案1】:

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

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

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

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

另请参阅:
Runtime-Callable Wrappers
COM-Callable Wrappers
IConnectionPointContainer 在非托管世界中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-15
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多