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

Handling events from out-of-proc COM server in managed STA application(在托管 STA 应用程序中处理来自进程外 COM 服务器的事件)
本文介绍了在托管 STA 应用程序中处理来自进程外 COM 服务器的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Apparently, managed handlers for events, sourced from an unmanaged out-of-process COM server, are called back on a random pool thread, rather than on the main STA thread (as I'd expect). I've discovered this while answering a question on Internet Explorer automation. In the code below, DocumentComplete is fired on a non-UI thread (so "Event thread" is not the same as "Main thread" in the debug output). Thus, I have to use this.Invoke to show a message box. To the best of my knowledge, this behavior is different from unmanaged COM clients, where events subscribed to from an STA thread are automatically marshalled back to the the same thread.

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

What is the reason behind such departure from the traditional COM behavior? So far, I haven't found any references confirming this.

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");
        }
    }
}

推荐答案

我发现 以下摘录来自Adam Nathan 的 ".NET 和 COM:完整的互操作性指南":

I've found the following excerpt from Adam Nathan's ".NET and COM: The Complete Interoperability Guide":

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

If the COM object lives in an STA, any calls from MTA threads are marshaled appropriately so the COM object remains in its world of thread affinity. But, in the other direction, no such thread or context switch occurs.

因此,这是预期的行为.到目前为止,这是我能找到的关于该主题的唯一(半官方)来源.

Thus, this is the expected behavior. So far, that's the only (semi-official) source on the subject I could find.

这篇关于在托管 STA 应用程序中处理来自进程外 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子句?)