Ejemplo: Obtener datos WMI del equipo local de forma asincrónica
Puede usar el procedimiento y los ejemplos de código de este tema para crear una aplicación cliente WMI completa que realice la inicialización COM, se conecte a WMI en el equipo local, obtenga datos de forma asincrónica y, a continuación, realice la limpieza. En este ejemplo se obtiene el nombre del sistema operativo en el equipo local y se muestra.
El siguiente procedimiento se usa para ejecutar la aplicación WMI. Los pasos del 1 al 5 contienen todos los pasos necesarios para configurar y conectarse a WMI, y los pasos 6 y siete son donde se recupera el nombre del sistema operativo de forma asincrónica.
Para obtener datos WMI del equipo local de forma asincrónica
Inicialice parámetros COM con una llamada a CoInitializeEx.
Para obtener más información, consulte Inicializar COM para una aplicación WMI.
Inicialice la seguridad del proceso COM mediante una llamada a CoInitializeSecurity.
Para obtener más información, consulte Establecimiento del nivel de seguridad de proceso predeterminado mediante C++.
Obtenga el localizador inicial de WMI mediante una llamada a CoCreateInstance.
Para obtener más información, consulte Crear una conexión a un espacio de nombres WMI.
Obtenga un puntero a IWbemServices para el espacio de nombres root\cimv2 en el equipo local llamando a IWbemLocator::ConnectServer. Para conectarse a un equipo remoto, consulte Ejemplo: Obtener datos WMI desde un equipo remoto.
Para obtener más información, consulte Crear una conexión a un espacio de nombres WMI.
Establezca la seguridad del proxy IWbemServices para que el servicio WMI pueda suplantar al cliente llamando a CoSetProxyBlanket.
Para obtener más información, consulte Establecer los niveles de seguridad en una conexión WMI.
Use el puntero IWbemServices para realizar solicitudes a WMI. En este ejemplo se usa el método IWbemServices::ExecQueryAsync para recibir los datos de forma asincrónica. Cuando reciba datos de manera asincrónica, debe proporcionar una implementación de IWbemObjectSink. En este ejemplo se proporciona la implementación en la clase QuerySink. El código de implementación y el código de archivo de encabezado de esta clase se proporcionan tras el ejemplo principal. El método IWbemServices::ExecQueryAsync llama al método QuerySink::Indicate cada vez que se reciben los datos.
Para obtener más información sobre cómo crear una solicitud a WMI, consulte Manipular información de clase e instancia y Llamar a un método.
Espere a que los datos se recuperen de forma asincrónica. Use el método IWbemServices::CancelAsyncCall para detener manualmente la llamada asincrónica.
En el ejemplo de código siguiente se obtienen datos WMI del equipo local de forma asincrónica.
#include "querysink.h"
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL); // Reserved
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE); // proxy capabilities
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system.
// The IWbemService::ExecQueryAsync method will call
// the QuerySink::Indicate method when it receives a result
// and the QuerySink::Indicate method will display the OS name
QuerySink* pResponseSink = new QuerySink();
pResponseSink->AddRef();
hres = pSvc->ExecQueryAsync(bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_OperatingSystem"),
WBEM_FLAG_BIDIRECTIONAL,
NULL,
pResponseSink);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
pResponseSink->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Wait to get the data from the query in step 6 -----------
Sleep(500);
pSvc->CancelAsyncCall(pResponseSink);
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
El siguiente archivo de encabezado se usa para la clase QuerySink. La clase QuerySink se usa en el ejemplo de código anterior.
// QuerySink.h
#ifndef QUERYSINK_H
#define QUERYSINK_H
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
class QuerySink : public IWbemObjectSink
{
LONG m_lRef;
bool bDone;
CRITICAL_SECTION threadLock; // for thread safety
public:
QuerySink() { m_lRef = 0; bDone = false;
InitializeCriticalSection(&threadLock); }
~QuerySink() { bDone = true;
DeleteCriticalSection(&threadLock); }
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void** ppv);
virtual HRESULT STDMETHODCALLTYPE Indicate(
LONG lObjectCount,
IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
);
virtual HRESULT STDMETHODCALLTYPE SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
);
bool IsDone();
};
#endif // end of QuerySink.h
El siguiente ejemplo de código es una implementación de la clase QuerySink.
// QuerySink.cpp
#include "querysink.h"
ULONG QuerySink::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG QuerySink::Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
HRESULT QuerySink::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
{
*ppv = (IWbemObjectSink *) this;
AddRef();
return WBEM_S_NO_ERROR;
}
else return E_NOINTERFACE;
}
HRESULT QuerySink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hres = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
VARIANT varName;
hres = apObjArray[i]->Get(_bstr_t(L"Name"),
0, &varName, 0, 0);
if (FAILED(hres))
{
cout << "Failed to get the data from the query"
<< " Error code = 0x"
<< hex << hres << endl;
return WBEM_E_FAILED; // Program has failed.
}
printf("Name: %ls\n", V_BSTR(&varName));
}
return WBEM_S_NO_ERROR;
}
HRESULT QuerySink::SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
if(lFlags == WBEM_STATUS_COMPLETE)
{
printf("Call complete.\n");
EnterCriticalSection(&threadLock);
bDone = true;
LeaveCriticalSection(&threadLock);
}
else if(lFlags == WBEM_STATUS_PROGRESS)
{
printf("Call in progress.\n");
}
return WBEM_S_NO_ERROR;
}
bool QuerySink::IsDone()
{
bool done = true;
EnterCriticalSection(&threadLock);
done = bDone;
LeaveCriticalSection(&threadLock);
return done;
} // end of QuerySink.cpp