7

我的 .NET 3.5 C# WinForms 应用程序中有一个类,它有五个方法。每种方法都使用不同的 C++ COM 接口集。用于Marshal.FinalReleaseCOMObject清理这些 COM 对象。此代码在此 .NET 平台上运行良好,没有任何问题。但是,当我将此应用程序移至 .NET 4.0 时,我开始在这些方法之一中将变量从ICOMInterface1to 转换为的行中出现此错误ICOMInterface2,即:

ICOMInterface1  myVar= obj as ICOMInterface2; 

无法使用已与其底层 RCW 分离的 COM 对象。

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

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

4

1 回答 1

14

简单的答案是永远不要使用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的好博客文章,它是邪恶的。这是一种危险的武器,除非需要,否则只会伤害你。既然你在问这个问题,我怀疑你实际上根本不需要打电话。:-)

于 2012-04-11T16:30:20.610 回答