问题描述
显然,来自非托管进程外 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 对象保留在它的世界中线程亲和性.但是,在另一个方向,没有这样的线程或发生上下文切换.
因此,这是预期的行为.到目前为止,这是我能找到的关于该主题的唯一(半官方)来源.
Thus, this is the expected behavior. So far, that's the only (semi-official) source on the subject I could find.
这篇关于在托管 STA 应用程序中处理来自进程外 COM 服务器的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!