WMI技术介绍和应用——Event Consumer Provider
? ? ? ? 在《WMI技術介紹和應用——Event Provider》和《WMI技術介紹和應用——接收事件》中,我們展現了如何處理和事件相關的WMI知識。而《WMI技術介紹和應用——接收事件》一文則主要講解了如何查詢事件,這種查詢是在我們進程存在時發生的,一旦我們進程不存在了,這種查詢也無法執行。我們將這種行為稱為消費事件,我們執行查詢的進程叫做“事件臨時消費者”。相對應的,WMI還存在“事件永久消費者”,它并不寄生我們的編寫的進程中。本文主要講解“事件永久消費者”的編寫方法。(轉載請指明出于breaksoftware的csdn博客)
? ? ? ? 由于VS2005沒有這種模板,所以我便使用事件提供者模板生成了一個工程,并對這個工程進行改造。我們先從mof文件出發
? ? ? ? 由于我們不需要注冊事件提供者,所以我們刪除instance?of?__EventProviderRegistration內容。
? ? ? ? 我們先要聲明一個事件消費類
class TestEventConsumer : __EventConsumer
{[key] string name;[write] string value;
};
? ? ? ? 實例化該類
instance of TestEventConsumer as $Consumer
{name = "TestEventConsumer_Name1";value = "TestEventConsumer_Value";
};
? ? ? ? 再注冊一個事件消費者提供者實例
instance of __EventConsumerProviderRegistration
{Provider = $EventConsumer;ConsumerClassNames = {"TestEventConsumer"};
};
? ? ? ? ConsumerClassNames是一個數組,它記錄了事件消費者名。
? ? ? ? 然后要實例化一個篩選器
instance of __EventFilter as $Filter
{Name = "TestEventFilter";QueryLanguage = "WQL";Query = "SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_USBCOntrollerDevice'";EventNamespace = "\\\\.\\root\\CIMV2";
};
? ? ? ? 其中定義了篩選器的名字、查詢的語言、查詢的命令和需要查詢的命名空間。如果沒有指定EventNamespace,則使用該mof中默認的命名空間。在本例中,我們要監控USB設備的創建,故要監控CIMV2空間。這兒需要注意的是,我們可以Query內部事件或者外部事件。
? ? ? ? 最后我們將篩選器綁定到消費者上。
instance of __FilterToConsumerBinding
{Consumer = $Consumer;Filter = $Filter;
};
? ? ? ? 如此,我們便將mof文件構建好了。
? ? ? ? 我們再回到cpp文件中,我們首先要定義一個事件消費者Sink
class CEventConsumerSink:public CComObjectRootEx<CComMultiThreadModel>,public IWbemUnboundObjectSink
{
public:CEventConsumerSink() {}~CEventConsumerSink(){}BEGIN_COM_MAP(CEventConsumerSink) COM_INTERFACE_ENTRY(IWbemUnboundObjectSink) END_COM_MAP() // IWbemUnboundObjectSink
public: STDMETHOD(IndicateToConsumer)(IWbemClassObject* pLogicalConsumer, long lNumObjects, IWbemClassObject** apObjects);
};
? ? ? ? 我們要實現IndicateToConsumer方法,將事件傳到到該方法中處理
STDMETHODIMP CEventConsumerSink::IndicateToConsumer(IWbemClassObject* pLogicalConsumer, long lNumObjects, IWbemClassObject** apObjects)
{ObjectLock lock(this); HRESULT hr = WBEM_S_NO_ERROR; CComVariant varClass; hr = pLogicalConsumer->Get(CComBSTR("__CLASS"), 0, &varClass, 0, 0);if (0 == _wcsicmp(V_BSTR(&varClass), L"TestEventConsumer")) {for (long lIndex = 0; lIndex < lNumObjects; lIndex++) {CComVariant varEventType;hr = apObjects[lIndex]->Get(CComBSTR("TargetInstance"), 0, &varEventType, 0, 0);CComQIPtr<IWbemClassObject> spEvent = V_UNKNOWN(&varEventType);CComVariant varEventTypeClass;hr = spEvent->Get(CComBSTR("__CLASS"), 0, &varEventTypeClass, 0, 0);OutputTrace("CEventConsumerSink::IndicateToConsumer"); } }else {hr = WBEM_E_NOT_FOUND;}return hr;
}
? ? ? ? 這段邏輯,我們獲取事件名稱,并檢測其是否是我們需要監控的事件。如果是,則遍歷事件數組——發來的事件是一批的。
? ? ? ? 然后我們改造主類。事件消費者提供者不需要繼承IWbemInstProviderImpl,但是要繼承IWbemEventConsumerProvider。于是我們在模板生成的代碼中將其他無關的方法去掉
class ATL_NO_VTABLE CEventConsumer : public CComObjectRootEx<CComMultiThreadModel>,public CComCoClass<CEventConsumer, &CLSID_EventConsumer>,public IWbemProviderInit,public IWbemEventConsumerProvider
{ public:CEventConsumer(){ }~CEventConsumer(){}DECLARE_REGISTRY_RESOURCEID(IDR_EVENTCONSUMER)DECLARE_NOT_AGGREGATABLE(CEventConsumer)BEGIN_COM_MAP(CEventConsumer)COM_INTERFACE_ENTRY(IWbemProviderInit)COM_INTERFACE_ENTRY(IWbemEventConsumerProvider)END_COM_MAP()//IWbemProviderInitHRESULT STDMETHODCALLTYPE Initialize( __in_opt LPWSTR pszUser,LONG lFlags,__in LPWSTR pszNamespace,__in_opt LPWSTR pszLocale,IWbemServices *pNamespace,IWbemContext *pCtx,IWbemProviderInitSink *pInitSink);// IWbemEventConsumerProviderHRESULT STDMETHODCALLTYPE FindConsumer( /* [in] */ IWbemClassObject *pLogicalConsumer,/* [out] */ IWbemUnboundObjectSink **ppConsumer);};
? ? ? ??Initialize中刪除模板生成的多余代碼就可以了,我們主要要實現的就是FindConsumer方法
STDMETHODIMP CEventConsumer::FindConsumer( /* [in] */ IWbemClassObject *pLogicalConsumer,/* [out] */ IWbemUnboundObjectSink **ppConsumer)
{HRESULT hr = WBEM_E_NOT_FOUND;*ppConsumer = NULL;CComVariant varClass;hr = pLogicalConsumer->Get(L"__Class", 0, &varClass, 0, 0);if (0 == _wcsicmp(V_BSTR(&varClass), L"TestEventConsumer")) {CComObject<CEventConsumerSink>* pEventSink = NULL;hr = CComObject<CEventConsumerSink>::CreateInstance(&pEventSink);if (FAILED(hr)) {return hr;}hr = pEventSink->QueryInterface(IID_IWbemUnboundObjectSink, (LPVOID*)ppConsumer);if (FAILED(hr)) {return hr;}}else {hr = WBEM_E_NOT_FOUND;}return hr;
}
? ? ? ? 這段邏輯我們在檢測完消費者類是否正確后,就去獲取消費者指針。
? ? ? ? 如此Event Consumer Provider便搭建起來了。
總結
以上是生活随笔為你收集整理的WMI技术介绍和应用——Event Consumer Provider的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WMI技术介绍和应用——Event Pr
- 下一篇: WMI技术介绍和应用——总结(完)