WMI技术介绍和应用——Event Provider
? ? ? ? 在《WMI技術介紹和應用——Instance/Method Provider》一文中,我們介紹了Instance和Method Provider的編寫方法。本文我們將介紹更有意思的“事件提供者”。在《WMI技術介紹和應用——事件通知》中,我們曾經提到事件是分為兩種:intrinsic event和extrinsic event。這兩種事件提供者在編寫上也非常類似,我們先以extrinsic event為例。(轉載請指明出于breaksoftware的csdn博客)
intrinsic event provider
? ? ? ? 之前生成工程的過程和《WMI技術介紹和應用——Instance/Method Provider》中介紹的一致,但是我們這次要新增的ATL class則不同
? ? ? ? 在”名稱“頁,我們在short name中填上我們事件提供者的名稱”TestEvent",其他輸入框內容將自動生成。
? ? ? ? 事件類型我們選擇extrinsic event,其他不填
? ? ? ? 在“屬性”頁,將Threading model設置為Both。Support選項都勾選上
? ? ? ? 執行完之后,我們就生成了一個mof文件、一個TestEvent.h和TestEvent.cpp文件。我們繼續從mof文件入手,我們申明一個事件類
[Locale(1033) : ToInstance,UUID("{E5EDE7F6-D9F9-4195-8E97-643B71F2FB91}") : ToInstance]
class ClassEventInstance: __ExtrinsicEvent
{
string name = "CIN";
string value = "CIV";
};
? ? ? ? 然后注冊一個事件提供者,并指定查詢命令
instance of __EventProviderRegistration
{provider = $TestEvent;EventQueryList = {"select * from ClassEventInstance"};
};
? ? ? ? 再回到cpp代碼文件,首先我們要修改類名
const static WCHAR * s_pMyClassName = L"ClassEventInstance";
? ? ? ? 其次我們要修改AccessCheck函數,刪除掉這行,否則我們查詢不會成功
hr = WBEM_E_ACCESS_DENIED;
? ? ? ? 我們需要修改ProvideEvents函數,在該函數末尾新增如下邏輯
HANDLE hThread = (HANDLE)_beginthread(ThreadRoutine, 0, this);CloseHandle(hThread);
? ? ? ? 我們啟動一個線程,用于事件的發送。我們傳入this指針只是為了之后調用我們類中的一個方法。我們看下線程函數
static void ThreadRoutine(void* param) {OutputTrace("CTestEvent::ThreadRoutine");CoInitializeEx(NULL, COINIT_MULTITHREADED);CTestEvent* pThis = (CTestEvent*)(param);while(true) {Sleep(1000*2);pThis->FireEvent();}CoUninitialize();
};
? ? ? ? 這段邏輯,我們在一個死循環中每隔兩秒鐘觸發一次事件——FireEvent。FireEvent本來是模板自動生成的,而我們借用它實現事件的觸發。這兒需要注意一個文件,本文主要講解搭建的關鍵步驟,而對很多其他細節和安全問題沒有做過多處理,否則就喧賓奪主了。比如本文中所提到的線程執行函數,其實存在線程安全問題,而我又不想引入COM跨線程問題,所以就如此簡單粗暴的編寫。
STDMETHODIMP CTestEvent::FireEvent()
{HRESULT hr = WBEM_S_NO_ERROR;ATLASSERT(m_pEventClass);CComPtr<IWbemClassObject> pInstance;hr = m_pEventClass->SpawnInstance(0, &pInstance);if(FAILED(hr)) {return hr;}CComVariant value;value.vt = VT_BSTR;value.bstrVal = CComBSTR("notepad.exe");pInstance->Put(L"name", 0, &value, 0);return m_pSink->Indicate(1, &(pInstance.p) );
}
? ? ? ? 我們Spawn一個實例,然后填充它的一些屬性,最后將該對象放入客戶端可以訪問的sink中。
? ? ? ? 我們使用之前實現的查詢類查詢該事件
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);CAsynNotifyQuery<CInstanceEvent> recvnotify(L"root\\default", L"SELECT * FROM ClassEventInstance", hEvent);recvnotify.ExcuteFun();
? ? ? ? 我們即可以看到結果
extrinsic event provider? ? ? ??
? ? ? ? extrinsic event provider實現講完了,我們再講講intrinsic event provider。工程向導方面和extrinsic event provider基本相同,只是在WMI Class頁中選擇intrinsic event。我們對新的provider取名為IntrinsicEvent。我們也從mof入手,看看怎么修改
[
dynamic : ToInstance,
provider("IntrinsicEvent") : ToInstance, // uses the TestInstance Provider
ClassContext("whatever!"), // information is dynamically// supported by the provider
DisplayName("IntrinsicClassInstance"): ToInstance
] class IntrinsicClassInstance
{
[key]
string name = "CIN";
[PropertyContext("IntrinsicClassInstance_Member")]
string value = "CIV";
};
? ? ? ? 首先我們定義Event的類名——IntrinsicClassInstance,并申明其有兩個屬性——name和value。其次我們我們修改下事件提供者注冊對象
instance of __EventProviderRegistration
{provider = $IntrinsicEvent;EventQueryList = {"select * from __InstanceCreationEvent where TargetInstance isa \"IntrinsicClassInstance\""};
};
? ? ? ? 從WQL的寫法我們可以發現,這種寫法和檢測進程創建的Win32_Process類類似,這就是內部(Intrinsic)事件的特點。cpp的修改和extrinsic event provider中介紹的過程類似,只是Intrinsic沒有FireEvent方法,那我們就自己申明和定義一個
STDMETHODIMP CIntrinsicEvent::FireEvent()
{HRESULT hr = WBEM_S_NO_ERROR;ATLASSERT(m_pEventClass);CComPtr<IWbemClassObject> pInstance;hr = m_pDataClass->SpawnInstance(0, &pInstance);if(FAILED(hr)) {OutputTrace("CIntrinsicEvent::FireEvent1");return hr;}CComVariant value;value.vt = VT_BSTR;value.bstrVal = CComBSTR("notepad.exe");pInstance->Put(L"name", 0, &value, 0);CComPtr<IWbemClassObject> pEventInstance;hr = m_pEventClass->SpawnInstance(0, &pEventInstance);if(FAILED(hr)) {return hr;}CComVariant varTargetInst(pInstance);pEventInstance->Put(L"TargetInstance", 0, &varTargetInst, 0);return m_pSink->Indicate(1, &(pEventInstance.p) );
}
? ? ? ? 我們將新生成的實例放入到pEventInstance實例的"TargetInstance"中,這也和上面的WQL的“TargetInstance isa \"IntrinsicClassInstance\"”相對應。pEventInstance實例的類是我們在模板基礎上新增的,我們要修改Initialize函數,新增
hr = m_pNamespace->GetObject(CComBSTR("__InstanceCreationEvent"), 0, pCtx, //passing IWbemContext pointer to prevent deadlocks&m_pEventClass, NULL);
if (FAILED(hr)) {return hr;
}
? ? ? ?我們使用如下代碼訪問該事件
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);CAsynNotifyQuery<CInstanceEvent> recvnotify(L"root\\default", L"SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'IntrinsicClassInstance'", hEvent);recvnotify.ExcuteFun();
? ? ? ? 我們可以得到如下結果
? ? ? ? 工程鏈接:http://pan.baidu.com/s/1o6QcgPW 密碼:4l5v
總結
以上是生活随笔為你收集整理的WMI技术介绍和应用——Event Provider的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WMI技术介绍和应用——Instance
- 下一篇: WMI技术介绍和应用——Event Co