Ich schreibe eine Win32 C++ - DLL, die die COM verwendet, um WMI abzufragen. Wie kann ich programmgesteuert feststellen, ob COM bereits initialisiert wurde? Vielen Dank.COM Initialisierung und Verwendung in Win32 C++ DLL
Antwort
Mark Ransom ist richtig
die einfache, saubere und einfache Lösung ist der COM-Initialisierung durch den Anrufer zu verlangen.
hässliche Hack
Sie können Ihren ersten Anruf versuchen - wahrscheinlich CoCreateInstance
, und wenn es CO_E_NOTINITIALIZED zurückkehrt, laufen CoInitialize
selbst (und vergessen Sie nicht, in diesem Fall UNINIT)
jedoch, es ist immer noch problematisch, ein CoInitialize in einen Aufrufer Thread von einer DLL "injizieren". So gibt es eine
saubere Lösung
Lassen Sie die DLL einen Worker-Thread erstellen (was bedeutet, dass die DLL muss Init und Teardown Anrufe), CoInitializeEx in diesem Thread selbst, und verschieben Sie alle COM-Aufrufe in diesem separaten Thread.
Der einfachste Weg ist, nicht zu stören, machen Sie es nur eine Anforderung von jedermann mit Ihrer DLL, dass sie zuerst COM initialisieren. Sonst laufen Sie Gefahr, Ihre eigene Initialisierung zu verpfuschen, wenn sie es nach Ihres durchführen.
Auf der anderen Seite, wenn Ihre Flaggen zu CoInitializeEx
denen der Anwendung entsprechen, sollten Sie in Ordnung sein. Von den CoInitializeEx
documentation:
Mehrere Anrufe zu CoInitializeEx von das gleiche Gewinde erlaubt sind, solange sie die gleiche Parallelität Flag übergeben, aber nachfolgende gültige Anrufe zurückkehren S_FALSE.
Das ist wirklich nicht hilfreich. Leider ist der Großteil der Anwendung bereits geschrieben. Ich muss wissen, wie man bestimmt, ob das COM bereits initialisiert worden ist. Mir ist klar, dass dies keine Best Practice ist, aber es muss damit arbeiten. –
@ Jim: Das ist richtig. CoInitializeEx() immer genau einmal und CoUninitialize() genau einmal in deinem Code. Es ist nicht und sollte nicht wichtig sein, wenn es bereits in Ihrem Thread aufgerufen wurde. Darüber hinaus steuern Sie nicht, wann der Code, den Sie für die Abwärtssteuerung verwenden, COM aufheben wird. Daher ist es gefährlich, sich beim Start auf den Initialisierungsstatus zu verlassen. –
+1, Siehe auch: http://Stackoverflow.com/q/2154151/57428 - sieht so aus, als würde man 'CoInitialize()' mehr aufrufen, was zu einigen seltsamen Problemen führen kann. – sharptooth
CoInitializeEx \ CoUninitialize sollte nur von Threads (nicht von DLL-Aufrufe) aufgerufen werden.
BTW, sollten Sie nicht CoInitializeEx \ CoUninitialize in DllMain verwenden!
Es folgt peterchen saubere Lösung, wie ich es für einen Thread-sichere COM-Logger-Komponente codiert, die ich wickeln wollte:
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);
}
Danke, ich habe einen Worker Thread verwendet. Initialisierung und Abbau erfolgen alle in der gleichen DLL-Funktion. 'WaitForSingleObject' wird verwendet, um auf den Worker-Thread zu warten. –