Win32 C++动态链接库中COM的初始化及使用

p4tfgftt  于 2023-01-10  发布在  其他
关注(0)|答案(4)|浏览(181)

我正在写一个Win32 C++ DLL,它使用COM来查询WMI。我如何通过编程来确定COM是否已经初始化?谢谢。

4bbkushb

4bbkushb1#

"马克·兰塞姆说得对"
直接、干净和简单的解决方案是要求调用方进行COM初始化。
"丑陋的黑客"
您可以尝试第一次调用-可能是CoCreateInstance,如果它返回CO_E_NOTINITIALIZED,则自己运行CoInitialize(在这种情况下不要忘记取消初始化)

  • 但是 *,从DLL将CoInitialize“注入”到调用方线程中仍然存在问题。
    清洁溶液

让DLL创建一个辅助线程(这意味着DLL需要Init和Teardown调用),您自己在此线程中使用CoInitializeEx,并将所有COM调用移到该单独的线程。

wqsoz72f

wqsoz72f2#

最简单的方法是不麻烦,只要要求任何使用你的DLL的人先初始化COM。否则,如果他们在你的初始化之后执行,你就有可能搞砸他们自己的初始化。
另一方面,如果CoInitializeEx的标志与应用程序的标志相匹配,则应该没有问题。
允许同一线程多次调用CoInitializeEx,只要它们传递相同的并发标志即可,但后续有效调用返回S_FALSE。

lhcgjxsq

lhcgjxsq3#

它遵循@peterchen clean solution,因为我为一个线程安全的COM日志记录器组件编写了它,我想 Package 它:

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);
}
bxjv4tth

bxjv4tth4#

CoInitializeEx\CoUninitialize只能由线程调用(不能由Dll调用调用)。
顺便说一句,您不应该在DllMain中使用CoInitializeEx\CoUninitialize!

相关问题