Esempio: recupero di dati WMI da un computer remoto
È possibile utilizzare la procedura e gli esempi di codice in questo argomento per creare un'applicazione client WMI completa che esegue l'inizializzazione COM, connettersi a WMI in un computer remoto, ottenere i dati in modo semisincrono e quindi eseguire la pulizia. Per altre informazioni su come ottenere dati dal computer locale, vedere Esempio: Recupero di dati WMI dal computer locale. Per altre informazioni su come ottenere i dati in modo asincrono, vedere Esempio: Recupero di dati WMI dal computer locale in modo asincrono.
Nota
Se si sta tentando di connettersi a un computer remoto, vedere le informazioni in Connessione a WMI in remoto.
La procedura seguente illustra come eseguire l'applicazione WMI. I passaggi da 1 a 5 contengono tutti i passaggi necessari per configurare e connettersi a WMI e i passaggi 6 e 7 sono la posizione in cui i dati vengono sottoposti a query e ricevuti.
Per ottenere dati WMI da un computer remoto
Inizializzare i parametri COM con una chiamata a CoInitializeEx.
Per altre informazioni, vedere Inizializzazione di COM per un'applicazione WMI.
Inizializzare la sicurezza del processo COM chiamando CoInitializeSecurity.
Per altre informazioni, vedere Impostazione del livello di sicurezza del processo predefinito con C++.
Ottenere il localizzatore iniziale in WMI chiamando CoCreateInstance.
Per altre informazioni, vedere Creazione di una connessione a uno spazio dei nomi WMI.
Ottenere un puntatore a IWbemServices per lo spazio dei nomi \\root\cimv2 in un computer remoto chiamando IWbemLocator::ConnectServer. Quando ci si connette a un computer remoto, è necessario conoscere il nome del computer, il dominio, il nome utente e la password del computer remoto a cui ci si connette. Questi attributi vengono tutti passati al metodo IWbemLocator::ConnectServer . Assicurarsi inoltre che il nome utente nel computer che sta tentando di connettersi al computer remoto disponga dei privilegi di accesso corretti nel computer remoto. Per altre informazioni, vedere Connessione tramite Windows Firewall. Per connettersi al computer locale, vedere Esempio: Recupero di dati WMI dal computer locale e Creazione di una connessione a uno spazio dei nomi WMI.
Quando si gestiscono nomi utente e password, è consigliabile richiedere all'utente di immettere le informazioni, usare le informazioni e quindi eliminare le informazioni, in modo che vi sia meno possibilità di intercettare le informazioni da parte di un utente non autorizzato. Il passaggio 4 nel codice di esempio seguente usa CredUIPromptForCredentials per ottenere il nome utente e la password e quindi usa SecureZeroMemory per eliminare le informazioni dopo l'uso in IWbemLocator::ConnectServer. Per altre informazioni, vedere Gestione delle password e richiesta dell'utente per le credenziali.
Creare una struttura COAUTHIDENTITY per fornire le credenziali per l'impostazione della sicurezza del proxy.
Impostare la sicurezza proxy IWbemServices in modo che il servizio WMI possa rappresentare il client chiamando CoSetProxyBlanket.
Per altre informazioni, vedere Impostazione dei livelli di sicurezza in una connessione WMI.
Usare il puntatore IWbemServices per effettuare richieste di WMI. Viene eseguita una query per ottenere il nome del sistema operativo e la quantità di memoria fisica libera chiamando IWbemServices::ExecQuery.
La query WQL seguente è uno degli argomenti del metodo .
SELECT * FROM Win32_OperatingSystem
Il risultato di questa query viene archiviato in un puntatore IEnumWbemClassObject. In questo modo, gli oggetti dati della query possono essere recuperati in modo semisincrono con l'interfaccia IEnumWbemClassObject . Per altre informazioni, vedere Enumerazione WMI. Per ottenere i dati in modo asincrono, vedere Esempio: Recupero di dati WMI dal computer locale in modo asincrono.
Per altre informazioni sull'esecuzione di richieste di WMI, vedere Manipolazione di informazioni sulle classi e sull'istanza, esecuzione di query su WMI e chiamata di un metodo.
Impostare la sicurezza proxy dell'enumeratore IEnumWbemClassObject. Assicurarsi di cancellare le credenziali dalla memoria al termine dell'uso.
Per altre informazioni, vedere Impostazione della sicurezza in IWbemServices e altri proxy.
Ottenere e visualizzare i dati dalla query WQL. Il puntatore IEnumWbemClassObject è collegato agli oggetti dati restituiti dalla query e gli oggetti dati possono essere recuperati con il metodo IEnumWbemClassObject::Next. Questo metodo collega gli oggetti dati a un puntatore IWbemClassObject passato al metodo . Usare il metodo IWbemClassObject::Get per ottenere le informazioni desiderate dagli oggetti dati.
L'esempio di codice seguente viene usato per ottenere la
Name
proprietà dall'oggetto dati, che fornisce il nome del sistema operativo.VARIANT vtProp; // Get the value of the Name property hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); wcout << " OS Name : " << vtProp.bstrVal << endl;
Dopo aver archiviato il valore della
Name
proprietà nella variabilevtProp
VARIANT, può essere visualizzato all'utente.Nell'esempio di codice seguente viene illustrato come usare nuovamente la variabile VARIANT per archiviare e visualizzare il valore della quantità di memoria fisica libera.
hr = pclsObj->Get(L"FreePhysicalMemory", 0, &vtProp, 0, 0); wcout << " Free physical memory (in kilobytes): " << vtProp.uintVal << endl;
Per altre informazioni, vedere Enumerazione WMI.
Nell'esempio di codice seguente viene illustrato come ottenere i dati WMI in modo semisincrono da un computer remoto.
#define _WIN32_DCOM
#define UNICODE
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "credui.lib")
#pragma comment(lib, "comsuppw.lib")
#include <wincred.h>
#include <strsafe.h>
int __cdecl 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_IDENTIFY, // 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;
// Get the user name and password for the remote computer
CREDUI_INFO cui;
bool useToken = false;
bool useNTLM = true;
wchar_t pszName[CREDUI_MAX_USERNAME_LENGTH+1] = {0};
wchar_t pszPwd[CREDUI_MAX_PASSWORD_LENGTH+1] = {0};
wchar_t pszDomain[CREDUI_MAX_USERNAME_LENGTH+1];
wchar_t pszUserName[CREDUI_MAX_USERNAME_LENGTH+1];
wchar_t pszAuthority[CREDUI_MAX_USERNAME_LENGTH+1];
BOOL fSave;
DWORD dwErr;
memset(&cui,0,sizeof(CREDUI_INFO));
cui.cbSize = sizeof(CREDUI_INFO);
cui.hwndParent = NULL;
// Ensure that MessageText and CaptionText identify
// what credentials to use and which application requires them.
cui.pszMessageText = TEXT("Press cancel to use process token");
cui.pszCaptionText = TEXT("Enter Account Information");
cui.hbmBanner = NULL;
fSave = FALSE;
dwErr = CredUIPromptForCredentials(
&cui, // CREDUI_INFO structure
TEXT(""), // Target for credentials
NULL, // Reserved
0, // Reason
pszName, // User name
CREDUI_MAX_USERNAME_LENGTH+1, // Max number for user name
pszPwd, // Password
CREDUI_MAX_PASSWORD_LENGTH+1, // Max number for password
&fSave, // State of save check box
CREDUI_FLAGS_GENERIC_CREDENTIALS |// flags
CREDUI_FLAGS_ALWAYS_SHOW_UI |
CREDUI_FLAGS_DO_NOT_PERSIST);
if(dwErr == ERROR_CANCELLED)
{
useToken = true;
}
else if (dwErr)
{
cout << "Did not get credentials " << dwErr << endl;
pLoc->Release();
CoUninitialize();
return 1;
}
// change the computerName strings below to the full computer name
// of the remote computer
if(!useNTLM)
{
StringCchPrintf(pszAuthority, CREDUI_MAX_USERNAME_LENGTH+1, L"kERBEROS:%s", L"COMPUTERNAME");
}
// Connect to the remote root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
//---------------------------------------------------------
hres = pLoc->ConnectServer(
_bstr_t(L"\\\\COMPUTERNAME\\root\\cimv2"),
_bstr_t(useToken?NULL:pszName), // User name
_bstr_t(useToken?NULL:pszPwd), // User password
NULL, // Locale
NULL, // Security flags
_bstr_t(useNTLM?NULL:pszAuthority),// Authority
NULL, // Context object
&pSvc // IWbemServices proxy
);
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: --------------------------------------------------
// Create COAUTHIDENTITY that can be used for setting security on proxy
COAUTHIDENTITY *userAcct = NULL ;
COAUTHIDENTITY authIdent;
if( !useToken )
{
memset(&authIdent, 0, sizeof(COAUTHIDENTITY));
authIdent.PasswordLength = wcslen (pszPwd);
authIdent.Password = (USHORT*)pszPwd;
LPWSTR slash = wcschr (pszName, L'\\');
if( slash == NULL )
{
cout << "Could not create Auth identity. No domain specified\n" ;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
StringCchCopy(pszUserName, CREDUI_MAX_USERNAME_LENGTH+1, slash+1);
authIdent.User = (USHORT*)pszUserName;
authIdent.UserLength = wcslen(pszUserName);
StringCchCopyN(pszDomain, CREDUI_MAX_USERNAME_LENGTH+1, pszName, slash - pszName);
authIdent.Domain = (USHORT*)pszDomain;
authIdent.DomainLength = slash - pszName;
authIdent.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
userAcct = &authIdent;
}
// Step 6: --------------------------------------------------
// Set security levels on a WMI connection ------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_DEFAULT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_xxx
COLE_DEFAULT_PRINCIPAL, // Server principal name
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
userAcct, // 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 7: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("Select * from Win32_OperatingSystem"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 8: -------------------------------------------------
// Secure the enumerator proxy
hres = CoSetProxyBlanket(
pEnumerator, // Indicates the proxy to set
RPC_C_AUTHN_DEFAULT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_xxx
COLE_DEFAULT_PRINCIPAL, // Server principal name
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
userAcct, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket on enumerator. Error code = 0x"
<< hex << hres << endl;
pEnumerator->Release();
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// When you have finished using the credentials,
// erase them from memory.
SecureZeroMemory(pszName, sizeof(pszName));
SecureZeroMemory(pszPwd, sizeof(pszPwd));
SecureZeroMemory(pszUserName, sizeof(pszUserName));
SecureZeroMemory(pszDomain, sizeof(pszDomain));
// Step 9: -------------------------------------------------
// Get the data from the query in step 7 -------------------
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
wcout << " OS Name : " << vtProp.bstrVal << endl;
// Get the value of the FreePhysicalMemory property
hr = pclsObj->Get(L"FreePhysicalMemory",
0, &vtProp, 0, 0);
wcout << " Free physical memory (in kilobytes): "
<< vtProp.uintVal << endl;
VariantClear(&vtProp);
pclsObj->Release();
pclsObj = NULL;
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
if( pclsObj )
{
pclsObj->Release();
}
CoUninitialize();
return 0; // Program successfully completed.
}