Win32 C++ 中 COM 的初始化和使用DLL

发布于 2024-10-07 16:00:21 字数 69 浏览 2 评论 0原文

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

I am writing a Win32 C++ DLL that uses the COM to query WMI. How can I programmatically determine if COM has already been initialized? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

倾城°AllureLove 2024-10-14 16:00:21

马克·兰塞姆是对的
直接、干净且简单的解决方案是要求调用者初始化 COM。

丑陋的黑客
您可以尝试第一次调用 - 可能是 CoCreateInstance,如果它返回 CO_E_NOTINITIALIZED,请自行运行 CoInitialize(在这种情况下不要忘记取消初始化)

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

干净的解决方案
让 DLL 创建一个工作线程(这意味着 DLL 需要 Init 和 Teardown 调用),自己在该线程中进行 CoInitializeEx,并将所有 COM 调用移至该单独的线程。

Mark Ransom is right
the straightforward, clean and simple solution is to require COM initialization by the caller.

Ugly hack
You can try your first call - likely CoCreateInstance, and if it returns CO_E_NOTINITIALIZED, run CoInitialize yourself (and don't forget to uninit in that case)

However, it is still problematic to "inject" a CoInitialize into a caller thread from a DLL. So there's a

Clean Solution
Let the DLL create a worker thread (which means the DLL needs Init and Teardown calls), CoInitializeEx in this thread yourself, and move all the COM calls to that separate thread.

左耳近心 2024-10-14 16:00:21

最简单的方法就是不要打扰,只需要求任何使用您的 DLL 的人首先初始化 COM。否则,如果他们在您的初始化之后执行初始化,您将面临搞乱自己的初始化的风险。

另一方面,如果您的 CoInitializeEx 标记与应用程序的标记匹配,则应该没问题。来自 CoInitializeEx 文档< /a>:

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

The easiest way is not to bother, just make it a requirement of anybody using your DLL that they initialize COM first. Otherwise you run the risk of messing up their own initialization if they perform it after yours.

On the other hand if your flags to CoInitializeEx match those of the application, you should be fine. From the CoInitializeEx documentation:

Multiple calls to CoInitializeEx by
the same thread are allowed as long as
they pass the same concurrency flag,
but subsequent valid calls return
S_FALSE.

奶茶白久 2024-10-14 16:00:21

它遵循 @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);
}

It follows @peterchen clean solution as I coded it for a thread-safe COM logger component that I wanted to wrap:

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);
}
恍梦境° 2024-10-14 16:00:21

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

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

CoInitializeEx\CoUninitialize should only be called by threads (not by Dll-calls).

BTW ,you should not Use CoInitializeEx\CoUninitialize in DllMain !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文