【问题标题】:CoInitialize Called from BackgroundWorker C#从 BackgroundWorker C# 调用 CoInitialize
【发布时间】:2018-06-25 04:58:40
【问题描述】:

我有一个使用 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 的任何建议?

谢谢。

【问题讨论】:

    标签: c# c++ dll com backgroundworker


    【解决方案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)

    【讨论】:

      猜你喜欢
      • 2013-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 2014-12-31
      • 2018-04-05
      相关资源
      最近更新 更多