예제: 원격 컴퓨터 WMI 데이터 수집
이 글에서 설명하는 절차 및 코드 예제를 사용하면 COM 초기화를 수행하고, 원격 컴퓨터의 WMI에 연결하고, 반동기적으로 데이터를 가져온 다음 정리하는 완전한 WMI 클라이언트 응용 프로그램을 만들 수 있습니다.
로컬 컴퓨터에서 데이터를 가져오는 방법에 대한 자세한 내용은 예: 로컬 컴퓨터에서 WMI 데이터 수집하기를 참조하십시오.
데이터를 비동기적으로 가져오는 방법에 대한 자세한 내용은 예: 로컬 컴퓨터에서 비동기적으로 WMI 데이터 수집하기를 참조하세요.
주의
원격 컴퓨터에 연결하려는 경우 원격으로 WMI에 연결에 대한 정보를 참조하십시오.
https://learn.microsoft.com/en-us/windows/win32/wmisdk/connecting-to-wmi-remotely-starting-with-vista
다음 절차는 WMI 응용 프로그램을 실행하는 방법을 보여줍니다. 1~5단계에는 WMI를 설정하고 연결하는 데 필요한 모든 절차들을 포함하고 있으며 6~7단계에서는 데이터를 쿼리하고 수신합니다.
원격 컴퓨터에서 WMI 데이터를 가져오려면
1. CoInitializeEx를 호출하여 COM 매개변수를 초기화합니다.
자세한 내용은 WMI 응용 프로그램용 COM 초기화를 참조하십시오.
2, CoInitializeSecurity를 호출하여 COM 프로세스 보안을 초기화합니다.
자세한 내용은 C++를 사용하여 기본 프로세스 보안 수준 설정을 참조하십시오.
3. CoCreateInstance를 호출하여 WMI에 대한 초기 로케이터를 얻습니다.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
4. IWbemLocator::ConnectServer를 호출하여 로컬 컴퓨터의 root\cimv2 네임스페이스에 대한 IWbemServices에 대한 포인터를 가져옵니다.
원격 컴퓨터에 연결할 때 연결하려는 원격 컴퓨터의 컴퓨터 이름, 도메인, 사용자 이름 및 암호를 알아야 합니다. 이러한 특성은 모두 IWbemLocator::ConnectServer 메서드로 전달 합니다.
또한 원격 컴퓨터에 연결하려는 컴퓨터의 사용자 이름에 원격 컴퓨터에 대한 올바른 액세스 권한이 있는지 확인하십시오.
자세한 내용은 Windows 방화벽을 통해 연결을 참조하십시오.
로컬 컴퓨터에 연결하려면 예: 로컬 컴퓨터에서 WMI 데이터 가져오기 와 WMI 네임스페이스에 대한 연결 만들기를 참조하십시오.
사용자 이름과 암호를 처리할 때 권한이 없는 사용자가 정보를 가로챌 가능성을 줄이기 위해 사용자에게 정보를 입력하라는 메시지를 표시해주고 해당 정보를 사용한 다음 정보를 삭제하는 것이 좋습니다.
아래 예제 코드의 4단계는 CredUIPromptForCredentials를 사용하여 사용자 이름과 암호를 가져온 다음 SecureZeroMemory를 사용하여 IWbemLocator::ConnectServer에서 사용된 정보를 제거합니다.
자세한 내용은 MSDN에서 암호 처리 및 사용자에게 자격 증명 요청을 참조하십시오.
5. COAUTHIDENTITY 구조를 생성하여 프록시 보안 설정을 위한 자격 증명을 제공합니다.
6. WMI 서비스가 CoSetProxyBlanket을 호출하여 클라이언트를 가장(impersonate)할 수 있도록 IWbemServices 프록시 보안을 설정합니다.
자세한 내용은 WMI 연결에 대한 보안 수준 설정을 참조하십시오.
7. CoInitializeEx를 호출하여 COM 매개변수를 초기화합니다.
IWbemServices 포인터를 사용하여 WMI를 요청합니다. IWbemServices::ExecQuery를 호출하여 운영 체제의 이름과 사용 가능한 실제 메모리 양을 얻기 위해 쿼리가 실행됩니다.
다음 WQL 쿼리는 메서드 인수 중 하나입니다.
SELECT * FROM Win32_OperatingSystem
이이 쿼리의 결과는 IEnumWbemClassObject 포인터에 저장됩니다.
이렇게 하면 쿼리의 데이터 개체를 IEnumWbemClassObject 인터페이스로 반동기적으로 검색할 수 있습니다.
자세한 내용은 WMI 열거를 참조하세요. 데이터를 비동기적으로 가져오려면 예: 로컬 컴퓨터에서 비동기적으로 WMI 데이터 가져오기를 참조하십시오.
WMI 요청에 대한 자세한 내용은 클래스 및 인스턴스 정보 조작, WMI 쿼리 및 메서드 호출을 참조하십시오.
8. IEnumWbemClassObject enumerator 프록시 보안을 설정합니다. 자격 증명을 사용한 후에는 메모리에서 자격 증명을 지워야 합니다.
자세한 내용은 IWbemServices 및 기타 프록시에 대한 보안 설정을 참조하십시오.
9. 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 데이터를 가져오는 방법을 보여줍니다.
#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.
}
예제: 프로바이더 메서드 호출하기
이 글의 프로그래밍 절차 및 예제 코드를 사용해서 COM 초기화를 수행하고, 로컬 컴퓨터의 WMI에 연결하고, 반동기적으로 데이터를 검색한 다음 정리하는 완전한 WMI 클라이언트 응용 프로그램을 만들 수 있습니다.
Win32_Process::Create 메서드는 새로운 프로세스로 Notepad.exe를 실행 하는 데 사용됩니다.
다음 절차는 WMI 응용 프로그램을 실행하는 데 사용됩니다.
1~5단계에는 WMI를 설정하고 연결하는 데 필요한 모든 단계가 포함되어 있으며 6단계에서는 프로바이더 메서드가 호출됩니다.
프로바이더 메서드를 호출하려면
1. CoInitializeEx를 호출하여 COM 매개변수를 초기화합니다.
자세한 내용은 WMI 응용 프로그램용 COM 초기화를 참조하십시오.
2, CoInitializeSecurity를 호출하여 COM 프로세스 보안을 초기화합니다.
자세한 내용은 C++를 사용하여 기본 프로세스 보안 수준 설정을 참조하십시오.
3. CoCreateInstance를 호출하여 WMI에 대한 초기 로케이터를 얻습니다.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
4. IWbemLocator::ConnectServer를 호출하여 로컬 컴퓨터의 root\cimv2 네임스페이스에 대한 IWbemServices에 대한 포인터를 가져옵니다. 원격 컴퓨터에 연결하려면 예: 원격 컴퓨터에서 WMI 데이터 수집하기를 참조하십시오.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
5. WMI 서비스가 CoSetProxyBlanket을 호출하여 클라이언트를 가장(Impersonate) 할 수 있도록 IWbemServices 프록시 보안을 설정합니다.
자세한 내용은 WMI 연결에 대한 보안 수준 설정을 참조하십시오.
6. IWbemServices 포인터를 사용하여 WMI에 요청합니다.
이 예제에서는 IWbemServices::ExecMethod를 사용하여 프로바이더 메서드 Win32_Process::Create를 호출합니다.
WMI 요청에 대한 자세한 내용은 클래스 및 인스턴스 정보 조작 및 메서드 호출을 참조하십시오.
프로바이더 메서드에 입력 매개변수 또는 출력 매개변수가 있는 경우 매개변수 값을 IWbemClassObject 포인터에 지정해야 합니다.
입력 매개변수(in-parameters)의 경우 입력 매개변수(in-parameters) 인스턴스를 생성한 다음 이 새 인스턴스의 값을 설정해야 합니다.
Win32_Process::Create 메서드를 제대로 실행하려면 CommandLine 매개 변수에 대한 값이 필요합니다.
다음 코드 예제에서는 IWbemClassObject 포인터를 만들고 Win32_Process::Create의 매개변수(in-parameters) 인스턴스를 생성한 다음 CommandLine 매개 변수 값을 Notepad.exe로 설정합니다.
// Set up to call the Win32_Process::Create method
BSTR MethodName = SysAllocString(L"Create");
BSTR ClassName = SysAllocString(L"Win32_Process");
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Create the values for the in-parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in-parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
다음 코드 예제는 Win32_Process::Create 메서드 out-parameters가 IWbemClassObject 포인터에 제공되는 방식을 보여줍니다.
out-parameter 값은 IWbemClassObject::Get 메서드로 얻어지고 VARIANT 변수에 저장되어 해당 변수를 사용자에게 표시 할 수 있습니다.
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
NULL, pClassInstance, &pOutParams, NULL);
VARIANT varReturnValue;
hres = pOutParams->Get(_bstr_t(L"ReturnValue"), 0,
&varReturnValue, NULL, 0);
다음 코드 예제는 WMI를 사용하여 프로바이더 메서드를 호출하는 방법을 보여줍니다.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int iArgCnt, 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 negotiates service
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 for 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 ----
// set up to call the Win32_Process::Create method
BSTR MethodName = SysAllocString(L"Create");
BSTR ClassName = SysAllocString(L"Win32_Process");
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Create the values for the in parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
NULL, pClassInstance, &pOutParams, NULL);
if (FAILED(hres))
{
cout << "Could not execute method. Error code = 0x"
<< hex << hres << endl;
VariantClear(&varCommand);
SysFreeString(ClassName);
SysFreeString(MethodName);
pClass->Release();
pClassInstance->Release();
pInParamsDefinition->Release();
pOutParams->Release();
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// To see what the method returned,
// use the following code. The return value will
// be in &varReturnValue
VARIANT varReturnValue;
hres = pOutParams->Get(_bstr_t(L"ReturnValue"), 0,
&varReturnValue, NULL, 0);
// Clean up
//--------------------------
VariantClear(&varCommand);
VariantClear(&varReturnValue);
SysFreeString(ClassName);
SysFreeString(MethodName);
pClass->Release();
pClassInstance->Release();
pInParamsDefinition->Release();
pOutParams->Release();
pLoc->Release();
pSvc->Release();
CoUninitialize();
return 0;
}
예제: WMI 를 통한 이벤트 통지 수신하기
이 글의 절차 및 코드 예제를 사용하면 COM 초기화를 수행하고 로컬 컴퓨터의 WMI에 연결하고 이벤트 알림을 받은 다음 정리하는 WMI 클라이언트 응용 프로그램을 완성 할 수 있습니다.
이 예제에서는 새 프로세스가 생성될 때 사용자에게 이벤트를 알립니다. 이벤트는 비동기적으로 수신됩니다.
다음 절차는 WMI 응용 프로그램을 실행하는 데 사용됩니다.
1~5단계에는 WMI를 설정하고 연결하는 데 필요한 모든 단계가 포함되어 있으며 6단계에서는 이벤트 알림을 받습니다.
WMI를 통해 이벤트 알림을 받으려면
1. CoInitializeEx를 호출하여 COM 매개변수를 초기화합니다.
자세한 내용은 WMI 응용 프로그램용 COM 초기화를 참조하십시오.
2, CoInitializeSecurity를 호출하여 COM 프로세스 보안을 초기화합니다.
자세한 내용은 C++를 사용하여 기본 프로세스 보안 수준 설정을 참조하십시오.
3. CoCreateInstance를 호출하여 WMI에 대한 초기 로케이터를 얻습니다.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
4. IWbemLocator::ConnectServer를 호출하여 로컬 컴퓨터의 root\cimv2 네임스페이스에 대한 IWbemServices에 대한 포인터를 가져옵니다. 원격 컴퓨터에 연결하려면 예: 원격 컴퓨터에서 WMI 데이터 수집하기를 참조하십시오.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
5. WMI 서비스가 CoSetProxyBlanket을 호출하여 클라이언트를 가장(Impersonate) 할 수 있도록 IWbemServices 프록시 보안을 설정합니다.
자세한 내용은 WMI 연결에 대한 보안 수준 설정을 참조하십시오.
6. IWbemServices 포인터를 사용하여 WMI에 요청합니다.
이 예제에서는 IWbemServices::ExecNotificationQueryAsync 메서드를 사용하여 비동기 이벤트를 수신합니다. 비동기 이벤트를 받을 때 IWbemObjectSink 인터페이스를 구현 개발 해야 합니다.
이 예제는 EventSink 클래스에서 구현을 제공합니다.이 클래스의 구현 코드 및 헤더 파일 코드는 기본 예제 아래에 제공됩니다.
IWbemServices::ExecNotificationQueryAsync 메서드는 이벤트가 수신될 때마다 EventSink::Indicate 메서드를 호출합니다.
이 예제에서 EventSink::Indicate 메서드는 프로세스가 생성될 때마다 호출됩니다.
이 예제를 테스트하려면 코드를 실행하고 Notepad.exe와 같은 프로세스를 시작합니다.
이렇게 하면 이벤트 알림이 트리거됩니다.
WMI 요청에 대한 자세한 내용은 클래스 및 인스턴스 정보 조작 및 메서드 호출을 참조하십시오.
다음 예제 코드는 WMI를 통해 이벤트 알림을 받습니다.
#include "eventsink.h"
int main(int iArgCnt, 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 negotiates service
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: -------------------------------------------------
// Receive event notifications -----------------------------
// Use an unsecured apartment for security
IUnsecuredApartment* pUnsecApp = NULL;
hres = CoCreateInstance(CLSID_UnsecuredApartment, NULL,
CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment,
(void**)&pUnsecApp);
EventSink* pSink = new EventSink;
pSink->AddRef();
IUnknown* pStubUnk = NULL;
pUnsecApp->CreateObjectStub(pSink, &pStubUnk);
IWbemObjectSink* pStubSink = NULL;
pStubUnk->QueryInterface(IID_IWbemObjectSink,
(void **) &pStubSink);
// The ExecNotificationQueryAsync method will call
// The EventQuery::Indicate method when an event occurs
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * "
"FROM __InstanceCreationEvent WITHIN 1 "
"WHERE TargetInstance ISA 'Win32_Process'"),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
// Check for errors.
if (FAILED(hres))
{
printf("ExecNotificationQueryAsync failed "
"with = 0x%X\n", hres);
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 1;
}
// Wait for the event
Sleep(10000);
hres = pSvc->CancelAsyncCall(pStubSink);
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pUnsecApp->Release();
pStubUnk->Release();
pSink->Release();
pStubSink->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
다음 헤더 파일은 EventSink 클래스에 사용됩니다. EventSink 클래스는 이전 코드 예제에서 사용되었습니다.
// EventSink.h
#ifndef EVENTSINK_H
#define EVENTSINK_H
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
class EventSink : public IWbemObjectSink
{
LONG m_lRef;
bool bDone;
public:
EventSink() { m_lRef = 0; }
~EventSink() { bDone = true; }
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
);
};
#endif // end of EventSink.h
다음 예제 코드는 EventSink 클래스의 구현입니다.
// EventSink.cpp
#include "eventsink.h"
ULONG EventSink::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG EventSink::Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
HRESULT EventSink::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 EventSink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hres = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
printf("Event occurred\n");
}
return WBEM_S_NO_ERROR;
}
HRESULT EventSink::SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
if(lFlags == WBEM_STATUS_COMPLETE)
{
printf("Call complete. hResult = 0x%X\n", hResult);
}
else if(lFlags == WBEM_STATUS_PROGRESS)
{
printf("Call in progress.\n");
}
return WBEM_S_NO_ERROR;
} // end of EventSink.cpp
이상.
'프로그래밍' 카테고리의 다른 글
[C++]WMI 질의 만들기 - 1 (0) | 2023.02.12 |
---|---|
WMI C++ 응용프로그램 예제들 (0) | 2023.02.11 |
[C++] WMI - OS의 모든 것을 질의 해보기 (0) | 2023.02.07 |
[C#] 텍스트 파일 읽기 (0) | 2023.02.06 |
[C#.NET]여러가지 머신레벨의 시스템 정보 얻는 방법 (0) | 2023.02.05 |