处理托管STA应用程序中进程外COM服务器的事件

本文关键字:COM 服务器 事件 进程 STA 应用程序 处理 | 更新日期: 2023-09-27 18:29:11

显然,来自非托管进程外COM服务器的事件的托管处理程序是在随机池线程上调用的,而不是在主STA线程上(正如我所期望的)。我在回答一个关于Internet Explorer自动化的问题时发现了这一点。在下面的代码中,DocumentComplete是在非UI线程上激发的(因此"Event thread"与调试输出中的"Main thread"不同)。因此,我必须使用this.Invoke来显示一个消息框。据我所知,这种行为与非托管COM客户端不同,在非托管COM客户机中,从STA线程订阅的事件会自动编组回同一线程。

这种背离COM传统行为的原因是什么?到目前为止,我还没有找到任何证实这一点的参考资料。

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace WinformsIE
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs ev)
        {
            var ie = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
            ie.Visible = true;
            Debug.Print("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
            ie.DocumentComplete += (object browser, ref object URL) =>
            {
                string url = URL.ToString();
                Debug.Print("Event thread: {0}", Thread.CurrentThread.ManagedThreadId);
                this.Invoke(new Action(() =>
                {
                    Debug.Print("Action thread: {0}", Thread.CurrentThread.ManagedThreadId);
                    var message = String.Format("Page loaded: {0}", url);
                    MessageBox.Show(message);
                }));
            };
            ie.Navigate("http://www.example.com");
        }
    }
}

处理托管STA应用程序中进程外COM服务器的事件

我从Adam Nathan的".NET and COM:the Complete Interoperability Guide"中找到了以下摘录:

如果COM对象位于STA中,则来自MTA线程的任何调用适当地封送,以便COM对象保留在线程亲和性。但是,在另一个方向上,没有这样的线索或上下文切换发生。

因此,这就是预期的行为。到目前为止,这是我能找到的关于这个问题的唯一(半官方)消息来源。