【问题标题】:VC++ thread marshalling and COM : The application called an interface that was marshalled for a different threadVC++ 线程编组和 COM:应用程序调用了为不同线程编组的接口
【发布时间】:2011-04-05 08:35:07
【问题描述】:

我的 VC++ 2005 基于对话框的应用程序在对话框类中初始化一个 COM 对象,并在工作线程中使用它。

我在应用程序开始和工作线程开始时调用了 CoInitialize(NULL)。但是,当调用 COM 方法时,会出现错误“应用程序调用了为不同线程编组的接口”。

如果我使用 CoInitializeEx(0,COINIT_MULTITHREADED) 那么我会得到同样的错误信息

请帮我找出根本原因。

谢谢。

【问题讨论】:

    标签: multithreading visual-c++ com


    【解决方案1】:

    您通过调用 CoInitialize(NULL) 创建了两个单线程单元。接口指针必须在可用之前从一个单元封送到另一个单元。将工作线程初始化为 MTA 并不能解决问题。原始接口指针仍然是在单线程单元中创建的,因此不是线程安全的。换句话说,您不能直接从线程调用接口方法。这些调用必须被编组到创建接口的线程。编组接口指针设置了使之成为可能的管道。

    唯一不必编组的情况是两个线程都是 MTA。这几乎是不可能的,如果它创建任何窗口,你的主线程必须是 STA。并且 COM 服务器实际上必须是线程安全的,它们很少是这样的。他们使用注册表中的 ThreadingModel 键来宣传他们需要的东西。如有必要,COM 实际上会创建一个 STA 线程来为服务器找到一个好的归宿。

    您必须使用 CoMarshalInterThreadInterfaceInStream() 编组指针以避免错误。这是一个相当不友好的函数,IGlobalInterfaceTable 更容易使用。 COM 服务器也必须支持它,您通常需要一个代理/存根 DLL 来处理封送处理。如果没有,您将获得 E_NOINTERFACE。

    还要注意开销,将工作线程的调用编组到主线程非常昂贵,并且取决于主线程的响应速度。换句话说,如果您编写线程来加速您的程序或避免阻塞用户界面,那么这实际上是行不通的。这就是“没有免费的午餐”原则。

    【讨论】:

      【解决方案2】:

      CoMarshalInterface()CoUnMarshalInterface() 可能是最简单的方法。

      看看http://support.microsoft.com/kb/206076。您可以下载代码示例并在 Client.cpp 中找到您需求的不同实现。

      【讨论】:

        【解决方案3】:

        我认为在另一个线程中访问 COM 对象的方法之一是使用全局接口指针。初始化后,形成指向线程的 GIT 指针和 dwCookie 值。然后在线程内部将指针重新解释为 DWORD 并将其传递给 GI 表以获取我们的 COM 指针。

        谢谢

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-21
          • 1970-01-01
          • 1970-01-01
          • 2023-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多