次の方法で共有


サービス コントロール ハンドラー関数

各サービスには、サービス プロセスがサービス コントロール プログラムから制御要求を受信したときにコントロール ディスパッチャーによって呼び出されるコントロール ハンドラーである Handler 関数があります。 したがって、この関数はコントロール ディスパッチャーのコンテキストで実行されます。 例については、「 コントロール ハンドラー関数の記述」を参照してください。

サービスは 、RegisterServiceCtrlHandler または RegisterServiceCtrlHandlerEx 関数を呼び出して、そのサービス コントロール ハンドラー関数を登録します。

サービス コントロール ハンドラーが呼び出されると、サービスは SetServiceStatus 関数を呼び出して、コントロール コードを処理してサービスの状態が変更された場合にのみ、その状態を SCM に報告する必要があります。 コントロール コードを処理してもサービスの状態が変更されない場合は、 SetServiceStatus を呼び出す必要はありません。

サービス制御プログラムは、 ControlService 関数を使用して制御要求を送信できます。 すべてのサービスは、 SERVICE_CONTROL_INTERROGATE 制御コードを受け入れて処理する必要があります。 SetServiceStatus を呼び出すことで、他のコントロール コードの受け入れを有効または無効にすることができます。 SERVICE_CONTROL_DEVICEEVENTコントロール コードを受信するには、RegisterDeviceNotification 関数を呼び出す必要があります。 サービスでは、追加のユーザー定義コントロール コードを処理することもできます。

サービスが SERVICE_CONTROL_STOP 制御コードを受け入れる場合は、受信時に停止し、 SERVICE_STOP_PENDING または SERVICE_STOPPED 状態に移動する必要があります。 SCM は、このコントロール コードを送信した後、他のコントロール コードを送信しません。

Windows XP: サービスが NO_ERROR を返し、引き続き実行する場合は、引き続き制御コードを受け取ります。 この動作は、Windows Server 2003 および Windows XP Service Pack 2 (SP2) 以降で変更されました。

コントロール ハンドラーは 30 秒以内にを返す必要があります。または、SCM からエラーが返されます。 サービスがコントロール ハンドラーの実行時に長い処理を実行する必要がある場合は、長い処理を実行するセカンダリ スレッドを作成してから、コントロール ハンドラーから戻る必要があります。 これにより、サービスがコントロール ディスパッチャーを同一化できなくなります。 たとえば、時間がかかるサービスの停止要求を処理する場合は、停止プロセスを処理する別のスレッドを作成します。 コントロール ハンドラーは、SERVICE_STOP_PENDING メッセージを使用して SetServiceStatus を呼び出して、 を返す必要があります。

ユーザーがシステムをシャットダウンすると、SERVICE_ACCEPT_PRESHUTDOWNコントロール コードを使用して SetServiceStatus を呼び出したすべてのコントロール ハンドラーは、SERVICE_CONTROL_PRESHUTDOWNコントロール コードを受け取ります。 サービス コントロール マネージャーは、サービスが停止するか、指定された事前シャットダウンタイムアウト値が期限切れになるまで待機します (この値は ChangeServiceConfig2 関数で設定できます)。 この制御コードは特別な状況でのみ使用する必要があります。これは、この通知を処理するサービスは、サービスが停止するか、事前シャットダウンタイムアウト間隔の有効期限が切れるまでシステムのシャットダウンをブロックするためです。

事前シャットダウン通知が完了すると、SERVICE_ACCEPT_SHUTDOWNコントロール コードで SetServiceStatus を呼び出したすべてのコントロール ハンドラーは、SERVICE_CONTROL_SHUTDOWNコントロール コードを受け取ります。 インストールされているサービスのデータベースに表示される順序で通知されます。 既定では、サービスは、システムがシャットダウンする前にクリーンアップ タスクを実行するのに約 20 秒です。 この時間が経過すると、サービスのシャットダウンが完了したかどうかに関係なく、システムのシャットダウンが続行されます。 システムがシャットダウン状態のまま (再起動または電源オフではない) 場合、サービスは引き続き実行されることに注意してください。

サービスのクリーンアップにさらに時間がかかる場合は、 STOP_PENDING ステータス メッセージと待機ヒントが送信されるため、サービス コントローラーは、サービスのシャットダウンが完了したことをシステムに報告するまでの待機時間を認識します。 ただし、サービスがシャットダウンを停止しないようにするには、サービス コントローラーが待機する時間に制限があります。 サービス スナップインを介してサービスがシャットダウンされている場合、制限は 125 秒 (125,000 ミリ秒) です。 オペレーティング システムが再起動中の場合、次のレジストリ キーの WaitToKillServiceTimeout 値 (ミリ秒単位) に制限時間が指定されます。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

重要

サービスでは、この値を変更して制限時間を増やさないでください。 WaitToKillServiceTimeout を手動で設定する必要がある場合、値はミリ秒単位である必要があります。

お客様は、オペレーティング システムの高速シャットダウンが必要です。 たとえば、UPS 電源で実行されているコンピューターが、UPS の電源が切れる前にシャットダウンを完了できない場合、データが失われる可能性があります。 そのため、サービスはできるだけ早くクリーンアップ タスクを完了する必要があります。 定期的にデータを保存し、ディスクに保存されたデータを追跡し、保存されていないデータをシャットダウン時にのみ保存することで、保存されていないデータを最小限に抑えるのが良い方法です。 コンピューターはシャットダウン中であるため、割り当てられたメモリやその他のシステム リソースの解放に時間を費やさないでください。 終了していることをサーバーに通知する必要がある場合は、ネットワークの問題によってサービスのシャットダウンが遅れる可能性があるため、応答の待機に費やされる時間を最小限に抑えます。

サービスのシャットダウン中、既定では、SCM は依存関係を考慮しないことに注意してください。 SCM は実行中のサービスの一覧を列挙し、 SERVICE_CONTROL_SHUTDOWN コマンドを送信します。 そのため、依存する別のサービスが既に停止しているため、サービスが失敗する可能性があります。

サービスのシャットダウン順序を手動で設定するには、サービス名を含む複数文字列レジストリ値をシャットダウンする順序で作成し、次のように Control キーの PreshutdownOrder 値に割り当てます。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PreshutdownOrder="Shutdown Order"

アプリケーションから依存サービスのシャットダウン順序を設定するには、 SetProcessShutdownParameters 関数を使用します。 SCM は、この関数を使用して、ハンドラー 0x1E0優先度を設定します。 SCM は、コントロール ハンドラーが呼び出されたときに SERVICE_CONTROL_SHUTDOWN 通知を送信し、サービスが終了するまで待機してから、コントロール ハンドラーから戻ります。

コントロール ハンドラー関数の記述