如何在C#中为COM STA线程提取消息?

时间:2011-07-21 04:55:40

标签: c# com message sta doevents

我有一个主要的STA线程,它在COM对象上调用很多方法,而辅助STA线程也在同一个对象上执行大量工作。我希望主线程和辅助线程并行工作(即我希望主要和次要的隔行扫描输出)。我知道我需要不时地在主线程中抽取消息 - 在C ++中调用Get / Translate / DispatchMessage就可以了。

但是我遇到了在C#中使用相同策略的问题。起初我在主线程中使用CurrentThread.Join()来控制第二个线程。它没用。然后我转向Application.DoEvents() - 每当我想要第二个线程运行时,我在主线程中调用它。结果是第二个线程快速抓取控件并且不会松开 - 主线程无法继续直到第二个线程全部完成。

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

正确的做法是什么?是否有C#相当于Get / Translate / DispatchMessage?

由于

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

2 个答案:

答案 0 :(得分:7)

您的原始C ++代码违反了STA合同。其中指出必须将接口指针从一个线程封送到另一个线程,以便对象上的所有调用仅来自一个线程。这是单线程COM服务器的一项硬性要求,但这样做不会带来与在线程安全的代码上从多个线程调用make相关的典型痛苦。使用两个STA线程使您免于此要求,该对象仅由创建它的线程拥有。第二个线程只是另一个线程,由于服务器不支持多线程,因此无法安全地进行调用。

你在C ++代码中以某种方式逃脱了它,很难想象偶尔会有一个小故障。 COM无法在进程内COM服务器上强制执行STA合同,仅在进程外服务器上执行。在这种情况下,违反合同会生成RPC_E_WRONG_THREAD。

Anyhoo,你不再在C#程序中侥幸逃脱。 CLR会自动为您编组接口指针。您在第二个线程上进行的调用将被封送到拥有该对象的STA线程。仍然存在交错,但第二个线程的调用只能在第一个线程空闲并重新进入消息循环时传递。没有解决方法,接口指针的CLR处理严格遵循规则。

这会对我想象的代码产生很多影响,最大的一个是第二个线程真的不再能完成任何事情了。没有并发性,对对象的所有调用都是严格序列化的。并且线程安全。你可能最好只从一个线程进行所有调用,这样你就不必为死锁带来相当大的风险。作为奖励,使正确的消息流动不那么重要。如果第二个线程执行其他关键工作,那么利用COM支持单线程代码可能会有所帮助。

答案 1 :(得分:3)

就.Net中的Get / Translate / Dispatch而言,你应该可以在你的帮助线程上调用Application.RunDispatcher.Run()(取决于你是使用winforms还是wpf)。这将在该线程上为您调用Get / Trans / Dispatch。如果你不喜欢这个想法,那么你可以P / Invoke Win32调用。

虽然.Net会根据hans'回答几乎所有内容都适合你,但实际上我发现来自COM对象的消息会导致你的UI线程断断续续,因为底层的DispatchMessage()似乎需要很长时间(肯定比我预期的要长,或者可以解释)。我们改变了我们的解决方案,在辅助线程上创建COM对象,并明确地从UI线程调度它。