RCW &在 C# 中使用 COM 互操作时的引用计数

RCW amp; reference counting when using COM interop in C#(RCW amp;在 C# 中使用 COM 互操作时的引用计数)
本文介绍了RCW &在 C# 中使用 COM 互操作时的引用计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Office 互操作程序集的应用程序.我知道运行时管理的运行时可调用包装器(RCW)".但我不太确定引用计数是如何增加的.MSDN 说,

I have an application that uses Office interop assemblies. I am aware about the "Runtime Callable Wrapper (RCW)" managed by the runtime. But I am not very sure how the reference count gets incremented. MSDN says,

RCW 只保留一个对包装的 COM 对象,无论调用它的托管客户端的数量.

RCW keeps just one reference to the wrapped COM object regardless of the number of managed clients calling it.

如果我理解正确,在下面的例子中,

If I understand it correctly, on the following example,

using Microsoft.Office.Interop.Word;

static void Foo(Application wrd)
{
    /* .... */
}

static void Main(string[] args)
{
    var wrd = new Application();
    Foo(wrd);
    /* .... */
}

我将实例 wrd 传递给另一个方法.但这不会增加内部引用计数.所以我想知道在什么情况下引用计数会增加?谁能指出引用计数增加的情况?

I am passing the instance wrd to another method. But this doesn't increment the internal reference count. So I am wondering on what scenarios the reference count gets incremented? Can anyone point out a scenario where the reference count gets incremented?

我还阅读了一些博客,其中说在使用 COM 对象进行编程时避免使用双点.类似于 wrd.ActiveDocument.ActiveWindow.作者声称编译器创建单独的变量来保存将增加引用计数器的值.恕我直言,这是错误的,第一个例子证明了这一点.对吗?

Also I read some blog which says avoid using double dots when programming with COM objects. Something like, wrd.ActiveDocument.ActiveWindow. The author claims that compiler creates separate variables to hold the values which will increment the reference counter. IMHO, this is wrong and the first example proves this. Is that correct?

任何帮助都会很棒!

推荐答案

我也一直在研究这个问题,致力于以 COM/.Net-Interop 为中心的应用程序,解决泄漏、挂起和崩溃问题.

I have been researching this question too, working on a COM/.Net-Interop-centric application, fighting leaks, hangs and crashes.

简答:每次将 COM 对象从 COM 环境传递到 .NET.

Short answer: Every time the COM object is passed from COM environment to .NET.

长答案:

  1. 对于每个 COM 对象,都有一个 RCW 对象 [测试 1] [参考 4]
  2. 每次从 COM 对象中请求对象时,引用计数都会增加(调用返回 COM 对象的 COM 对象的属性或方法,返回的 COM 对象引用计数将增加 1)[测试 1]
  3. 通过转换为对象的其他 COM 接口或在 [Test 2] 周围移动 RCW 引用不会增加引用计数
  4. 每次将对象作为 COM 引发的事件中的参数传递时,引用计数都会增加 [Ref 1]

附带说明:您应该始终在使用完 COM 对象后立即释放它们.将这项工作留给 GC 可能会导致泄漏、意外行为和事件死锁.如果您访问的对象不在创建对象的 STA 线程上,则这一点要重要十倍.[参考 2] [参考 3] [痛苦的个人经历]

On a side note: You should ALWAYS release COM objects as soon as you are finished using them. Leaving this work to the GC can lead to leaks, unexpected behavior and event deadlocks. This is tenfold more important if you access object not on the STA thread it was created on. [Ref 2] [Ref 3] [Painful personal experience]

我希望我已经涵盖了所有情况,但是 COM 是一个棘手的问题.干杯.

I'm hope I have covered all cases, but COM is a tough cookie. Cheers.

测试 1 - 引用计数

private void Test1( _Application outlookApp )
{
    var explorer1 = outlookApp.ActiveExplorer();
    var count1 = Marshal.ReleaseComObject(explorer1);
    MessageBox.Show("Count 1:" + count1);

    var explorer2 = outlookApp.ActiveExplorer();
    var explorer3 = outlookApp.ActiveExplorer();
    var explorer4 = outlookApp.ActiveExplorer();

    var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer4);
    var count2 = Marshal.ReleaseComObject(explorer4);
    MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 6, Equals: True

测试 2 - 引用计数续.

private static void Test2(_Application outlookApp)
{
    var explorer1 = outlookApp.ActiveExplorer();
    var count1 = Marshal.ReleaseComObject(explorer1);
    MessageBox.Show("Count 1:" + count1);

    var explorer2 = outlookApp.ActiveExplorer();

    var explorer3 = explorer2 as _Explorer;
    var explorer4 = (ExplorerEvents_10_Event)explorer2;
    var explorerObject = (object)explorer2;
    var explorer5 = (Explorer)explorerObject;

    var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer5);
    var count2 = Marshal.ReleaseComObject(explorer4);
    MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 4, Equals: True

除了我的经验和测试之外,我还引用了以下来源:

1.Johannes Passing's - RCW 引用计数规则!= COM 引用计数规则

2.Eran Sandler - Runtime Callable Wrapper Internals 和常见的陷阱

3.Eran Sandler - Marshal.ReleaseComObject 和 CPU 旋转

4.MSDN - 运行时可调用包装器

这篇关于RCW &在 C# 中使用 COM 互操作时的引用计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)