显然,来自非托管进程外COM服务器的事件的托管处理程序在随机池线程上回调,而不是在主STA线程上回调(正如我所期望的那样).
我在回答
Internet Explorer automation上的问题时发现了这一点.在下面的代码中,DocumentComplete在非UI线程上触发(因此“事件线程”与调试输出中的“主线程”不同).因此,我必须使用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");
}
}
}
最佳答案 我从Adam Nathan的
“.NET and COM: The Complete Interoperability Guide”中找到了
the following excerpt:
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.
因此,这是预期的行为.到目前为止,这是我能找到的唯一(半官方)来源.