例: リモート コンピューターから WMI データを取得する
このトピックの手順とコード例を使用すると、COM の初期化を実行し、リモート コンピューター上の WMI に接続して半同期的にデータを取得したうえでクリーンアップする、完全な WMI クライアント アプリケーションを作成できます。 ローカル コンピューターからデータを取得する方法の詳細については、「例: ローカル コンピューターから WMI データを取得する」を参照してください。 非同期的にデータを取得する方法の詳細については、「例: ローカル コンピューターから WMI データを非同期的に取得する」を参照してください。
Note
リモート コンピュータに接続しようとしている場合は、「WMI へのリモート接続」の情報を参照してください。
次の手順は、WMI アプリケーションを実行する方法を示しています。 手順 1 から 5 には、WMI のセットアップと接続に必要な手順がすべて含まれています。手順 6 と 7 では、データのクエリの実行と受信について確認できます。
リモート コンピューターから WMI データを取得するには
CoInitializeEx の呼び出しで COM パラメーターを初期化します。
詳細については、「WMI アプリケーション用 COM の初期化」を参照してください。
CoInitializeSecurity を呼び出して COM プロセスのセキュリティを初期化します。
詳細については、「C++ を使用した既定のプロセスのセキュリティ レベルの設定」を参照してください。
CoCreateInstance を呼び出して、WMI への初期ロケーターを取得します。
詳細については、「WMI 名前空間への接続の作成」を参照してください。
リモート コンピューターで \\root\cimv2 名前空間の IWbemServices へのポインターを取得するには、IWbemLocator::ConnectServer を呼び出します。 リモート コンピューターに接続するときは、接続先のリモート コンピューターのコンピューター名、ドメイン、ユーザー名、パスワードを知っている必要があります。 これらの属性はすべて、 IWbemLocator::ConnectServer メソッドに渡されます。 また、リモート コンピューターに接続しようとしているコンピューターのユーザー名に、リモート コンピューターへの正しいアクセス特権が設定されていることを確認します。 詳細については、「Windows ファイアウォール経由の接続」を参照してください。 ローカル コンピューターに接続するには、「例: ローカル コンピューターから WMI データを取得する」および「WMI 名前空間への接続の作成」を参照してください。
ユーザー名とパスワードを処理するときは、ユーザーに情報の入力を求め、情報を使用したら情報を削除することをお勧めします。そうすることで、承認されていないユーザーによる情報傍受の可能性が低くなります。 次のコード例の手順 4 では、 CredUIPromptForCredentials を使用してユーザー名とパスワードを取得し、 IWbemLocator::ConnectServerで使用した後、 SecureZeroMemory を使用して情報を削除します。 詳細については、「パスワードの処理」および「ユーザーに資格情報を要求する」を参照してください。
プロキシ セキュリティを設定するために資格情報を提供する COAUTHIDENTITY 構造体を作成します。
IWbemServices プロキシ セキュリティを設定して、WMI サービスが CoSetProxyBlanket を呼び出すことでクライアントを偽装できるようにします。
詳細については、「WMI 接続にセキュリティ レベルを設定する」を参照してください。
WMI の要求を行うには、 IWbemServices ポインターを使用します。 IWbemServices::ExecQuery を呼び出すことによって、オペレーティング システムの名前と空き物理メモリ量を取得するために、クエリが実行されます。
次の WQL クエリは、メソッド引数の 1 つです。
SELECT * FROM Win32_OperatingSystem
このクエリの結果は、 IEnumWbemClassObject ポインターに格納されます。 これにより、IEnumWbemClassObject インターフェイスを使用して、クエリからデータ オブジェクトを半同期的に取得できます。 詳細については、「WMI の列挙」を参照してください。 データを非同期的に取得する方法については、「例: ローカル コンピューターから WMI データを非同期的に取得する」を参照してください。
WMI の要求の詳細については、「クラスとインスタンス情報の操作」、「WMI のクエリ」、および「メソッドの呼び出し」を参照してください。
IEnumWbemClassObject 列挙子のプロキシ セキュリティを設定します。 資格情報の使用が完了したら、必ずメモリから資格情報を消去してください。
詳細については、「IWbemServices およびその他のプロキシにセキュリティを設定する」を参照してください。
WQL クエリからデータを取得して表示します。 IEnumWbemClassObject ポインターはクエリが返したデータ オブジェクトにリンクされ、データ オブジェクトは IEnumWbemClassObject::Next メソッドを使用して取得できます。 このメソッドは、メソッドに渡される IWbemClassObject ポインターにデータ オブジェクトをリンクします。 IWbemClassObject::Get メソッドを使用して、データ オブジェクトから必要な情報を取得します。
次のコード例は、オペレーティング システムの名前を提供するデータ オブジェクトから
Name
プロパティを取得するために使用されます。VARIANT vtProp; // Get the value of the Name property hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); wcout << " OS Name : " << vtProp.bstrVal << endl;
Name
プロパティの値が VARIANT 変数vtProp
に格納されると、ユーザーに表示できるようになります。次のコード例は、 VARIANT 変数を再び使用して、空き物理メモリ量の値を格納して表示する方法を示します。
hr = pclsObj->Get(L"FreePhysicalMemory", 0, &vtProp, 0, 0); wcout << " Free physical memory (in kilobytes): " << vtProp.uintVal << endl;
詳細については、「WMI の列挙」を参照してください。
次のコード例は、リモート コンピューターから WMI データを半同期的に取得する方法を示します。
#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.
}