.NET和COM互操作性:从.NET客户端发布COM

时间:2012-03-14 19:49:26

标签: .net com com-interop

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

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

2 个答案:

答案 0 :(得分:2)

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

明确使用FinalReleaseComObject实际上会导致编程错误。如果代码中的另一个组件仍然引用COM对象,那么您将从其下面取出本机对象。这可能会导致运行时故障。

答案 1 :(得分:2)

已修改“是”,以及“否”。

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

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

  1. 每次一个对象从COM-> NET交叉时,它应该 FinalRelaseComObject但不是 {{1} ,调用它。也就是说,每次对象交叉时都应该调用一次 ,即使它导致引用等于RCW
  2. 对RCW(只是代理包装器)的引用数量无关紧要;只有物体越过边界的时间。参见规则#1。 (控制引用和保留它们很重要,但在这种情况下发生的“最差”是使用“分离的RCW”的例外,它与使用Disposed流的没有区别。)
  3. 我说上面的规则和 ReleaseComObject因为RCW对象被缓存在身份代理中,所以使用FinalReleaseComObject 会影响COM- > NET边界交叉,你甚至不知道 ! (这很糟糕,在这一点上,我完全同意JaredPars的回答。)

    “no”,当RCW被回收(终结者被调用)时,它将自动“释放”COM引用(有效地调用{{ 1}}本身)。请记住,因为只有一个RCW对象,这意味着只要在.NET中引用它就永远不会回收。如果RCW被回收,则没有问题,因为从上面来看,没有更多对RCW的引用,因此.NET知道它可以将COM引用减少1(这可能会导致COM要销毁的对象。)

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

    在我的代码中,我有一个支持FinalReleaseComObject的{​​{1}}类。这允许我通过清除生命周期所有权传递从COM-> NET获得的RCW对象。在切换到这种方法和众多问题之后,我在Outlook-Addin开发中遇到的问题很少(实际上几乎没有)。 “缺点”是需要确定COM-> NET边界,但一旦确定,则内部所有生命周期都得到正确处理。

    快乐的编码。