引用非托管COM对象时,运行时可调用包装器(RCW)的范围是什么?根据文件:
运行时只创建一个RCW 对于每个COM对象,无论如何 存在的引用数量 那个对象。
如果我不得不“猜测” - 这个解释应该意味着“每个过程一个”,但它真的吗?我们非常欢迎任何其他文件。
我的应用程序在自己的应用程序域(它是Outlook插件)中运行,我想知道如果我在循环中使用Marshal.ReleaseComObject(x)直到它的计数达到0(按照建议)会发生什么。它是否会从其他插件中释放引用(在同一个Outlook进程中的其他应用程序域中运行)?
编辑:完美 - 现在混乱更加严重。基于2个答案(来自Lette和Ilya),我们有2个不同的答案。官方MSDN doc表示每个流程(版本2.0+),但ver. 1.1 of the doc错过了这句话。
与此同时,在Mason Bendixen的文章中,它表示它是每个appdomain。
由于他的文章已经过时(2007年4月),我已经向他发送了一封要求澄清的电子邮件,但如果其他人必须添加内容,请执行此操作。
由于
答案 0 :(得分:3)
在托管中,我们有一个每个应用域 高速缓存 映射规范IUnknowns回到 的RCW。当IUnknown进入时 系统(通过元帅电话, 通过激活,作为回报 来自方法调用的参数等), 我们检查缓存以查看RCW 已存在的COM对象。如果 存在映射,引用 返回现有的RCW。否则一个 创建了新的RCW并进行了缓存映射 已添加。
答案 1 :(得分:3)
Ilya引用的Mason Bendixen博客文章是正确的:RCW的范围是AppDomain,而不是进程。我只能猜测Runtime Callable Wrapper (MSDN 2.0)文章是“随便”说的。该文章在一般意义上不一定是不正确的,因为最典型的是仅使用单个AppDomain执行,但该句子在技术上并不准确。
关于你的具体问题:
“我想知道如果我会发生什么 在a中使用Marshal.ReleaseComObject(x) 循环,直到它的计数达到0(如 推荐的)。它会释放吗? 来自其他插件的引用 (在其他应用程序域中运行 在同一个Outlook过程中)??“
答案取决于您设置加载项的方式。通常,如果您不采取预防措施,那么答案是肯定的,它会影响在同一AppDomain中运行的其他加载项中的引用。但是既然你声明你是从一个单独的AppDomain运行的,那么,不,它不会。
您可以使用COM Shim Wizard Version 2.3.1来隔离加载项。可以在此处找到COM Shim向导的文档:Isolating Microsoft Office Extensions with the COM Shim Wizard Version 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,则您的代码是隔离的,但其身份可能与其他加载项不同,但是,因为您的加载项仍将共享默认的mscoree.dll加载程序,除非您使用其他一些方法可以解决这个问题。
我希望这会有所帮助......
答案 2 :(得分:1)
根据相同的文档:
运行时为每个对象维护单个RCW 每个进程。
我认为我们可以安全地假设 object = instance ,因此如果addins / AppDomains不保存对同一实例的引用,则调用{{1不会释放对其他地方创建的实例的引用。
编辑:文档的措辞可能有误,as stated elsewhere。如果是这样,因为你的加载项是在一个单独的AppDomain中运行的,所以你很幸运。即使不同的加载项引用相同的实例(例如Outlook中的Message对象),在AppDomain中调用的ReleaseComObject
也不会导致其他AppDomain中的RCW丢失对该实例的引用。