运行时可调用包装(RCW)范围-进程还是应用程序域?

时间:2020-03-06 14:59:39  来源:igfitidea点击:

引用非托管COM对象时,Runtime Callable Wrapper(RCW)的范围是什么?根据文档:

The runtime creates exactly one RCW
  for each COM object, regardless of the
  number of references that exist on
  that object.

如果我不得不"猜测",那么这种解释应该意味着"每个过程一个",但这是真的吗?任何其他文档将非常欢迎。

我的应用程序在其自己的应用程序域(它是Outlook加载项)中运行,并且我想知道如果我在循环中使用Marshal.ReleaseComObject(x)直到计数达到0(按照建议)时会发生什么。它将释放来自其他加载项的引用(在同一Outlook进程中的其他应用程序域中运行)吗?

编辑:完美,现在的困惑更大。根据2个答案(来自Lette和Ilya),我们有2个不同的答案。 MSDN官方文档说每个进程(适用于2.0版或者更高版本),但缺少用于ver的这句话。文档的1.1.

同时,在梅森·本迪克森(Mason Bendixen)的文章中,它说这是针​​对每个应用程序域的。

由于他的文章较旧(2007年4月),我给他发送了一封电子邮件,要求其澄清,但是如果其他人必须添加一些内容,请这样做。

谢谢

解决方案

根据相同的文档:

The runtime maintains a single RCW per process for each object.

我认为我们可以放心地假设object = instance,因此,如果addins / AppDomains不保存对同一实例的引用,则对ReleaseComObject的调用不会释放对在其他地方创建的实例的引用。

编辑:文档的措词可能是错误的,如其他地方所述。如果是这样,由于加载项在单独的AppDomain中运行,因此我们很幸运。即使不同的加载项引用了相同的实例(例如Outlook中的Message对象),在AppDomain中调用的ReleaseComObject也不会导致其他AppDomain中的RCW丢失对该实例的引用。

In managed, we have a per app domain
  cache
  mapping canonical IUnknowns back to
  RCWs. When an IUnknown enters the
  system (through a marshal call,
  through activation, as a return
  parameter from a method call, etc.),
  we check the cache to see if an RCW
  already exists for the COM object. If
  a mapping exists, a reference to the
  existing RCW is returned. Otherwise a
  new RCW is created and a cache mapping
  is added.

从梅森的博客

Ilya引用的Mason Bendixen博客文章是正确的:RCW的作用域是AppDomain,而不是过程。我只能猜测Runtime Callable Wrapper(MSDN 2.0)文章说的是"随意"。该文章在一般意义上不一定是错误的,因为最典型的情况是仅使用一个AppDomain执行该语句,但是该语句在技术上并不准确。

关于具体问题:

"I would like to know what happens if I
  use Marshal.ReleaseComObject(x) in a
  loop until it's count reaches 0 (as
  recommended). Will it release
  references from other addins 
  (running in other application domain 
  in the same Outlook process)??"

答案取决于我们如何设置外接程序。通常,如果我们不采取预防措施,那么答案是肯定的,它将影响在同一AppDomain中运行的其他加载项中的引用。但是,由于我们声明自己是从单独的AppDomain运行的,因此,不会,它不会。

有一个COM Shim向导版本2.3.1,可用于隔离外接程序。可以在此处找到COM Shim向导的文档:使用COM Shim向导版本2.3.1隔离Microsoft Office Extensions。

COM Shim向导使用反射来构建自定义的COM前端加载程序,该加载程序将外接程序集加载到单独的AppDomain中。这从两个方面创造了安全性:

(1)通过使用单独的,自定义的COM入口点,Microsoft Office与所有其他外接程序可以正确地分别标识外接程序。否则,默认情况下,所有加载项都共享相同的默认mscoree.dll加载程序。共享同一加载程序的问题是,如果任何加载项发生崩溃,则Microsoft Office将mscoree.dll识别为问题的根源,并且下次将不会自动加载它。我们可以手动将其重新打开,但是由于别人的加载项有问题,加载项下次将不会自动加载!

(2)通过将程序集加载到单独的AppDomain中,可以将运行时可调用包装(RCW)与加载到同一进程中的其他加载项隔离。在这种情况下,如果调用Marshal.ReleaseComObject(object)或者Marshal.FinalReleaseComObject(object),则不会影响其他任何加载项。更重要的是,如果其他任何外接程序进行了此类调用,则可以防止外接程序被损坏。 :-)

使用COM Shim向导的缺点是,通过在单独的AppDomain之外进行操作,会产生额外的编组开销。我认为对于Microsoft Outlook加载项来说,这应该不会引起注意。但是,对于某些需要大量调用对象模型的密集型例程,这可能是一个因素,例如Microsoft Excel加载项有时可能就是这种情况。

我们说我们已经在从单独的AppDomain运行加载项。如果这是真的,那么我们已经与其他AppDomain脱离了Marshal.ReleaseComObject(object)和Marshal.FinalReleaseComObject(object)调用。 (顺便说一下,我对操作方式感到好奇。我们是否明确创建了自己的AppDomain?Visual Studio中的默认加载项模板没有在单独的AppDomain中运行,而是使用mscoree.dll加载。)

如果我们创建自己的AppDomain,则代码是隔离的,但是其标识可能不会与其他加载项分开,因为加载项仍将共享默认的mscoree.dll加载程序,除非我们使用其他方式解决这个问题。

我希望这有帮助...