WMI技术介绍和应用——执行方法
? ? ? ? 在之前的博文中,我們主要介紹了如何使用WMI查詢信息和接收事件。本文將介紹WMI的另一種用法——執行方法。(轉載請指明出于breaksoftware的csdn博客)
? ? ? ? 這塊的內容在msdn中有詳細的介紹,如果想看原版的可以參閱《Example: Calling a Provider Method》
? ? ? ? 本文將基于《WMI技術介紹和應用——VC開發WMI應用的基本步驟》中介紹的基類CWMI,在繼承類中重寫Excute函數,實現執行方法的功能。
? ? ? ? 之所以繼承于CWMI,是為了將WMI邏輯中相同部分提煉出來。不同的使用方式只要完成其核心功能即可,回顧下CWMI類的執行主體
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;
}
? ? ? ? 除Excute方法之外的其他方法,我們都是公用的。那我們看下執行方法的類是如何實現的。
? ? ? ? 首先我們定義一個map,用于保存執行函數的參數。因為不同函數的參數名不同,類型不同,所以我們要做如下定義
typedef std::map<std::wstring, CComVariant> ParamsMap;class CExcuteMethod : public CWMI
{
public:CExcuteMethod(const wstring& wszNamespace, const std::wstring& wstrClass,const std::wstring& wstrInstanceName, const std::wstring& wstrMethod, const std::wstring& wstrRet, const ParamsMap& params);~CExcuteMethod(void);
private:HRESULT Excute(CComPtr<IWbemServices> pSvc);
private:std::wstring m_wstrInstanceName;std::wstring m_wstrClassName;std::wstring m_wstrMethod;std::wstring m_wstrRet;ParamsMap m_params;
};
? ? ? ? CComVariant類型保證我們每個參數可以由使用者自己定義。
? ? ? ? 在構造函數中,我們需要傳入WMI類名(非C++類名),調用方法名,返回值名,參數map。
? ? ? ? 在執行的主體函數Excute中,我們首先使用WMI類名獲取類
HRESULT CExcuteMethod::Excute( CComPtr<IWbemServices> pSvc )
{HRESULT hr = WBEM_S_FALSE;do {CComBSTR bstrClassName = m_wstrClassName.c_str();CComPtr<IWbemClassObject> spClassObject = NULL;hr = pSvc->GetObject(bstrClassName, 0, NULL, &spClassObject, NULL);if (FAILED(hr) || !spClassObject) {break;}
? ? ? ? 然后通過方法名,獲取這個類中函數的入參定義
CComBSTR bstrMethodName = m_wstrMethod.c_str();CComPtr<IWbemClassObject> spInParamsDefinition = NULL;hr = spClassObject->GetMethod(bstrMethodName, 0, &spInParamsDefinition, NULL);if (FAILED(hr) || !spInParamsDefinition) {break;}
? ? ? ? 實例化入參定義的一個實例,然后對這個入參實例進行參數賦值。注意一下,這個地方的賦值,非常符合腳本語言的問題,即通過名稱進行賦值,而不是按照C語言風格的入參順序進行賦值
CComPtr<IWbemClassObject> spParamsInstance = NULL;hr = spInParamsDefinition->SpawnInstance(0, &spParamsInstance);if (FAILED(hr) || !spParamsInstance) {break;}for (ParamsMap::iterator it = m_params.begin(); it != m_params.end(); it++) {if (!it->first.empty()) {CComVariant value = it->second;hr = spParamsInstance->Put(it->first.c_str(), 0, &value, 0);}}
? ? ? ? 最后,我們通過類名、方法名、參數實例去執行方法名獲取返回的數據實例
CComPtr<IWbemClassObject> spOutParams = NULL;if (!m_wstrInstanceName.empty()) {//CComBSTR(L"ClassInstance.name='InstanceName'")CComBSTR bstrInstanceName = m_wstrInstanceName.c_str();hr = pSvc->ExecMethod(bstrInstanceName, bstrMethodName, 0, NULL, spParamsInstance, &spOutParams, NULL);}else if (!m_wstrClassName.empty()) {hr = pSvc->ExecMethod(bstrClassName, bstrMethodName, 0, NULL, spParamsInstance, &spOutParams, NULL);}if (SUCCEEDED(hr) && !m_wstrRet.empty()) {CComVariant varRet;hr = spOutParams->Get(CComBSTR(m_wstrRet.c_str()), 0, &varRet, NULL, 0);}
? ? ? ? 如此便可以執行一個方法調用。這兒有個地方需要注意下,就是調用ExecMethod方式存在兩種方式:
- 類的靜態方法直接使用類名調用
- 類的非靜態方法使用對象名調用,這種調用我們將在之后的講解WMI Provider時介紹。
? ? ? ? 我們在main函數中進行如下測試
CExcuteMethod* excute_method = NULL;{ParamsMap params;{CComVariant vt;vt.vt = VT_BSTR;vt.bstrVal = CComBSTR("notepad.exe");params[L"CommandLine"] = vt;}excute_method = new CExcuteMethod(L"root\\CIMV2", L"", L"Win32_Process", L"Create", L"ReturnValue", params);excute_method->ExcuteFun();}delete excute_method;
? ? ? ? 這段代碼將啟動一個記事本程序,我們沒有指定對象名,說明Ceate方法是Win32_Process的靜態方法。這段代碼需要注意下,就是我為什么要使用動態創建指針的方式,而不是直接定義一個對象?還有就是為什么要種{}控制除指針申明和銷毀之外的邏輯?這其中主要的原因是我們CWMI類中控制了COM組件的初始化和卸載操作。如果直接使用對象,則對象的消亡和Main函數中使用的CComVariant類型數據的消亡順序將不可控制,會導致崩潰(實際的確是CComVariant后釋放從而出現異常)。而我們使用動態創建對象和使用{}控制CComVariant的生命周期的方式,實現了對象消亡順序的可控。當然這不是一種好的設計,于是我們似乎應該將WMI的初始化和卸載交由調用者控制。
? ? ? ? 工程源碼見《WMI技術介紹和應用——WMI概述》結尾。
總結
以上是生活随笔為你收集整理的WMI技术介绍和应用——执行方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WMI技术介绍和应用——接收事件
- 下一篇: WMI技术介绍和应用——事件通知