从BackgroundWorker调用的CoInitialize C#

时间:2018-01-16 13:08:02

标签: c# c++ dll com backgroundworker

我有一个使用C ++ DLL的C#Windows窗体应用程序。在DLL中,我初始化COM:

auto hResult = CoInitialize(NULL); // Initialize COM
if (hResult != S_OK && hResult != S_FALSE) { 
    WSACleanup(); 
    return 1; 
}

当我在BackgroundWorker进程之外运行DLL时,一切正常。如果我这样做,我的应用程序冻结DLL完成。所以,我正在尝试使用BackgroundWorker;但每当我在DoWork函数中运行DLL时,我都无法初始化COM。

有人可以解释一下,并提供有关如何在BackgroundWorker中运行我的DLL的任何建议吗?

谢谢。

1 个答案:

答案 0 :(得分:1)

BackgroundWorker使用线程池线程。 .NET线程池线程自动初始化为MTA(CoInitializeEx(NULL, COINIT_MULTITHREADED))。您的DLL正在尝试将线程初始化为STA(CoInitialize()),并且该调用应该返回RPC_E_CHANGED_MODE。这是一个失败。

通常,我不会在库中初始化调用线程上的COM 。我认为这是一个反模式。单个客户端应用程序可以使用多个库,并且每个库可能(尝试)初始化COM。更好的设计是让每个线程的所有者在该线程上初始化COM。您的客户端应用程序将为主线程及其拥有的任何后台线程初始化COM(.NET会为您完成所有这些操作)。每个库都会指定(在文档中)其入口点的线程/单元要求(例如"必须从STA线程调用此DLL' FooExport函数。")。库拥有的线程将由库控制其公寓状态。从库中调用CoInitialize/Ex的唯一真正好处是尝试检测您的线程当前所处的公寓状态,以便以编程方式检查库的公寓要求,但是有一些场景(中性) - 这是一个有问题的公寓)。

根据您的情况:

  • 如果您的DLL需要STA,请在客户端应用程序中手动创建后台线程,并在启动线程之前将单元状态设置为STA(请参阅SetApartmentState)。另请考虑删除库中的CoInitialize电话。
  • 如果您的DLL可以使用MTA,请从您的DLL中删除CoInitialize来电,或使用CoInitializeEx(NULL, COINIT_MULTITHREADED)