各サービスにはコントロール ハンドラー (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 を呼び出して返す必要があります。
ユーザーがシステムをシャットダウンすると、setServiceStatus 呼び出したすべてのコントロール ハンドラーが、SERVICE_ACCEPT_PRESHUTDOWN コントロール コードと共に、SERVICE_CONTROL_PRESHUTDOWN コントロール コードを受け取ります。 サービス コントロール マネージャーは、サービスが停止するか、指定されたプリシャットダウン タイムアウト値が期限切れになるまで待機します (この値は、ChangeServiceConfig2 関数で設定できます)。 この通知を処理するサービスは、サービスが停止するか、事前シャットダウンタイムアウト間隔が切れるまでシステムのシャットダウンをブロックするため、この制御コードは特別な状況でのみ使用する必要があります。
事前シャットダウン通知が完了すると、setServiceStatus 呼び出したすべてのコントロール ハンドラーが、SERVICE_ACCEPT_SHUTDOWN コントロール コードと共に、SERVICE_CONTROL_SHUTDOWN コントロール コードを受け取ります。 インストールされているサービスのデータベースに表示される順序で通知されます。 既定では、サービスは、システムがシャットダウンする前にクリーンアップ タスクを実行するのに約 20 秒です。 この時間が経過すると、サービスのシャットダウンが完了したかどうかに関係なく、システムのシャットダウンが続行されます。 システムがシャットダウン状態 (再起動または電源オフではない) のままになっている場合、サービスは引き続き実行されることに注意してください。
サービスのクリーンアップに必要な時間が長い場合は、STOP_PENDING ステータス メッセージと待機ヒントが送信されるため、サービス コントローラーは、サービスのシャットダウンが完了したことをシステムに報告するまでの待機時間を認識します。 ただし、サービスがシャットダウンを停止しないようにするには、サービス コントローラーが待機する時間に制限があります。 サービス スナップインを使用してサービスをシャットダウンする場合、制限は 125 秒 (125,000 ミリ秒) です。 オペレーティング システムが再起動する場合は、次のレジストリ キーの WaitToKillServiceTimeout 値 (ミリ秒) に制限時間が指定されます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
大事な
サービスでは、この値を変更して制限時間を増やさないでください。 WaitToKillServiceTimeout を手動で 設定する必要がある場合は、値をミリ秒単位にする必要があります。
お客様は、オペレーティング システムを高速にシャットダウンする必要があります。 たとえば、UPS 電源で実行されているコンピューターが、UPS の電源が切れる前にシャットダウンを完了できない場合、データが失われる可能性があります。 そのため、サービスはできるだけ早くクリーンアップ タスクを完了する必要があります。 データを定期的に保存し、ディスクに保存されているデータを追跡し、保存されていないデータをシャットダウン時にのみ保存することで、保存されていないデータを最小限に抑えるのが良い方法です。 コンピューターはシャットダウン中であるため、割り当てられたメモリやその他のシステム リソースの解放に時間を費やさないでください。 終了していることをサーバーに通知する必要がある場合は、ネットワークの問題によってサービスのシャットダウンが遅れる可能性があるため、応答の待機に費やされる時間を最小限に抑えます。
サービスのシャットダウン中、既定では、SCM は依存関係を考慮しないことに注意してください。 SCM は、実行中のサービスの一覧を列挙し、SERVICE_CONTROL_SHUTDOWN コマンドを送信します。 そのため、依存している別のサービスが既に停止しているため、サービスが失敗する可能性があります。
サービスのシャットダウン順序を手動で設定するには、次のように、サービス名を含む複数文字列レジストリ値をシャットダウンする必要がある順序で作成し、制御キーの PreshutdownOrder 値に割り当てます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PreshutdownOrder="Shutdown Order"
アプリケーションからの依存サービスのシャットダウン順序を設定するには、SetProcessShutdownParameters 関数を使用します。 SCM では、この関数を使用してハンドラー 0x1E0優先順位を指定します。 SCM は、コントロール ハンドラーが呼び出されたときに SERVICE_CONTROL_SHUTDOWN 通知を送信し、サービスが終了するまで待機してから、コントロール ハンドラーから戻ります。
関連トピック
-
コントロール ハンドラー関数 を記述する