“不能使用已与其基础RCW分离的COM对象”。与.NET 4.0 [英] "COM object that has been separated from its underlying RCW cannot be used" with .NET 4.0

查看:312
本文介绍了“不能使用已与其基础RCW分离的COM对象”。与.NET 4.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在.NET 3.5 C#WinForms应用程序中有一个类,它具有五个方法。
每个方法使用不同的C ++ COM接口集。
是使用 Marshal.FinalReleaseCOMObject 清理这些COM对象的。此代码在此.NET平台上可以正常工作,没有任何问题。
但是,当我将此应用程序移至.NET 4.0时,在其中将 ICOMInterface1 转换为 ICOMInterface2 ,即:

I've a class in my .NET 3.5 C# WinForms application which has five methods. Each method uses different sets of C++ COM interfaces. Am using Marshal.FinalReleaseCOMObject for cleaning up these COM objects. This code works fine on this .NET platform without any issues. But when I move this application to .NET 4.0, I start getting this error in one of these methods at a line where I cast a variable from ICOMInterface1 to ICOMInterface2, i.e.:

ICOMInterface1  myVar= obj as ICOMInterface2; 




与其基础RCW分开的COM对象不能为$ b使用$ b。

COM object that has been separated from its underlying RCW cannot be used.

如果我删除正在使用 Marshal.FinalReleaseCOMObject ,我没有收到此错误。

And if I remove the line where am using Marshal.FinalReleaseCOMObject, I don't get this error.

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

What am I missing here? And how do I clean up these unmanaged COM objects from the memory on .NET 4.0 platform?

推荐答案

简单的答案是<除非绝对必要,否则不要使用 Marshal.FinalReleaseComObject 。而且,如果这样做,您还必须遵循一些其他规则。

The simple answer is to never use Marshal.FinalReleaseComObject unless you absolutely must. And if you do, there are some additional rules you must follow.

在.NET中使用COM对象时,运行时将创建称为 RCW或该对象的运行时可调用包装器。此RCW只是在对象上保留COM引用的普通对象。如您所料,当该对象被垃圾回收时,它将在COM对象上调用IUnknown :: Release()。这意味着除非您的COM对象要求,最后的Release()在某个特定时刻完成,否则请让垃圾收集器来处理它。许多COM对象都属于这种情况,因此请绝对验证您必须仔细管理对Release()的调用。

When a COM object is used in .NET, the runtime creates what's known as a "RCW" or "runtime callable wrapper" for that object. This RCW is just a normal object that holds a COM reference on the object. When this object is garbage collected, it will call IUnknown::Release() on the COM object, as you'd expect. What this means is unless your COM object requires that the last Release() is done at a very certain moment in time, just let the garbage collector take care of it. Many COM objects fall into this case, so absolutely verify that you must manage the call to Release() carefully.

因此,当您调用FinalReleaseComObject,这实际上是减少RCW对COM对象的引用,直到它达到零,然后RCW释放COM对象。至此,此RCW已变成僵尸,对它的任何使用都会产生您所看到的异常。 CLR(默认情况下)仅为任何基础的COM对象创建一个RCW,因此这意味着,如果您使用的COM API两次返回相同的对象,那么它将只有一个RCW。调用FinalReleaseComObject意味着突然所有对该RCW的使用都是吐司。

So when you're calling FinalReleaseComObject, that is essentially decrementing the reference the RCW has on the COM object until it hits zero and the RCW then releases the COM object. At this point, this RCW is now zombied, and any use of it will give the exception you've seen. The CLR (by default) only creates a single RCW for any underlying COM object, so this means if the COM API you're using returned the same object twice, it's just going to have a single RCW. Calling FinalReleaseComObjectwould mean that suddenly all uses of that RCW are toast.

唯一保证您拥有唯一的Marshal.GetUniqueObjectForIUnknown的方法,这可以防止任何RCW共享。但是就像我前面说过的那样,在大多数COM API中并不是一开始就要做的,所以就不要这样做。

The only way to guarantee you have a unique Marshal.GetUniqueObjectForIUnknown, which prevents any RCW sharing. But like I said earlier, in most COM APIs this isn't neccessary to do in the first place, so just don't do it.

Paul Harrington写下了一个很好的博客文章关于[Final] ReleaseComObject及其弊端。这是一种危险的武器,除非需要,否则只会伤害您。由于您是在问这个问题,所以我怀疑您实际上根本不需要打这个电话。 :-)

Paul Harrington wrote up a good blog post about [Final]ReleaseComObject and it's evils. It's a dangerous weapon that unless needed will only hurt you. Since you're asking this question, I'd suspect you don't actually need to be calling it at all. :-)

这篇关于“不能使用已与其基础RCW分离的COM对象”。与.NET 4.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆