非同期イベント通知の受信
非同期イベント通知は、アプリケーションがシステム リソースを独占することなく、常にイベントを監視できるようにする手法です。 非同期イベント通知には、他の非同期呼び出しと同じセキュリティ制限があります。 代わりに、半同期呼び出しを行うことができます。 詳細については、メソッドの呼び出しに関するページを参照してください。
クライアントにルーティングされる非同期イベントのキューは、非常に大きくなる可能性があります。 そのため WMI は、メモリ不足を回避するためのシステム全体のポリシーを実装します。 キューが特定のサイズを超えると、WMI は、イベントの速度を低下させるか、キューからのイベントの削除を開始します。
WMI は、Win32_WMISetting クラスの LowThresholdOnEvents と HighThresholdOnEvents プロパティを使用して、メモリ不足回避の制限を設定します。 最小値は、WMI がイベントの速度低下の通知を開始するタイミングを示し、最大値はイベントの削除を開始するタイミングを示します。 低いしきい値と高いものの既定値は、1000000 (10 MB) と 2000000 (20 MB) です。 さらに、MaxWaitOnEvents プロパティを設定して、WMI がイベントを削除するまでに待機する時間を指定できます。 MaxWaitOnEvents の既定値は 2000、つまり 2 秒です。
VBScript での非同期イベント通知の受信
イベント通知を受信するためのスクリプト呼び出しは、基本的には、同じセキュリティ上の問題があるすべての非同期呼び出しと同じです。 詳細については、「VBScript を使用して非同期呼び出しを行う」を参照してください。
VBScript で非同期イベント通知を受信するには
WScript.CreateObject を呼び出し、progid "WbemScripting" とオブジェクト型 SWbemSink を指定して、シンク オブジェクトを作成します。 このシンク オブジェクトが通知を受信します。
処理するイベントごとにサブルーチンを記述します。 次の表に、SWbemSink イベントの一覧を示します。
イベント 説明 OnObjectReady オブジェクトが戻ったことをシンクに報告します。 この呼び出しを使用すると、操作が完了するまで毎回 1 つのオブジェクトが返されます。 OnCompleted 非同期呼び出しが完了したことを報告します。 操作が無期限の場合、このイベントは発生しません。 OnObjectPut 非同期 put 操作の完了を報告します。 このイベントは、インスタンスまたは保存されたクラスのオブジェクト パスを返します。 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 インターフェイスを使用するか、セキュリティ記述子に対してアクセス チェックを実行するオプションがあります。 詳細については、「非同期呼び出しでのセキュリティの設定」を参照してください。
非同期イベント通知を設定するには
非同期通知を初期化する前に、メモリ不足の回避パラメーターが Win32_WMISetting に正しく設定されていることを確認します。
受信するイベントの種類を決定します。
WMI では、組み込みと非組み込みのイベントがサポートされます。 組み込みイベントは WMI によって定義済みのイベントで、非組み込みイベントは、サード パーティのプロバイダーによって定義済みのイベントです。 詳細については、「受信するイベントの種類の決定」を参照してください。
C++ で非同期イベント通知を受信する方法について、次の手順で説明します。
C++ で非同期イベント通知を受信するには
CoInitializeEx と CoInitializeSecurity 関数への呼び出しを使用してアプリケーションを設定します。
CoInitializeEx の呼び出しは COM を初期化し、CoInitializeSecurity は WMI にコンシューマーのプロセスを呼び出すアクセス許可を付与します。 CoInitializeEx 関数は、非同期通知に必要なマルチスレッド アプリケーションをプログラミングする機能の付与も行います。 詳細については、「WMI セキュリティの維持」を参照してください。
このトピックのコードを正しくコンパイルするには、次の参照と #include ステートメントが必要です。
#define _WIN32_DCOM #include <iostream> using namespace std; #include <wbemidl.h>
CoInitializeEx と CoInitializeSecurity の呼び出しで一時イベント コンシューマーを設定する方法について、次のコード例で説明します。
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; } // ... }
IWbemObjectSink インターフェイスを使用してシンク オブジェクトを作成します。
WMI は、IWbemObjectSink を使用してイベント通知を送信し、非同期操作またはイベント通知の状態を報告します。
IWbemServices::ExecNotificationQueryAsync メソッドへの呼び出しを使用して、イベント コンシューマーを登録します。
"pResponseHandler" パラメーターが、前の手順で作成したシンク オブジェクトを指すようにします。
登録の目的は、必要な通知のみを受信することです。 余分な通知を受信すると、処理と配信時間が無駄になり、WMI のフィルター機能が最大限に活用されません。
ただし、一時的なコンシューマーは、複数の種類のイベントを受信できます。 この場合、一時的なコンシューマーは、イベントの種類ごとに IWbemServices::ExecNotificationQueryAsync を別個に呼び出す必要があります。 たとえば、コンシューマーは、新しいプロセスが作成されたとき (インスタンス作成イベントまたは __InstanceCreationEvent) と、特定のレジストリ キーの変更 (RegistryKeyChangeEvent などのレジストリ イベント) について通知を必要とする場合があります。 そのため、コンシューマーは ExecNotificationQueryAsync へのある呼び出しでインスタンス作成イベントに登録し、ExecNotificationQueryAsync への別の呼び出しでレジストリ イベントに登録します。
複数のイベントに登録するイベント コンシューマーを作成する場合は、同じシンクに複数のクラスを登録しないようにする必要があります。 代わりに、登録されたイベントのクラスごとに別個のシンクを使用します。 専用シンクを使用すると、メンテナンスの処理が簡素化されて役立ち、他のユーザーに影響を与えることなく 1 つの登録をキャンセルできるようになります。
イベント コンシューマーで必要なアクティビティを実行します。
この段階で、ほとんどのコードを含めていて、ユーザー インターフェイスにイベントを表示するなどのアクティビティを含めている必要があります。
完了したら、IWbemServices::CancelAsyncCall イベントへの呼び出しで一時イベント コンシューマーの登録を解除します。
CancelAsyncCall への呼び出しが成功するか失敗するかに関係なく、オブジェクト参照数がゼロになるまでシンク オブジェクトを削除しないでください。 詳細については、メソッドの呼び出しに関するページを参照してください。