이 섹션의 WMI 응용 프로그램 예제는 C++로 작성되었습니다.
WMI 구성 요소들을 이용해서 프로그래밍 할 수 있는 다양한 작업을 시연해보고 Visual Basic 스크립트 사용한 대안 프로그램에 대한 제안 합니다.
각 애플리케이션은 비슷한 코딩 방식으로 일련의 단계 마다 분리되어 있으며 서로 다른 예제의 코드 섹션을 쉽게 결합하여 맞춤형 애플리케이션을 만들 수 있습니다.
다음 표에는 이 섹션의 C++ 예제가 나열 해 보았습니다.
예제 설명
예제
|
설명
|
예: 로컬 컴퓨터에서 WMI 데이터 수집하기
|
이 예제는 로컬 컴퓨터의 WMI 네임스페이스에 연결하여 로컬 컴퓨터의 쿼리로부터 데이터를 수집합니다. 데이터는 반동기식으로 수집합니다.
|
예: 로컬 컴퓨터에서 비동기로 WMI 데이터 수집하기
|
이 예는 로컬 컴퓨터의 WMI 네임스페이스에 연결하여 로컬 컴퓨터에 쿼리 해서 데이터를 수집합니다. 데이터는 비동기식으로 수집됩니다.
|
예: 원격 컴퓨터에서 WMI 데이터 수집하기
|
이 예에서는 원격 컴퓨터의 WMI 네임스페이스에 연결하고 원격 컴퓨터를 질의하여 데이터를 가져옵니다. 데이터는 반동기식으로 수집됩니다.
|
예: 프로바이더 메서드 호출하기
|
이 예에서는 로컬 컴퓨터의 WMI 네임스페이스에 연결하여 WMI의 메서드를 호출합니다. 메서드는 동기식으로 실행됩니다.
|
예: WMI를 통해 이벤트 알림 받기
|
이 예에서는 로컬 컴퓨터의 WMI 네임스페이스에 연결하여 로컬 컴퓨터에서 이벤트를 받습니다. 이벤트는 반동기적으로 수신됩니다.
|
예: 로컬 컴퓨터에서 WMI 데이터 수집하기
이 글의 프로그래밍 절차 및 예제 코드를 사용해서 COM 초기화를 수행하고, 로컬 컴퓨터의 WMI에 연결하고, 반동기적으로 데이터를 검색한 다음 정리하는 완전한 WMI 클라이언트 응용 프로그램을 만들 수 있습니다.
이 예제에서는 로컬 컴퓨터의 운영 체제 이름을 가져와서 표시합니다. 원격 컴퓨터에서 데이터를 검색하려면 예: 원격 컴퓨터에서 WMI 데이터 수집하기를 참조해 보십시오. 데이터를 비동기적으로 가져오려면 예: 원격 컴퓨터에서 WMI 데이터 수집하기를 참조하십시오.
다음 절차는 WMI 응용 프로그램을 실행하는 데 사용됩니다. 1~5단계에는 WMI를 설정하고 연결하는 데 필요한 모든 단계가 포함되어 있으며 6~7단계에서는 데이터를 쿼리하여 해당 데이터를 수신합니다.
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::ExecQuery를 호출하여 운영 체제 이름에 대한 쿼리를 실행합니다.
다음 WQL 쿼리는 메서드 인수 중 하나입니다.
SELECT * FROM Win32_OperatingSystem
이 쿼리의 결과는 IEnumWbemClassObject 포인터에 저장됩니다.
이렇게 하면 쿼리의 데이터 개체를 IEnumWbemClassObject 인터페이스로 반동기적으로 검색할 수 있습니다.
자세한 내용은 WMI 열거를 참조하세요. 데이터를 비동기적으로 가져오려면 예: 로컬 컴퓨터에서 비동기적으로 WMI 데이터 가져오기를 참조하십시오.
WMI 요청에 대한 자세한 내용은 클래스 및 인스턴스 정보 조작, WMI 쿼리 및 메서드 호출을 참조하십시오.
7. WQL 쿼리에서 데이터를 가져오고 표시합니다.
IEnumWbemClassObject 포인터는 쿼리가 반환한 데이터 객체에 연결되며 IEnumWbemClassObject::Next 메서드를 사용하여 데이터 객체를 검색할 수 있습니다.
이 메서드는 메서드에 전달되는 IWbemClassObject 포인터에 데이터 객체를 연결합니다. IWbemClassObject::Get 메서드를 사용하여 데이터 객체에서 원하는 정보를 가져옵니다.
다음 코드 예제는 운영 체제의 이름을 제공하는 데이터 객체에서 Name 속성을 가져오는 데 사용됩니다.
VARIANT vtProp;
VariantInit(&vtProp);
// Get the value of the Name property
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
Name 속성 값이 VARIANT 변수 vtProp에 저장되고 사용자에게 표시 할 수 있는 상태가 됩니다.
자세한 내용은 WMI 열거를 참조하십시오.
다음 코드 예제에서는 로컬 컴퓨터에서 반동기적으로 WMI 데이터를 검색합니다.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
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 root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to 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: --------------------------------------------------
// 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
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 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
VariantInit(&vtProp);
// Get the value of the Name property
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
wcout << " OS Name : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
예: 로컬 컴퓨터에서 비동기로 WMI 데이터 수집하기
이 항목의 절차 및 코드 예제를 사용하여 COM 초기화를 수행하고, 로컬 컴퓨터의 WMI에 연결하고, 데이터를 비동기적으로 가져온 다음 정리하는 완전한 WMI 클라이언트 응용 프로그램을 만들 수 있습니다.
이 예는 로컬 컴퓨터의 운영 체제 이름을 가져와서 표시합니다.
다음은 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에 대한 포인터를 가져옵니다. 원격 컴퓨터에 연결하려면 예: 원격 컴퓨터에서 WMI 데이터 수집하기를 참조하십시오.
자세한 내용은 WMI 네임스페이스에 대한 연결 생성을 참조하십시오.
5. WMI 서비스가 CoSetProxyBlanket을 호출하여 클라이언트를 가장(Impersonate) 할 수 있도록 IWbemServices 프록시 보안을 설정합니다.
자세한 내용은 WMI 연결에 대한 보안 수준 설정을 참조하십시오.
6. IWbemServices 포인터를 사용하여 WMI에 요청합니다.
이 예제에서는 IWbemServices::ExecQueryAsync 메서드를 사용하여 데이터를 비동기적으로 수신합니다. 데이터를 비동기적으로 수신할 때마다 IWbemObjectSink 인터페이스를 구현 해야 합니다. 이 예제는 해당 구현으로 QuerySink 클래스를 만들었습니다. 이 클래스의 구현 코드 및 헤더 파일 코드는 주요 예제 다음에 제공됩니다. IWbemServices::ExecQueryAsync 메서드는 데이터가 수신될 때마다 QuerySink::Indicate 메서드를 호출합니다.
WMI 요청을 만드는 방법에 대한 자세한 내용은 클래스 및 인스턴스 정보 조작 및 메서드 호출을 참조하십시오.
데이터가 비동기적으로 데이터가 수신 될 때까지 기다리십시오.
IWbemServices::CancelAsyncCall 메서드를 사용하여 비동기 호출을 수동으로 중지합니다.
다음 코드는 로컬 컴퓨터에서 비동기 적으로 WMI 데이터를 수집 하는 코드 입니다:
#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.
}
// 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
다음 코드는 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
이상.
'프로그래밍' 카테고리의 다른 글
[C++]WMI 질의 만들기-2 (0) | 2023.02.13 |
---|---|
[C++]WMI 질의 만들기 - 1 (0) | 2023.02.12 |
WMI 데이터 수집 프로그램 예제 (1) | 2023.02.10 |
[C++] WMI - OS의 모든 것을 질의 해보기 (0) | 2023.02.07 |
[C#] 텍스트 파일 읽기 (0) | 2023.02.06 |