LPHANDLER_FUNCTION_EX
コールバックシグネチャ
DWORD LPHANDLER_FUNCTION_EX(
DWORD dwControl,
DWORD dwEventType,
void* lpEventData,
void* lpContext
);パラメーター
| フィールド | 型 | 説明 | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| dwControl | DWORD | コントロールコードです。このパラメーターには、次のいずれかの値を指定できます。
このパラメーターには、次の拡張コントロールコードのいずれかを指定することもできます。これらのコントロールコードは Handler 関数ではサポートされない点に注意してください。
このパラメーターには、次の表に示すとおり、ユーザー定義のコントロールコードを指定することもできます。
| ||||||||||||||||||||||||||||||||||||||||||||
| dwEventType | DWORD | 発生したイベントの種類です。このパラメーターは、dwControl が SERVICE_CONTROL_DEVICEEVENT、SERVICE_CONTROL_HARDWAREPROFILECHANGE、SERVICE_CONTROL_POWEREVENT、または SERVICE_CONTROL_SESSIONCHANGE の場合に使用されます。それ以外の場合は 0 です。 dwControl が SERVICE_CONTROL_DEVICEEVENT の場合、このパラメーターには次のいずれかの値を 指定できます。
dwControl が SERVICE_CONTROL_SESSIONCHANGE の場合、このパラメーターには WM_WTSSESSION_CHANGE メッセージの wParam パラメーターで 指定される値のいずれかを指定できます。 | ||||||||||||||||||||||||||||||||||||||||||||
| lpEventData | void* | 必要に応じて渡される、追加のデバイス情報です。このデータの形式は、 dwControl パラメーターおよび dwEventType パラメーターの値によって異なります。 dwControl が SERVICE_CONTROL_DEVICEEVENT の場合、このデータは、アプリケーションが WM_DEVICECHANGE メッセージの一部として受け取る lParam パラメーターに対応します。 dwControl が SERVICE_CONTROL_POWEREVENT で、dwEventType が PBT_POWERSETTINGCHANGE の場合、このデータは POWERBROADCAST_SETTING 構造体へのポインターです。 dwControl が SERVICE_CONTROL_SESSIONCHANGE の場合、このパラメーターは WTSSESSION_NOTIFICATION 構造体へのポインターです。 dwControl が SERVICE_CONTROL_TIMECHANGE の場合、このデータは SERVICE_TIMECHANGE_INFO 構造体へのポインターです。 | ||||||||||||||||||||||||||||||||||||||||||||
| lpContext | void* | RegisterServiceCtrlHandlerEx から渡されるユーザー定義のデータです。 複数のサービスが 1 つのプロセスを共有している場合、lpContext パラメーターはサービスを識別するのに 役立ちます。 |
公式ドキュメント
アプリケーション定義のコールバック関数で、 RegisterServiceCtrlHandlerEx 関数と共に使用されます。サービスプログラムは、 これを特定のサービスのコントロールハンドラー関数として使用できます。
LPHANDLER_FUNCTION_EX 型は、この関数へのポインターを定義します。 HandlerEx は、アプリケーション定義の名前を表すプレースホルダーです。
この関数は、RegisterServiceCtrlHandler 関数と共に使用される Handler コントロールハンドラー関数に代わるものです。 サービスはどちらのコントロールハンドラーも使用できますが、新しいコントロールハンドラーはユーザー定義のコンテキストデータと 追加の拡張コントロールコードをサポートします。
戻り値
この関数の戻り値は、受け取ったコントロールコードによって異なります。
戻り値の規則は次のとおりです。
- 一般に、サービスがそのコントロールを処理しない場合は ERROR_CALL_NOT_IMPLEMENTED を返します。ただし SERVICE_CONTROL_INTERROGATE については、サービスが処理しない場合でも NO_ERROR を返してください。
- サービスが SERVICE_CONTROL_STOP または SERVICE_CONTROL_SHUTDOWN を処理する場合は、NO_ERROR を返します。
- サービスが SERVICE_CONTROL_DEVICEEVENT を処理する場合は、要求を許可するときは NO_ERROR を、拒否するときはエラー コードを返します。
- サービスが SERVICE_CONTROL_HARDWAREPROFILECHANGE を処理する場合は、要求を許可するときは NO_ERROR を、 拒否するときはエラーコードを返します。
- サービスが SERVICE_CONTROL_POWEREVENT を処理する場合は、要求を許可するときは NO_ERROR を、拒否するときはエラー コードを返します。
- サービスが処理するその他すべてのコントロールコードについては、NO_ERROR を返します。
解説(Remarks)
サービスが開始されると、その ServiceMain 関数は 直ちに RegisterServiceCtrlHandlerEx 関数を呼び出して、コントロール要求を処理する HandlerEx 関数を指定する必要があります。受け付けるコントロールコードを 指定するには、SetServiceStatus 関数および RegisterDeviceNotification 関数を使用します。
サービスのメインスレッドにあるコントロールディスパッチャーは、サービスコントロールマネージャーからコントロール要求を受け取るたびに、 指定されたサービスのコントロールハンドラー関数を呼び出します。コントロール要求の処理後、サービスの状態が変化した場合、 コントロールハンドラーは SetServiceStatus を呼び出して、 新しい状態をサービスコントロールマネージャーに報告する必要があります。
コントロールハンドラー関数は、通知を受け取ったら直ちに制御を返すことを想定しています。 このコールバック関数はパラメーターを保存し、追加の処理を行う別のスレッドを作成するようにしてください。(アプリケーションは、 サービスを停止する前にそれらのスレッドが終了していることを保証する必要があります。) 特に、コントロールハンドラーではロックの取得など、 ブロックする可能性のある操作を避けてください。デッドロックを招いたり、システムが応答しなくなったりするおそれがあります。
サービスコントロールマネージャーは、サービスにコントロールコードを送信すると、他のサービスへ追加のコントロールコードを送信する前に、 ハンドラー関数が戻るのを待ちます。コントロールハンドラーはできるだけ早く制御を返す必要があります。30 秒以内に戻らない場合、SCM はエラーを返します。コントロールハンドラーの実行中にサービスが長時間の処理を行う必要がある場合は、 二次スレッドを作成してその処理を実行し、コントロールハンドラーからはすぐに戻るようにしてください。これにより、サービスが コントロールディスパッチャーを占有し、他のサービスがコントロールコードを受け取れなくなることを防げます。
サービスのシャットダウンに使用できる時間は限られている (約 20 秒) ため、SERVICE_CONTROL_SHUTDOWN コントロールコードは、 シャットダウン中にどうしてもクリーンアップが必要なサービスだけが処理するようにしてください。この 時間が経過すると、サービスのシャットダウンが完了しているかどうかにかかわらず、システムのシャットダウンが進行します。なお、システムが シャットダウン状態のまま (再起動も電源切断もされずに) 置かれた場合、サービスは実行され続けます。サービスが SERVICE_CONTROL_SHUTDOWN を受け付けるよう登録している場合は、このコントロールコードを処理して NO_ERROR を返す必要があります。このコントロールコードに対してエラーを返し、速やかに停止しないと、システムはサービスのシャットダウンに許された時間が満了するまで待たなければシステムのシャットダウンを進められないため、システムのシャットダウンに要する時間が長くなる可能性があります。
クリーンアップにさらに時間が必要な場合、サービスは待機ヒントを伴う STOP_PENDING 状態メッセージを送信し、 サービスコントローラーが、サービスのシャットダウン完了をシステムに報告するまでどれだけ待つべきかを把握できるようにしてください。 ただし、サービスによってシャットダウンが妨げられないように、サービスコントローラーが待機する時間には上限があります。 「サービス」スナップインからサービスをシャットダウンする場合、上限は 125 秒です。オペレーティングシステムを再起動している場合、制限時間は次のレジストリキーの WaitToKillServiceTimeout 値で指定されます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
プラグアンドプレイのデバイスイベントは、必ずできるだけ迅速に処理してください。そうしないと、システムが応答しなくなる 可能性があります。イベントハンドラーで実行がブロックされる可能性のある操作 (I/O など) を行う場合は、別のスレッドを開始して 非同期に実行するのが最善です。
サービスは、SetConsoleCtrlHandler 関数を使用して シャットダウン通知を受け取ることもできます。この通知は、実行中のアプリケーションがシャットダウンするときに受け取られます。これは サービスがシャットダウンされる前に発生します。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)