簡體   English   中英

在Win32 C ++ DLL中進行COM初始化和使用

[英]COM Initialization and Use in Win32 C++ DLL

我正在編寫一個Win32 C ++ DLL,它使用COM來查詢WMI。 如何以編程方式確定COM是否已初始化? 謝謝。

Mark Ransom是對的
簡單,干凈和簡單的解決方案是要求調用者進行COM初始化。

丑陋的黑客
您可以嘗試第一次調用 - 可能是CoCreateInstance ,如果它返回CO_E_NOTINITIALIZED,請自行運行CoInitialize (在這種情況下不要忘記取消)

但是 ,將一個CoInitialize“注入”來自DLL的調用者線程仍然存在問題。 所以有一個

清潔解決方案
讓DLL創建一個工作線程(這意味着DLL需要Init和Teardown調用),自己在這個線程中使用CoInitializeEx,並將所有COM調用移動到該單獨的線程。

最簡單的方法是不要打擾,只需要讓任何使用你的DLL的人首先初始化COM。 否則,如果他們你的初始化之后執行它你就有可能弄亂他們自己的初始化。

另一方面,如果您的CoInitializeEx標志與應用程序的標志匹配,那么您應該沒問題。 CoInitializeEx文檔

只要它們傳遞相同的並發標志,就允許同一個線程多次調用CoInitializeEx,但后續的有效調用返回S_FALSE。

它遵循peterchen清潔解決方案,因為我將其編碼為我想要包裝的線程安全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);
}

CoInitializeEx \\ CoUninitialize只應由線程調用(而不是由Dll調用)。

順便說一句,你不應該在DllMain中使用CoInitializeEx \\ CoUninitialize!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM