HANDLER_FUNCTION_EX
コールバックシグネチャ
DWORD HANDLER_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 はエラーを返します。コントロールハンドラーの実行中に長時間の処理が必要な場合は、その処理を行うセカンダリスレッドを作成してから コントロールハンドラーを抜けてください。これにより、サービスがコントロールディスパッチャーを占有し、 他のサービスがコントロールコードを受け取れなくなることを防げます。
SERVICE_CONTROL_SHUTDOWN コントロールコードは、シャットダウン時にどうしてもクリーンアップが必要なサービスだけが 処理すべきです。サービスのシャットダウンに使える時間は限られている (約 20 秒) ためです。この時間が経過すると、 サービスのシャットダウンが完了しているかどうかに関わらず、システムのシャットダウンが進行します。なお、システムがシャットダウン状態のまま (再起動も電源オフもされずに) 残された場合、サービスは実行を継続します。サービスが SERVICE_CONTROL_SHUTDOWN を受け付けるよう登録した場合、そのコントロールコードを処理して NO_ERROR を返す必要があります。このコントロールコードに対してエラーを返し、速やかに停止しないと、システムのシャットダウンに要する時間が長くなる可能性があります。システムは、サービスのシャットダウンに許された時間が満了するまで待たなければ、システムのシャットダウンを進められないためです。
クリーンアップにさらに時間が必要な場合、サービスは待機ヒントを添えて STOP_PENDING 状態のメッセージを送信し、 サービスのシャットダウンが完了したとシステムに報告するまでにどれだけ待てばよいかを、サービスコントローラーに知らせてください。 ただし、サービスがシャットダウンを妨げないよう、サービスコントローラーが待機する時間には上限があります。サービススナップインからサービスをシャットダウンする場合、上限は 125 秒です。オペレーティングシステムが再起動する場合、制限時間は次のレジストリキーの WaitToKillServiceTimeout 値で指定されます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
プラグアンドプレイのデバイスイベントは、必ずできるだけ速やかに処理してください。そうしないと、システムが応答しなくなる 可能性があります。イベントハンドラーで実行をブロックする可能性のある操作 (I/O など) を行う場合は、別のスレッドを開始して 非同期に処理するのが最適です。
サービスは、SetConsoleCtrlHandler 関数を使用して シャットダウン通知を受け取ることもできます。この通知は、実行中のアプリケーションがシャットダウンするときに受け取ります。 これは、サービスがシャットダウンされる前に発生します。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)