Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/jenkins/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在托管STA应用程序中处理来自进程外COM服务器的事件_C#_.net_Multithreading_Com_Com Interop - Fatal编程技术网

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

C# 在托管STA应用程序中处理来自进程外COM服务器的事件,c#,.net,multithreading,com,com-interop,C#,.net,Multithreading,Com,Com Interop,显然,源于非托管进程外COM服务器的事件托管处理程序在随机池线程上调用,而不是在主STA线程上调用(如我所料)。 我在回答一个问题时发现了这一点。在下面的代码中,DocumentComplete在非UI线程上触发(因此“事件线程”与调试输出中的“主线程”不同)。因此,我必须使用this.Invoke来显示消息框。据我所知,这种行为不同于非托管COM客户端,在非托管COM客户端中,从STA线程订阅的事件会自动封送回同一线程 这种背离传统COM行为的原因是什么?到目前为止,我还没有找到任何证实这一点

显然,源于非托管进程外COM服务器的事件托管处理程序在随机池线程上调用,而不是在主STA线程上调用(如我所料)。 我在回答一个问题时发现了这一点。在下面的代码中,
DocumentComplete
在非UI线程上触发(因此
“事件线程”
与调试输出中的
“主线程”
不同)。因此,我必须使用
this.Invoke
来显示消息框。据我所知,这种行为不同于非托管COM客户端,在非托管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");
        }
    }
}
我从亚当·内森那里找到:

如果COM对象位于STA中,则来自MTA线程的任何调用都将被删除 对COM对象进行了适当的封送处理,以使COM对象保持在其 线程亲和力。但是,在另一个方向上,没有这样的线或线 发生上下文切换


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

您的“主(…)”线程如何,或者您调用Activator.CreateInstance()的线程的单元状态是什么?这里的主线程和唯一显式线程是STA。该应用程序本身只是VS2012向导生成的WinForms应用程序:
[StatThread]static void Main(){/*…*/Application.Run(new Form1();}
。我认为这是正常的行为。接收事件的是由CLR(CCW或类似程序)实现的隐藏COM对象,该对象可能具有任何线程模型。NET中的事件可以到达任何线程。顺便说一句,让我们刷新一下记忆:-)@SimonMourier,我几乎记得在某个地方读到过,他们完全按照您描述的方式更改了COM=>.NET回调的规则。虽然你给出的链接似乎没有明确说明这一点。我也找不到任何其他来源。也许是亚当·内森写的关于互操作的书。这样吧,
ie
out-proc-proxy-free线程化了吗?我可以安全地直接从随机线程上的事件处理程序调用
ie
api吗?另外,我想知道我是否可以通过实现一个定制的
SynchronizationContext
来恢复传统的COM行为。因为它是进程外的,你可以在我相信的任何线程上调用IE,COM+代理/存根将发挥神奇的作用。我认为返回COM行为的唯一方法不是依赖于COM实现底层的.NET事件(委托等),而是实现手动COM事件接收器(IConnectionPoint等)。您应该能够以自己喜欢的方式声明此接收器对象单元行为。从未测试过这对我来说似乎太过分了:-)。。。下面是如何收回预期行为: