“与基础RCW分离的COM对象不能与.NET 4.0一起使用”

我在.NET 3.5 C#WinForms应用程序中有一个类,它有五种方法。 每种方法都使用不同的C ++ COM接口集。 我使用Marshal.FinalReleaseCOMObject来清理这些COM对象。 此代码在此.NET平台上运行正常,没有任何问题。 但是,当我将此应用程序移动到.NET 4.0时,我开始在这些方法中的一个中将错误从ICOMInterface1ICOMInterface2 ,即:

 ICOMInterface1 myVar= obj as ICOMInterface2; 

无法使用已与其基础RCW分离的COM对象。

如果我删除使用Marshal.FinalReleaseCOMObject的行,我不会收到此错误。

我在这里想念的是什么? 如何从.NET 4.0平台上的内存中清除这些非托管COM对象?

简单的答案是永远不要使用Marshal.FinalReleaseComObject除非你绝对必须。 如果你这样做,你必须遵循一些额外的规则。

当在.NET中使用COM对象时,运行时会为该对象创建所谓的“RCW”或“运行时可调用包装器”。 这个RCW只是一个普通的对象,它在对象上保存一个COM引用。 当这个对象被垃圾收集时,它将调用COM对象上的IUnknown :: Release(),正如您所期望的那样。 这意味着除非您的COM对象要求最后一个Release()在非常特定的时刻完成,只需让垃圾收集器处理它。 许多COM对象属于这种情况,因此请务必仔细validation是否必须仔细管理对Release()的调用。

因此,当您调用FinalReleaseComObject时,这实际上是递减RCW对COM对象的引用,直到它达到零并且RCW然后释放COM对象。 此时,这个RCW现在被僵尸了,任何使用它都会给你看到的例外。 CLR(默认情况下)仅为任何底层COM对象创建单个RCW,因此这意味着如果您正在使用的COM API两次返回相同的对象,那么它将只有一个RCW。 调用FinalReleaseComObject意味着突然所有 RCW的使用都是吐司。

保证您拥有唯一Marshal.GetUniqueObjectForIUnknown的唯一方法,它可以阻止任何RCW共享。 但正如我之前所说,在大多数COM API中,首先不需要这样做,所以就是不要这样做。

Paul Harrington撰写了一篇关于[Final] ReleaseComObject的好文章 ,这是一个很好的例子。 它是一种危险的武器,除非需要只会伤害你。 既然你问这个问题,我怀疑你实际上根本不需要调用它。 🙂