显然,来自非托管进程外COM服务器的事件的托管处理程序在随机池线程上回调,而不是在主STA线程上回调(正如我所期望的那样)。
我在Internet Explorer automation回答问题时发现了这一点。在下面的代码中,DocumentComplete
在非UI线程上触发(因此"Event thread"
与调试输出中的"Main thread"
不同)。因此,我必须使用this.Invoke
来显示消息框。据我所知,此行为与非托管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");
}
}
}
答案 0 :(得分:2)
我从Adam Nathan的the following excerpt找到了".NET and COM: The Complete Interoperability Guide":
如果COM对象位于STA中,则来自MTA线程的任何调用都是 适当地编组,以便COM对象保持在其世界中 线程亲和力。但是,在另一个方向,没有这样的线程或 上下文切换发生。
因此,这是预期的行为。到目前为止,这是我能找到的唯一(半官方)资料来源。