接收非同步事件通知

非同步事件通知是一種技術,可讓應用程式持續監視事件,而不需要獨佔系統資源。 非同步事件通知與其他非同步呼叫具有相同的安全性限制。 您可以改為進行半非同步呼叫。 如需詳細資訊,請參閱 呼叫方法

路由傳送至用戶端的非同步事件佇列可能會變得非常大。 因此,WMI 會實作全系統原則,以避免記憶體不足。 WMI 會讓事件變慢,或在佇列成長超過特定大小時,開始從佇列卸載事件。

WMI 使用Win32_WMISetting類別的LowThresholdOnEventsHighThresholdOnEvents屬性來設定記憶體不足避免的限制。 最小值表示 WMI 何時應該啟動慢速事件通知,而最大值則表示何時開始卸載事件。 低閾值和高閾值的預設值為 10000000 (10 MB) 和 2000000 (20 MB) 。 此外,您可以設定 MaxWaitOnEvents 屬性來描述 WMI 在卸載事件之前應該等候的時間量。 MaxWaitOnEvents的預設值為 2000 或 2 秒。

在 VBScript 中接收非同步事件通知

接收事件通知的腳本呼叫基本上與具有相同安全性問題的所有非同步呼叫相同。 如需詳細資訊,請參閱 使用 VBScript 進行非同步呼叫

在 VBScript 中接收非同步事件通知

  1. 呼叫 WScript.CreateObject 並指定 「WbemScripting」 和 SWbemSink的物件類型,以建立接收物件。 接收物件會收到通知。

  2. 針對您想要處理的每個事件撰寫副程式。 下表列出 SWbemSink 事件。

    事件 意義
    OnObjectReady 將 物件的傳回報告給接收。 使用此呼叫會每次傳回一個物件,直到作業完成為止。
    OnCompleted 報告非同步呼叫完成的時間。 如果作業無限期,則永遠不會發生此事件。
    OnObjectPut 報告非同步放置作業完成。 這個事件會傳回實例或已儲存類別的物件路徑。
    OnProgress 報告進行中非同步呼叫的狀態。 並非所有提供者都支援過渡進度報告。
    取消 取消與此物件接收相關聯的所有未完成非同步作業。

     

下列 VBScript 程式碼範例會以 10 秒輪詢間隔通知刪除進程。 在此腳本中,副程式SINK_OnObjectReady處理事件發生。 在此範例中,接收物件的名稱為 「Sink」,不過,您可以在選擇時將這個物件命名為 。

strComputer = "." 
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
Set MySink = WScript.CreateObject( _
    "WbemScripting.SWbemSink","SINK_")

objWMIservice.ExecNotificationQueryAsync MySink, _
    "SELECT * FROM __InstanceDeletionEvent" _
    & " WITHIN 10 WHERE TargetInstance ISA 'Win32_Process'"


WScript.Echo "Waiting for events..."

While (True)
    Wscript.Sleep(1000)
Wend

Sub SINK_OnObjectReady(objObject, objAsyncContext)
    Wscript.Echo "__InstanceDeletionEvent event has occurred."
End Sub

Sub SINK_OnCompleted(objObject, objAsyncContext)
    WScript.Echo "Event call complete."
End Sub

以 C++ 接收非同步事件通知

若要執行非同步通知,您只會建立個別的執行緒,以監視和接收來自 Windows Management Instrumentation 的事件 (WMI) 。 當該執行緒收到訊息時,執行緒會通知您的主要應用程式。

藉由指定個別執行緒,您可以允許主要進程在等候事件抵達時執行其他活動。 通知的非同步傳遞可改善效能,但可能會比您想要的安全性少。 在 C++ 中,您可以選擇使用 IWbemUnsecuredApartment 介面,或對安全性描述元執行存取檢查。 如需詳細資訊,請參閱 在非同步呼叫上設定安全性

設定非同步事件通知

  1. 在初始化任何非同步通知之前,請確定您已在 Win32_WMISetting中正確設定記憶體不足避免參數。

  2. 判斷您想要接收的事件種類。

    WMI 支援內建和外來事件。 內部事件是由 WMI 預先定義的事件,而 extrinsic 事件則是協力廠商提供者所定義的事件。 如需詳細資訊,請參閱 決定要接收的事件種類

下列程式描述如何在 C++ 中接收非同步事件通知。

在 C++ 中接收非同步事件通知

  1. 使用 對 CoInitializeExCoInitializeSecurity 函式的呼叫來設定應用程式。

    呼叫 CoInitializeEx 會初始化 COM,而 CoInitializeSecurity 會授與 WMI 呼叫取用者程式的許可權。 CoInitializeEx函式也會授與您程式設計多執行緒應用程式的能力,這是非同步通知的必要專案。 如需詳細資訊,請參閱 維護 WMI 安全性

    本主題中的程式碼需要下列參考和#include語句才能正確編譯。

    #define _WIN32_DCOM
    #include <iostream>
    using namespace std;
    #include <wbemidl.h>
    

    下列程式碼範例說明如何使用 對 CoInitializeExCoInitializeSecurity的呼叫來設定暫存事件取用者。

    void main(int argc, char **argv)
    {
        HRESULT hr = 0;
        hr = CoInitializeEx (0, COINIT_MULTITHREADED);
        hr = CoInitializeSecurity (NULL, 
           -1, 
           NULL, 
           NULL,   
           RPC_C_AUTHN_LEVEL_NONE, 
           RPC_C_IMP_LEVEL_IMPERSONATE, 
           NULL,
           EOAC_NONE,
           NULL); 
    
        if (FAILED(hr))
        {
           CoUninitialize();
           cout << "Failed to initialize security. Error code = 0x"
               << hex << hr << endl;
           return;
        }
    
    // ...
    }
    
  2. 透過 IWbemObjectSink 介面建立接收物件。

    WMI 使用 IWbemObjectSink 來傳送事件通知,以及報告非同步作業或事件通知的狀態。

  3. 使用 IWbemServices::ExecNotificationQueryAsync 方法的呼叫註冊事件取用者。

    請確定 pResponseHandler 參數指向在上一個步驟中建立的接收物件。

    註冊的目的是只接收必要的通知。 接收多餘的通知會浪費處理和傳遞時間;和 不會使用 WMI 的篩選能力,以取得最完整的可能。

    不過,暫時取用者可以接收一種以上的事件種類。 在此情況下,暫時取用者必須針對每個事件種類分別呼叫 IWbemServices::ExecNotificationQueryAsync 。 例如,取用者可能需要在實例建立事件 (或 __InstanceCreationEvent) 建立新進程時通知,以及在登錄事件 (特定登錄機碼的變更,例如 RegistryKeyChangeEvent) 。 因此,取用者會呼叫 ExecNotificationQueryAsync 來註冊實例建立事件,以及另一個呼叫 ExecNotificationQueryAsync 來註冊登錄事件。

    如果您選擇建立註冊多個事件的事件取用者,您應該避免向相同的接收註冊多個類別。 相反地,請針對已註冊事件的每個類別使用不同的接收。 擁有專用接收可簡化處理並協助維護,讓您取消一個註冊,而不會影響其他註冊。

  4. 在您的事件取用者中執行任何必要的活動。

    此步驟應該包含大部分的程式碼,並包含這類活動,例如向使用者介面顯示事件。

  5. 完成後,使用 IWbemServices::CancelAsyncCall 事件的呼叫來取消註冊暫存事件取用者。

    不論對 CancelAsyncCall 的呼叫是否成功或失敗,在物件參考計數達到零之前,請勿刪除接收物件。 如需詳細資訊,請參閱 呼叫方法