multithreading - COM 对象方法不在 CoInitialize-d 并创建对象的线程上执行

标签 multithreading com methods invoke

我正在开发一个 UI 应用程序,它会一路创建一个 COM 对象。
问题是,我想将这个 COM 对象完全“移动”到另一个线程上。

我要做的是:

  • 创建我想将对象移动到的新线程(使用 CreateThread API)
  • 进入此线程后,我正在调用 PeekMessage 为其设置消息队列
  • 调用CoInitialize,CoCreateInstance创建COM对象,QueryInterface得到我想要的接口(interface)
  • 最后,我在界面上调用一个方法,该方法显示一个带有 GetCurrentThreadId() 返回值的 MessageBox(我可以访问该对象所在的 COM 库的 VB6 代码)。

  • 问题是,正如此消息框所示,对象方法仍然在原始 UI 线程上执行,而不是在我创建并完成所有这些步骤的线程上执行。还要提一提,在调用了接口(interface)方法之后,我还在里面设置了一个经典的消息循环。

    我怎样才能改变这种行为并实现我想要的? (也就是说,我希望源自我新创建的线程的 COM 对象调用在 IT 上执行,而不是在原始应用程序线程上执行)

    这是一些伪代码,使其更加清晰:
    void myMainUIMethod(){
      MessageBox(GetCurrentThreadId()); // displays 1
      CreateThread(&myCOMObjectThreadProc);
    }
    void myCOMObjectThreadProc(){
      MessageBox(GetCurrentThreadId()); // displays 2
      CoInitialize(NULL);
      myObject = CoCreateInstance(myObjectsCLSID);
      myObjectInterface = myObject->QueryInterface(myObjectInterfaceCLSID);
      myObjectInterface->showThreadIDMessageBox(); // this would be the COM object method call
    }
    
    And, in the VB6 code of the object, here's the pseudo-definition of showThreadIDMessageBox.
    Public Sub showThreadIDMessageBox()
      Call MessageBox(GetCurrentThreadId()) //displays 1, I want it to display 2
    End Sub
    

    在创建新线程之前,我通过在主线程上进行 CoUninitializing 实现了我想要的。但是为什么会这样呢?如果在我创建新线程之前在主线程上初始化了 COM,也许由于某种原因它必须是......我不希望应用程序稍后崩溃,因为我必须在创建新线程之前调用 CoUninitialize。这是一些伪代码,说明无论哪个线程首先调用 CoInitialize 都会被 STA 对象选中。
    void myMainUIMethod(){
      MessageBox(GetCurrentThreadId()); // displays 1
      CoUninitialize(); // uninitialize COM on the main thread
      CreateThread(&myCOMObjectThreadProc);
      ***i: MessageBox("When you want to initialize COM on main thread, confirm this");
      CoInitialize();
    }
    void myCOMObjectThreadProc(){
      MessageBox(GetCurrentThreadId()); // displays 2
      ***ii: MessageBox("When you want to initialize COM on the new thread, confirm this");
      CoInitialize(NULL);
      myObject = CoCreateInstance(myObjectsCLSID);
      myObjectInterface = myObject->QueryInterface(myObjectInterfaceCLSID);
      myObjectInterface->showThreadIDMessageBox(); // this shows 2 IF ***ii is confirmed before ***i, 1 otherwise
    }
    

    非常感谢您,
    科尼留

    最佳答案

    看起来您的问题是您的 COM 组件线程模型是 未指定 在注册表项 InprocServer32 .这意味着该对象被视为 STA(单线程单元),但将被加载到 主(或主机)STA ,而不是创建它的 STA。这是第一个调用 CoInitialize 的线程.在调用 CoCreateInstance 的同一 STA 中创建您必须创建 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{Your CLSID}\InprocServer32@ThreadingModel注册表值并将其设置为 Apartment .

    引用 MSDN (InprocServer32 registry key documentation):

    If ThreadingModel is not present or is not set to a value, the server is loaded into the first apartment that was initialized in the process. This apartment is sometimes referred to as the main single-threaded apartment (STA). If the first STA in a process is initialized by COM, rather than by an explicit call to CoInitialize or CoInitializeEx, it is called the host STA. For example, COM creates a host STA if an in-process server to be loaded requires an STA but there is currently no STA in the process.

    关于multithreading - COM 对象方法不在 CoInitialize-d 并创建对象的线程上执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12487282/

    相关文章:

    C++ Thread函数通过引用传递

    c++ - 无法释放 IUnkown 对象,出现错误 : HRESULT: "The system cannot find the file specified"

    c++ - 到 ATL 的静态链接总是失败

    java - eclipse不匹配构造函数方法调用

    javascript - 事件处理程序无法访问 JavaScript 中的对象方法

    java - 我不知道这个线程有什么问题,我想了解多线程

    java - 如何在所有包含的线程完成之前阻止子例程结束?

    c# - 如何在不阻塞 UI 的情况下顺序运行多个任务?

    c++ - CoCreateInstance 上的 E_ACCESSDENIED,它曾经在这里工作

    php - php函数 'overload'是做什么的?