如何在c#中为COM STA线程发送消息

本文关键字:线程 消息 STA COM 中为 | 更新日期: 2023-09-27 18:03:13

我有一个主STA线程,它在COM对象上调用了很多方法,还有一个辅助STA线程,它在同一个对象上也做了很多工作。我希望主线程和辅助线程并行工作(即我期望主线程和辅助线程的交错输出)。我知道我需要在主线程中不时地泵送消息-在c++中调用Get/Translate/DispatchMessage将完成此任务。

但是我在c#中使用相同的策略时遇到了问题。首先,我在主线程中使用CurrentThread.Join()来控制第二个线程。但没有成功。然后我转向Application.DoEvents() -每当我想要第二个线程运行时,我就在主线程中调用它。结果是第二个线程很快地夺取了控制权,并且不会放手——主线程不能继续,直到第二个线程全部完成。

我读到的文档说Application.DoEvents()将处理所有等待事件-而GetMessage()只检索一条消息。

正确的做法是什么?是否有c#等效的Get/Translate/DispatchMessage?

感谢

UPDATE:第二个线程运行太快,向主STA线程发送了很多COM调用消息。我只是在第二个线程中添加了延迟来减慢它的速度。现在两个线程基本上是并行运行的。但我仍然想知道是否有c#等效的GetMessage/TranslateMessage/DispatchMessage

如何在c#中为COM STA线程发送消息

您的原始c++代码违反了STA合同。它声明接口指针必须从一个线程封送到另一个线程,以便对象上的所有调用只能从一个线程进行。这是单线程COM服务器的硬性要求,如果不这样做,就会冒着从多个线程对非线程安全的代码进行调用的典型风险。使用两个STA线程并不能将您从这个需求中解脱出来,对象仅由创建它的线程拥有。第二个线程只是另一个线程,由于服务器不支持多线程,从它调用不能安全。

你在c++代码中侥幸逃脱了,很难想象没有一个小故障。否则,COM不能在进程内COM服务器上强制执行STA契约,只能在进程外服务器上强制执行。在这种情况下,违反合约会生成rpce_wrong_thread。

无论如何,在c#程序中你不能再这样做了。CLR会自动为您封送接口指针。在第二个线程上进行的调用将被封送到拥有该对象的STA线程。仍然存在交错,但是只有当第一个线程空闲并重新进入消息循环时,第二个线程的调用才能交付。没有解决这个问题的方法,CLR对接口指针的处理是严格遵守规则的。

我想这将对你的代码产生很多影响,最大的一个是第二个线程真的不再完成任何事情了。没有并发性,对对象的所有调用都严格序列化。和线程安全的。您最好从一个线程中调用所有调用,这样您就不必规避死锁的巨大风险。让正确的信息传递变得不那么重要了。如果第二个线程做其他关键的工作,那么利用COM对单线程代码的支持会很有帮助。

就。net中的Get/Translate/Dispatch而言,您应该能够调用Application。在帮助线程上运行或Dispatcher.Run()(取决于您使用的是winforms还是wpf)。这将为您在调用Get/Trans/Dispatch的线程上泵送一个消息循环。如果你不喜欢这样做,那么你可以P/Invoke Win32调用。

虽然。net将使几乎所有的工作为您按照汉斯的回答,在实践中,我发现消息来自COM对象可能会导致你的UI线程的底层DispatchMessage()似乎需要很长时间(当然比我预期的要长,或者可以解释)。我们改变了我们的解决方案,在帮助线程上创建COM对象,并显式地从UI线程编组对它的调用。