【问题标题】:.NET and COM Interoperability : release COM from .NET client.NET 和 COM 互操作性:从 .NET 客户端释放 COM
【发布时间】:2012-03-31 08:03:47
【问题描述】:

假设我有一个 COM 对象(非托管)和 .NET 客户端。

是否需要从 .NET 客户端调用 Marshal.FinalReleaseComObject 方法才能释放 COM 对象?

【问题讨论】:

标签: .net com com-interop


【解决方案1】:

没有。无需从 .Net 客户端显式释放 COM 对象。 COM 对象将像任何其他 .Net 对象一样被收集,并且在删除所有对它的引用后将释放它的底层本机句柄。

明确使用FinalReleaseComObject 实际上会导致编程错误。如果代码中的另一个组件仍在引用 COM 对象,您将从它下面拉出本机对象。这可能会导致运行时失败。

【讨论】:

  • 错误做法。你 GC.Collect() + GC.WaitForPendingFinalizers() 如果你必须这样做,永远不会出错。
  • @HansPassant 这不适用于 Outlook 对象模型。各种相关的“解决方案”涉及尝试连续两次调用该序列。它只是“在实践中”不起作用(在我处理的情况下)。
  • @pst 如果GC.Collect + GC.WaitForPendingFinalizers 不起作用但FinalReleaseComObject 起作用,那么您的FinalReleaseComObject 很可能在程序中的某处孤立了对COM 对象的托管引用。
  • 只有一种 COM,Outlook 没有什么不同。也许你应该问一个关于它的问题。
  • @HansPassant 去过那里,已经做了好几个月了。您描述的方式只是不可靠。它与 GC 通行证有关,而不是(必然)拾取需要回收的 RCW,IIRC。这与using 与希望 Stream 终结器能够运行确实没有什么不同。有时它只是在它应该运行的时候却没有运行。再加上缓存(在 OOM 中臭名昭著),这只会“让事情无法工作”。
【解决方案2】:

修改“是”和“否”。

首先,请记住ReleaseComObject 不会自动减少真正的 COM 对象引用计数。相反,它会减少内部 RCW 计数器。 (每次从 COM->NET 移动 same COM 对象时,它都会使用 same RCW 并将 RCW 计数器加一。)同样,FinalRelaseComObject 也会影响RCW 计数器并有效地“将其设置为 0”。当 RCW 计数器变为零时,.NET 将减少 实际 COM ref-count。

所以,“是”,但根据这些规则进行了修改

  1. 每次从 COM->NET 交叉的对象应该在其上调用ReleaseComObject但不 FinalReleaseComObject。也就是说,每次对象交叉时都应该调用它一次即使它导致引用等于 RCW
  2. 对 RCW(它只是一个代理包装器)的引用数量无关紧要;只有物体越过边界的次数。参见规则#1。 (控制引用和谁保留它们很重要,但在这种情况下发生的“最坏情况”是使用“分离的 RCW”的一个例外,它与使用 Disposed 流没有什么不同。)

我说上面的规则,不是FinalReleaseComObject,因为RCW对象被缓存在一个身份代理中,所以使用FinalReleaseComObject会影响COM->NET边界跨越你甚至都不知道! (这很糟糕,在这一点上,我完全同意 JaredPars 的回答。)

“否”,当一个 RCW 被回收时(终结器被调用),它会自动“释放”COM 引用(有效地调用@987654327 @ 本身)。请记住,由于只有一个 RCW 对象,这意味着只要在 .NET 中有对它的引用,它就永远不会被回收。如果回收 RCW,则 没有问题,因为从上面看,不再有对所述 RCW 的引用,因此 .NET 知道它可以将 COM 引用计数减一(这可能会导致 COM要销毁的对象)。

但是,由于 .NET GC 是挑剔的且非确定性,因此依赖此行为意味着对象的生命周期不受控制。例如,在使用 Outlook 对象模型时,这可能会导致许多微妙的问题。 (其他 COM 服务器可能不太容易出现问题,但 OOM 在内部对对象进行了有趣的“缓存”。如果不明确控制生命周期,很容易得到“项目已被修改”异常。)

在我的代码中,我有一个支持IDisposableComWrapper 类。这使我可以传递从 COM->NET 获得的具有明确生命周期所有权的 RCW 对象。在切换到这种方法后,我在 Outlook-Addin 开发中遇到的问题非常少(实际上几乎没有),并且之前有许多问题。 “缺点”是需要确定 COM->NET 边界,但一旦确定,那么内部所有生命周期都得到正确处理。

编码愉快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    相关资源
    最近更新 更多