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

显然,来自非托管进程外COM服务器的事件的托管处理程序在随机池线程上调用,而不是在主STA线程上调用(正如我所期望的那样)。 我在回答有关Internet Explorer自动化的问题时发现了这一点。 在下面的代码中, 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"); } } } 

我从Adam Nathan的“.NET和COM:完整的互操作性指南”中找到了以下摘录 :

如果COM对象位于STA中,则来自MTA线程的任何调用都会被适当地封送,因此COM对象仍然处于线程关联的世界中。 但是,在另一个方向上,没有发生这样的线程或上下文切换。

因此,这是预期的行为。 到目前为止,这是我能找到的唯一(半官方)资料来源。