プロバイダーのアンロード
WMI は、プロバイダーの使用を終了すると、プロバイダーをメモリからアンロードします。 WMI がプロバイダーをアンロードする主な理由は、システム リソースを節約するためです。 そのため、WMI が効率的な方法でプロバイダーをアンロードできるようにするコードを追加する必要があります。 WMI がプロバイダーをアンロードするには、キャッシュ コントロールで指定された間隔からその間隔の 2 倍までの任意の期間がかかります。
WMI は、次のいずれかの方法でプロバイダーをアンロードします。
- プロバイダーに指定されたタスクが完了したら、プロバイダーをアンロードします。
- ユーザーがシステムをシャットダウンしたときに、すべてのプロバイダーをすばやくアンロードします。 WMI サービスがコマンド ラインからシャットダウンされると、WMI はインプロセス プロバイダーをアンロードします。
最初のシナリオがより一般的ですが、両方の可能性に備えてプロバイダーを記述する必要があります。
このトピックでは、次のセクションについて説明します。
アイドル状態のプロバイダーのアンロード
WMI は、アイドル状態のプロバイダーをアンロードするときに、次のアクションを実行します。
プロバイダーがアイドル状態かどうかを判断します。
WMI は ClearAfter プロパティを使用して、プロバイダーをアンロードする前にプロバイダーがアイドル状態を維持できる期間を決定します。 詳細については、「プロバイダーのアイドル時間へのアクセス」を参照してください。
プロバイダーの Release メソッドを呼び出します。
プロバイダーが純粋なプロバイダーの場合、Release はアクティブ メモリからプロバイダーを完全に削除します。 ただし、WMI が Release を呼び出した後も、純粋でないプロバイダーは引き続き実行される可能性があります。
プロバイダーのアイドル時間へのアクセス
プロバイダーがアクティブな状態を維持する最小時間は、ClearAfter プロパティによって決まります。 ClearAfter は、\root 名前空間の WMI システム クラス __CacheControl から派生するクラスのインスタンスにあります。
プロバイダーのアンロードを制御する __CacheControl から派生するクラスを次の一覧に示します。
- __EventConsumerProviderCacheControl
- __EventProviderCacheControl
- __EventSinkCacheControl
- __ObjectProviderCacheControl
- __PropertyProviderCacheControl
特定の種類のプロバイダーのキャッシュ コントロール インスタンスの ClearAfter プロパティを編集して、プロバイダーが非アクティブな状態を維持することを WMI が許容する最小時間を変更できます。 たとえば、プロパティ プロバイダーがアイドル状態を維持できる時間を制限するには、\root 名前空間の __PropertyProviderCacheControl インスタンスの ClearAfter プロパティを編集します。
WMI クライアントでもあるプロバイダーのアンロード
プロバイダーは、実行するために呼び出されたプロバイダー関数を完了した後も、WMI のクライアントを維持することが必要な場合があります。 たとえば、プッシュ プロバイダーが WMI にクエリを発行することが必要な場合があります。 詳細については、「プッシュまたはプルの状態の決定」を参照してください。 この場合、プロバイダーを表す __Win32Provider インスタンスの Pure プロパティを TRUE に設定する必要があります。 Pure プロパティが FALSE に設定されている場合、WMI がプライマリ インターフェイスの Release メソッドを呼び出すときに、プロバイダーが未処理のすべてのインターフェイス ポイントに対して IUnknown::Release を呼び出してアンロードを準備します。 詳細については、__Win32Provider の「解説」セクションを参照してください。
プロバイダーのプライマリ インターフェイスのリリース メソッドを実装する方法について、次の手順で説明します。
プロバイダーをアンロードするには
WMI がプロバイダーのプライマリ インターフェイスの Release メソッドを呼び出すときに、WMI に対して保持したすべてのインターフェイス ポインターを解放します。
通常、プロバイダーは、IWbemProviderInit::Initialize で提供される IWbemServices と IWbemContext インターフェイスへのポインターを保持します。
関連付けられている __Win32Provider インスタンスの Pure プロパティが FALSE に設定されている場合、プロバイダーは、WMI が Release を呼び出した後にクライアント アプリケーションのロールに切り替わることができます。 ただし、WMI はクライアント システムとして動作しているプロバイダーをアンロードできないため、システムのオーバーヘッドが増加します。
Pure が TRUE に設定されているプロバイダーは、要求を処理するためにのみ存在します。 そのため、この種類のプロバイダーはクライアント アプリケーションのロールを担当できず、WMI がアンロードできます。
シャットダウン中のプロバイダーのアンロード
通常の状況では、「WMI クライアントでもあるプロバイダーのアンロード」のガイドラインを使用すると、WMI がプロバイダーを適切にアンロードできます。 ただし、ユーザーがシステムのシャットダウンを選択したときなど、WMI が通常のアンロード手順を開始できない場合があります。 適切なクリーンアップ戦略の実装に加えて、データ ストレージのトランザクション モデルを使用して、プロバイダーが適切にアンロードされるようにできます。
ユーザーはいつでも WMI を停止する可能性があります。 このような状況では、WMI はプロバイダーのアンロードも、いずれのインプロセス プロバイダーに対する DllCanUnloadNow エントリ ポイントの呼び出しも実行しません。 さらに、シャットダウン時にインプロセス プロバイダーがメソッド呼び出しの最中である場合、WMI は呼び出しの最中に実行中のスレッドを終了する可能性があります。 この状況では、WMI は、オブジェクト デストラクターなどのクリーンアップを通常処理するルーチンを呼び出しません。 WMI は、単に DllMain を呼び出すのみです。
オペレーティング システムが WMI をシャットダウンすると、システムはインプロセス プロバイダーに割り当てられているすべてのメモリを自動的に解放します。 オペレーティング システムは、ファイル ハンドル、ウィンドウ ハンドルなどの、プロバイダーが保持するほとんどのリソースを閉じる処理も行います。 プロバイダーが、これを実現するために特定のアクションを実行する必要はありません。
WMI は呼び出しの最中にシャットダウンする可能性があるため、プロバイダーはデータ ソースを不整合な状態のままにしないようにする必要があります。 データを不整合な状態のままにすることは、読み取り専用プロバイダーでは問題になりません。 ただし、書き込み機能があるプロバイダーは、突然の終了後に安全にロールバックできるようにするために、何らかのトランザクション モデルを実装することが必要な場合があります。
オペレーティング システムが一部の一般的なシステム リソースを解放する場合がありますが、システムが、すべてのリソースを自動的に解放するわけではありません。 たとえば、オペレーティング システムがソケットまたはデータベース接続を解放しない場合があります。 代わりに、プロバイダーがそのようなリソースを手動でクリーンアップすることが必要な場合があります。 これらの問題を回避するには、プロバイダーをアウトプロセスで実装するか、クリーンアップ コードを追加します。
最もシンプルな解決策は、プロバイダーをアウトプロセスで実装することです。 WMI は COM タイムアウト後にプロバイダーを解放しますが、WMI がシャットダウンしてもアウトプロセス プロバイダーは強制終了されません。 クリーンアップと終了の堅牢性の問題がパフォーマンスよりも重要なプロバイダーは、アウトプロセスにすることが考えられます。
プロバイダーにクリーンアップ コードを配置する必要がある場合は、2 つのオプションがあります。 この種のクリーンアップを実行する場所の 1 つは、DLL のアンロード時にオペレーティング システムが呼び出す DLL エントリ ポイント関数である DllMain です。 クリーンアップ コードは DllMain に直接追加し、DLL_PROCESS_DETACH への応答で実行できます。 DllMain でのクリーンアップ コードの実装は、特に MFC や ATL などのプログラミング環境では、調整がやや難しい場合があります。 詳細については、Microsoft サポート技術情報の記事 Q148791「独自の DllMain を提供する方法 (MFC 標準 DLL で独自の DllMain を提供する方法)」を参照してください。(このリソースは、一部の言語や国または地域では使用できない場合があります)。
別の方法として、クリーンアップ コードをグローバル クラスのデストラクターに配置することもできます。 詳細については、「プロバイダーのアンロード」を参照してください。 Windows オペレーティング システムは、ヒープにグローバル オブジェクトを割り当てません。 オペレーティング システムは代わりに、DLL アンロード中にデストラクターを呼び出します。
WMI のグローバル オブジェクト内に収まるシンプルなクリーンアップ手順を次に示します。
class CMyCleanup
{
~CMyCleanup()
{
CloseHandle(m_hOpenFile);
CloseDatabaseConnection(g_hDatabase);
}
} g_Cleanup;
どちらの方法でもクリーンアップ コードで実行できる内容には、多くの制限があります。 たとえば、暗黙的にリンクされていないスレッドや DLL には、どのような方法でもアクセスできません。 また、どのような状況でも COM 呼び出しを行うことはできません。
関連トピック