c# - 从 BackgroundWorker C# 调用的 CoInitialize

标签 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 提供任何建议吗?

谢谢。

最佳答案

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

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

针对您的场景:

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

关于c# - 从 BackgroundWorker C# 调用的 CoInitialize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48282022/

相关文章:

C#。将对象列表保存到 Mongo 的最快方法

c++ - 可以将 std::map 创建为右值吗?

c++ - 重载 T 和 vector<T>

WPF TreeMap 库?

C# 4.0 允许项目不关心引用版本

C# 将文件(pdf、html 或 rtf)发送到打印机

c# - 在 C# 中使用 DI 登录到控制台

c# - 如何使用 C# StreamWriter 始终写入现有本地驱动器

c++ - 为什么 "Arrays needs a contiguous block of memory"是 C/C++ 中数组的坏点?

c++ - 将非托管 "QT"dll 导入 C# 给出 dllNotFoundException 但存在