与.NET 4.0无法使用"与其基础RCW分离的COM对象"

use*_*042 7 c# com com-callable-wrapper

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

ICOMInterface1  myVar= obj as ICOMInterface2; 
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jas*_*ski 13

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

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

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

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

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