studio - visual c++ 2008 redistributable 64
Inicialización COM y uso en Win32 C++ DLL (4)
CoInitializeEx / CoUninitialize solo debe invocarse mediante subprocesos (no mediante llamadas Dll).
Por cierto, no deberías usar CoInitializeEx / CoUninitialize en DllMain.
Estoy escribiendo una DLL Win32 C ++ que utiliza el COM para consultar WMI. ¿Cómo puedo determinar mediante programación si COM ya se ha inicializado? Gracias.
La manera más fácil es no molestarse, simplemente haga que un requisito de cualquier persona que use su DLL inicialice COM primero. De lo contrario, se corre el riesgo de arruinar su propia inicialización si la realizan después de la suya.
Por otro lado, si sus banderas para CoInitializeEx
coinciden con las de la aplicación, debería estar bien. De la documentación de CoInitializeEx
:
Se permiten múltiples llamadas a CoInitializeEx por el mismo hilo siempre que pasen el mismo indicador de concurrencia, pero las llamadas válidas posteriores devuelven S_FALSE.
Mark Ransom tiene razón
la solución sencilla, limpia y simple es requerir la inicialización de COM por parte de la persona que llama.
Ugly hack
Puede intentar su primera llamada, probablemente CoCreateInstance
, y si devuelve CO_E_NOTINITIALIZED, ejecute CoInitialize
usted mismo (y no olvide desasignar en ese caso)
Sin embargo , sigue siendo problemático "inyectar" un CoInitialize en un hilo que llama desde un archivo DLL. Entonces hay un
Solución limpia
Deje que el archivo DLL cree un hilo de trabajo (lo que significa que el archivo DLL necesita iniciar y desmantelar llamadas), CoInitializeEx en este hilo usted mismo, y mueva todas las llamadas COM a ese hilo separado.
Sigue la solución de peterchen clean ya que lo codifiqué para un componente COM logger seguro para subprocesos que quería envolver:
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);
}