WMI技术介绍和应用——VC开发WMI应用的基本步骤
? ? ? ? 在《WMI技術(shù)介紹和應(yīng)用——WMI概述》中介紹了我們可以使用C++、.net或者支持ActiveX技術(shù)的腳本語言來使用WMI。但是各種語言對WMI的控制能力是不同的,比如腳本語言只能用來從WMI獲取數(shù)據(jù)或者接收事件通知。而C++還可以編寫WMI提供者和發(fā)送消息。和腳本語言相比,C++對WMI有強(qiáng)大的控制和定制性,當(dāng)然也具有更大的復(fù)雜性。本文將主要講述使用VC如何搭建一個使用WMI的框架。(轉(zhuǎn)載請指明出于breaksoftware的csdn博客)
? ? ? ? 為了方便使用,我將該搭建步驟封轉(zhuǎn)到了一個類中
class CWMI
{
public:CWMI();~CWMI(void);
public:HRESULT ExcuteFun();
protected:VOID SetNamespace(wstring wstrNamespace);
private:HRESULT InitialCom();HRESULT SetComSecLevels();HRESULT ObtainLocator2WMI(CComPtr<IWbemLocator>& pLoc);HRESULT Connect2WMI(CComPtr<IWbemLocator> pLoc,CComPtr<IWbemServices>& pSvc);HRESULT SetProxySecLevels(CComPtr<IWbemServices> pSvc);virtual HRESULT Excute(CComPtr<IWbemServices> pSvc) = 0;
private:wstring m_wstrNamespace;
};
? ? ? ? SetNamespace用于設(shè)置命名空間。在《WMI技術(shù)介紹和應(yīng)用——WMI概述》中我們提到,WMI中存在諸如root\default、root\cimv2等WMI命令空間。因?yàn)槲覀円褂玫腤MI功能和命名空間有很大的關(guān)聯(lián),所以該類將提供這個設(shè)置命令空間的函數(shù)。
VOID CWMI::SetNamespace(wstring wstrNamespace)
{m_wstrNamespace = wstrNamespace;
}
? ? ? ? 剩下的函數(shù)就承載著了使用WMI步驟的邏輯和流程。
? ? ? ? 初始化COM庫
? ? ? ? 我們還要將之前的WMI框架圖列出來
? ? ? ? WMI是基于COM技術(shù)的。在WMI Consumers層,我們發(fā)現(xiàn),C++程序是直接和WMI COM API進(jìn)行交互。所以我們要先初始化COM組件庫。
HRESULT CWMI::InitialCom()
{HRESULT hr = E_FAIL;do {hr = CoInitializeEx(0, COINIT_MULTITHREADED);CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 設(shè)置進(jìn)程COM安全信息
? ? ? ? 因?yàn)閃MI是基于COM技術(shù)的,所以我們可以使用CoInitializeSecurity設(shè)置我們應(yīng)用的認(rèn)證信息和扮演等級(Impersonation Levels)。如果我們不調(diào)用該函數(shù),COM將通過讀取注冊表中的相關(guān)鍵值去決定我們應(yīng)用的認(rèn)證信息和扮演等級。然而,往往注冊表中記錄的認(rèn)證信息和扮演等級是非常低的。一般來說,注冊表記錄的扮演等級是RPC_C_IMP_LEVEL_IDENTIFY,而絕大部分WMI提供者至少需要RPC_C_IMP_LEVEL_IMPERSONATE等級。對于認(rèn)證信息,在特殊場景下,我們可能需要用其他用戶身份去使用COM。但是目前,我在管理員權(quán)限下運(yùn)行程序,權(quán)限基本上是夠得,所以設(shè)置也很簡單。
HRESULT CWMI::SetComSecLevels()
{// Set general COM security levels --------------------------// Note: If you are using Windows 2000, you must specify -// the default authentication credentials for a user by using// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----// parameter of CoInitializeSecurity ------------------------HRESULT hr = E_FAIL;do {hr = CoInitializeSecurity(NULL, -1, // COM negotiates serviceNULL, // Authentication servicesNULL, // ReservedRPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation NULL, // Authentication infoEOAC_NONE, // Additional capabilities NULL // Reserved);CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 創(chuàng)建進(jìn)程內(nèi)COM服務(wù)器
? ? ? ? 我們應(yīng)用中使用WMI完成相關(guān)功能,比如查詢硬盤ID,實(shí)際執(zhí)行查詢的操作是在WMI服務(wù)中執(zhí)行的,而不是我們的應(yīng)用。比如,在XP上,svchost.exe服務(wù)是WMI服務(wù)的載體。我們應(yīng)用通過COM告訴svchost.exe我們的請求,svchost.exe將我們請求執(zhí)行后,會將結(jié)果通過COM傳遞給我們的應(yīng)用。這樣就要求我們應(yīng)用和WMI服務(wù)進(jìn)程有通信。在我們應(yīng)用這邊,就需要創(chuàng)建一個進(jìn)程內(nèi)COM服務(wù)器用于接發(fā)數(shù)據(jù)。
HRESULT CWMI::ObtainLocator2WMI(CComPtr<IWbemLocator>& pLoc)
{HRESULT hr = E_FAIL;do {hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 連接WMI命名空間
? ? ? ? 這步是使用WMI的關(guān)鍵一步。我們使用上一步創(chuàng)建的IWbemLocator實(shí)例的ConnectServer函數(shù)連接本地或者遠(yuǎn)程的WMI命名空間。我們看一下函數(shù)聲明
HRESULT ConnectServer([in] const BSTR strNetworkResource,[in] const BSTR strUser,[in] const BSTR strPassword,[in] const BSTR strLocale,[in] LONG lSecurityFlags,[in] const BSTR strAuthority,[in] IWbemContext *pCtx,[out] IWbemServices **ppNamespace
);
? ? ? ? 第一個參數(shù)strNetworkResource是命名空間的名字,比如"root\default"或者"\\.\root\default"。第二三個是用戶名和密碼,如果是遠(yuǎn)程計(jì)算機(jī),則這兩個參數(shù)非常有用。最后一個參數(shù)返回了IWbemServices結(jié)構(gòu)的代理。我們可以通過該代理訪問WMI服務(wù)。
HRESULT CWMI::Connect2WMI( CComPtr<IWbemLocator> pLoc,CComPtr<IWbemServices>& pSvc )
{HRESULT hr = E_FAIL;do {hr = pLoc->ConnectServer(CComBSTR(m_wstrNamespace.c_str()), NULL, NULL, NULL, NULL, NULL, NULL, &pSvc );CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 設(shè)置WMI連接的安全等級
? ? ? ? 一般來說,如果沒有設(shè)置正確的安全屬性,COM是不允許一個進(jìn)程去訪問另一個進(jìn)程的中的對象。我們上步獲得的IWbemServices接口代理就需要訪問WMI服務(wù)進(jìn)程中的對象,所以我們要對該代理設(shè)置安全等級。
HRESULT CWMI::SetProxySecLevels( CComPtr<IWbemServices> pSvc )
{HRESULT hr = E_FAIL;do {hr = CoSetProxyBlanket(pSvc, // Indicates the proxy to setRPC_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_xxxNULL, // client identityEOAC_NONE // proxy capabilities );CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 發(fā)起WMI請求
? ? ? ? 通過以上一系列過程,我們終于可以開始使用WMI了。在我定義的類中,我將該步驟封裝成一個純虛函數(shù)Excute,繼承CWMI的類將實(shí)現(xiàn)具體的工作。
? ? ? ? 清理?
? ? ? ? 我們在使用完以上的代理和實(shí)例后,我們要釋放它們,并且最后要釋放COM庫。
CWMI::~CWMI(void)
{CoUninitialize();
}
? ? ? ? 總體來說執(zhí)行的流程用代碼可以描述為
HRESULT CWMI::ExcuteFun()
{HRESULT hr = E_FAIL;CComPtr<IWbemLocator> pLoc = NULL;CComPtr<IWbemServices> pSvc = NULL;do {hr = InitialCom();CHECKHR(hr);hr = SetComSecLevels();CHECKHR(hr);hr = ObtainLocator2WMI(pLoc);CHECKHR(hr);hr = Connect2WMI(pLoc, pSvc);CHECKHR(hr);hr = SetProxySecLevels(pSvc);CHECKHR(hr);hr = Excute(pSvc);CHECKHR(hr);} while (0);return hr;
}
? ? ? ? 下一節(jié),我將講解一個簡單的對CWMI的封裝類。
? ? ? ? 工程源碼見《WMI技術(shù)介紹和應(yīng)用——WMI概述》結(jié)尾。
總結(jié)
以上是生活随笔為你收集整理的WMI技术介绍和应用——VC开发WMI应用的基本步骤的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WMI技术介绍和应用——WMI概述
- 下一篇: WMI技术介绍和应用——使用VC编写一个