“不能将与其基础 RCW 分离的 COM 对象用于”与 .NET 4.0

本文关键字:用于 对象 COM NET 分离 不能 RCW | 更新日期: 2023-09-27 18:30:42

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

ICOMInterface1  myVar= obj as ICOMInterface2; 

已与其基础 RCW 分离的 COM 对象不能 使用。

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

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

“不能将与其基础 RCW 分离的 COM 对象用于”与 .NET 4.0

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