我有一个使用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的任何建议吗?
谢谢。
答案 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
的唯一真正好处是尝试检测您的线程当前所处的公寓状态,以便以编程方式检查库的公寓要求,但是有一些场景(中性) - 这是一个有问题的公寓)。
根据您的情况:
SetApartmentState
)。另请考虑删除库中的CoInitialize
电话。CoInitialize
来电,或使用CoInitializeEx(NULL, COINIT_MULTITHREADED)
。