引用非托管COM对象时,运行时可调用包装器(RCW)的范围是什么?根据文件:

  

运行时只创建一个RCW   对于每个COM对象,无论如何   存在的引用数量   那个对象。

如果我不得不“猜测” - 这个解释应该意味着“每个进程一个”,但它真的吗?我们非常欢迎任何其他文件。

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

编辑:完美 - 现在混乱更加严重。基于2个答案(来自Lette和Ilya),我们有2个不同的答案。官方 MSDN doc 表示每个流程(适用于版本2.0+),但它缺少这句话版本。 1.1的文档

与此同时,在Mason Bendixen的文章中,它表示它是每个appdomain。

由于他的文章已经过时(2007年4月),我已经向他发送了一封要求澄清的电子邮件,但如果其他人必须添加内容,请执行此操作。

由于

有帮助吗?

解决方案

  

在托管中,我们有一个每个应用域   高速缓存   映射规范IUnknowns回到   的RCW。当IUnknown进入时   系统(通过元帅电话,   通过激活,作为回报   来自方法调用的参数等),   我们检查缓存以查看RCW   已存在的COM对象。如果   存在映射,引用   返回现有的RCW。否则一个   创建了新的RCW并进行了缓存映射   已添加。

来自梅森的博客

其他提示

Ilya引用的Mason Bendixen博客文章是正确的:RCW的范围是AppDomain,而不是进程。我只能猜测运行时可调用包装器(MSDN 2.0) 文章是“随便”说的。该文章在一般意义上不一定是不正确的,因为最典型的是仅使用单个AppDomain执行,但该句子在技术上并不准确。

关于你的具体问题:

  

“我想知道如果我会发生什么   在a中使用Marshal.ReleaseComObject(x)   循环,直到它的计数达到0(如   推荐的)。它会释放吗?   来自其他插件的引用   (在其他应用程序域中运行   在同一个Outlook进程中)??“

答案取决于您设置加载项的方式。通常,如果您不采取预防措施,那么答案是肯定的,它会影响在同一AppDomain中运行的其他加载项中的引用。但是既然你声明你是从一个单独的AppDomain运行的,那么,不,它不会。

COM Shim可用于隔离加载项的向导版本2.3.1 。可以在此处找到COM Shim向导的文档:使用以下方法隔离Microsoft Office Extensions COM Shim Wizard版本2.3.1

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

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

(2)通过在单独的AppDomain中加载程序集,运行时可调用包装器(RCW)与加载到同一进程中的其他加载项隔离。在这种情况下,如果你调用Marshal.ReleaseComObject(object)或Marshal.FinalReleaseComObject(object),那么你就不会影响其他人的加载项。更重要的是,如果任何其他加载项进行此类调用,则可以保护您的加载项免受损坏。 : - )

使用COM Shim向导的缺点是,通过在单独的AppDomain中运行,会产生额外的编组开销。我不相信这对于Microsoft Outlook加载项应该是显而易见的。但是,对于某些对对象模型进行大量调用的密集例程,这可能是一个因素,例如有时可能是Microsoft Excel加载项的情况。

您声明您已经从单独的AppDomain运行加载项。如果这是真的,那么您已经与Marshal.ReleaseComObject(对象)和Marshal.FinalReleaseComObject(对象)相对于其他AppDomain进行了隔离。 (顺便说一下,我很好奇你是如何做到这一点的......你明确地创建自己的AppDomain吗?Visual Studio中的默认加载项模板在单独的AppDomain中运行并加载使用mscoree.dll。)

如果您要创建自己的AppDomain,您的代码是孤立的,但其身份可能与其他加载项不同,但是,因为您的加载项仍然是sharin

根据相同的文档:

  

运行时为每个对象维护单个RCW 每个进程

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top