【问题标题】:COM Initialization and Use in Win32 C++ DLLCOM初始化及在Win32 C++ DLL中的使用
【发布时间】:2011-05-26 05:47:05
【问题描述】:

我正在编写一个使用 COM 查询 WMI 的 Win32 C++ DLL。如何以编程方式确定 COM 是否已经初始化?谢谢。

【问题讨论】:

    标签: c++ visual-studio-2008 dll com


    【解决方案1】:

    Mark Ransom 是对的
    直接、干净和简单的解决方案是要求调用者进行 COM 初始化。

    丑陋的黑客攻击
    你可以尝试你的第一个电话——可能是CoCreateInstance,如果它返回CO_E_NOTINITIALIZED,你自己运行CoInitialize(在这种情况下不要忘记取消初始化)

    然而,将 CoInitialize 从 DLL “注入”到调用者线程中仍然存在问题。所以有一个

    清洁解决方案
    让 DLL 创建一个工作线程(这意味着 DLL 需要 Init 和 Teardown 调用),在这个线程中自己创建 CoInitializeEx,并将所有 COM 调用移动到那个单独的线程。

    【讨论】:

    • 谢谢,我最终使用了工作线程。初始化和拆卸都在同一个 DLL 函数中完成。 WaitForSingleObject 用于等待工作线程完成。
    【解决方案2】:

    最简单的方法是不要打扰,只要让任何使用您的 DLL 的人都要求他们首先初始化 COM。否则,如果他们你之后执行它,你就有可能搞乱他们自己的初始化。

    另一方面,如果CoInitializeEx 的标志与应用程序的标志匹配,则应该没问题。来自CoInitializeEx documentation

    多次调用 CoInitializeEx 只要允许相同的线程 它们传递相同的并发标志, 但随后的有效调用返回 S_FALSE。

    【讨论】:

    • 这真的没有帮助。不幸的是,大部分应用程序已经编写好了。我需要知道如何确定 COM 是否已经初始化。我意识到这不是最佳做法,但它是必须使用的。
    • @Jim:这是正确的。在您的代码中始终只使用一次 CoInitializeEx() 和恰好一次 CoUninitialize() 。如果它已经在你的线程中被调用,它并不重要。除此之外,您无法控制您控制的代码何时取消初始化 COM,因此依赖启动时的初始化状态是危险的。
    • +1,另请参阅:stackoverflow.com/q/2154151/57428 - 看起来像调用CoInitialize() 一次会导致一些奇怪的问题。
    【解决方案3】:

    它遵循 peterchen clean 解决方案,因为我将它编码为我想要包装的线程安全 COM 记录器组件:

    IComLoggerPtr _logger;
    _bstr_t _name;
    HANDLE _thread;
    HANDLE _completed;
    
    Logger::Logger(_bstr_t name)
    {
        _name = name;
    
        _completed = ::CreateEvent(NULL, false, false, NULL);
        if (_completed == NULL)
            ::AtlThrowLastWin32();
    
        // Launch the thread for COM interation
        DWORD threadId;
        _thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(this->threadRun),
            (LPVOID)this, 0, &threadId);
    
        // Wait object initialization
        HRESULT hr = ::WaitForSingleObject(_completed, INFINITE);
        if (FAILED(hr))
            AtlThrow(hr);
    }
    
    Logger::~Logger()
    {
        ::SetEvent(_completed);
        CloseHandle(_thread);
        CloseHandle(_completed);
    }
    
    DWORD WINAPI Logger::threadRun(LPVOID opaque)
    {
        Logger *obj = (Logger *)opaque;
    
        // Init Free-Threaded COM subsystem
        HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if (FAILED(hr))
            ::AtlThrow(hr);
    
        hr = obj->_logger.CreateInstance(__uuidof(ComLogger));
        if (FAILED(hr))
            ::AtlThrow(hr);
    
        obj->_logger->Init(obj->_name);
    
        // Initialization completed
        bool success = ::SetEvent(obj->_completed);
        if (!success)
            ::AtlThrowLastWin32();
    
        // Wait release event
        hr = ::WaitForSingleObject(obj->_completed, INFINITE);
        if (FAILED(hr))
            AtlThrow(hr);
    
        obj->_logger.Release();
    
        // Release COM subsystem
        ::CoUninitialize();
    }
    
    HRESULT Logger::Log(_bstr_t description)
    {
        return _logger->Log(description);
    }
    

    【讨论】:

      【解决方案4】:

      CoInitializeEx\CoUninitialize 只能由线程调用(而不是由 Dll 调用)。

      顺便说一句,你不应该在 DllMain 中使用 CoInitializeEx\CoUninitialize !

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-02
        • 2016-04-20
        • 2011-05-05
        • 1970-01-01
        • 2012-01-27
        • 2015-09-10
        • 1970-01-01
        • 2010-09-25
        相关资源
        最近更新 更多