サービス アプリケーションのデバッグの準備
このトピックでは、サービス アプリケーションをデバッグする前に必要になる可能性がある準備手順をすべて示します。 シナリオで必要な手順は、選択したアタッチ オプションと選択したデバッグ構成によって異なります。 これらの選択肢の一覧については、「 最適な方法の選択」を参照してください。
このトピックで説明する各準備手順では、必要な条件を指定します。 これらの手順は任意の順序で実行できます。
初期化コードのデバッグの有効化
初期化コードを含め、実行の開始時からサービス アプリケーションをデバッグする予定の場合は、この準備手順が必要です。
次のレジストリ キーを探すか作成します。 ProgramName はサービス アプリケーションの実行可能ファイルの名前です。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ProgramName
ProgramName にはファイル名拡張子を含める必要がありますが、パスは含めません。 たとえば、 ProgramName はMyservice.exeまたはThisservice.dll。
このレジストリ キーの下に、 Debugger という名前の文字列データ値を 作成します。 この文字列の値は、サービス アプリケーションにアタッチするデバッガーの完全なパスとファイル名に設定する必要があります。
ローカルでデバッグする場合は、次のような文字列を使用します。
c:\Debuggers\windbg.exe
Windows Vista 以降のバージョンの Windows を実行している場合は、このオプションを選択しないでください。
リモート デバッグを使用する場合は、-noio オプションを指定して NTSD を指定します。 これにより、NTSD は独自のコンソールなしで実行され、リモート接続経由でのみアクセスできます。 次に例を示します。
c:\Debuggers\ntsd.exe -server ServerTransport -noio -y SymbolPath
Windows が完全に読み込まれる前にデバッグ セッションが開始されると、リモート共有からシンボルにアクセスできない可能性があります。このような場合は、ローカル シンボルを使用する必要があります。 ServerTransport では、TCP や NPIPE などのユーザー モード サービスとやり取りせずに、Windows カーネルによって実装されるトランスポート プロトコルを指定する必要があります。 ServerTransport の構文については、「 デバッグ サーバーのアクティブ化」を参照してください。
カーネル モード デバッガーからユーザー モード デバッガーを制御する場合は、-d オプションを指定して NTSD を指定します。 次に例を示します。
c:\Debuggers\ntsd.exe -d -y SymbolPath
このメソッドを使用する予定で、シンボル サーバーからユーザー モード シンボルにアクセスする場合は、このメソッドをリモート デバッグと組み合わせる必要があります。 この場合は、-ddefer オプションを指定して NTSD を指定します。 TCP や NPIPE などのユーザー モード サービスとインターフェイスせずに、Windows カーネルによって実装されるトランスポート プロトコルを選択します。 次に例を示します。
c:\Debuggers\ntsd.exe -server ServerTransport -ddefer -y SymbolPath
詳細については、「 カーネル デバッガー からのユーザーモード デバッガーの制御」を参照してください.
このレジストリの編集が完了すると、この名前のサービスが開始または再起動されるたびにデバッガーが起動します。
サービス アプリケーションがデバッガーに侵入できるようにする
サービス アプリケーションがクラッシュしたとき、または例外が発生したときにデバッガーに中断させる場合は、この準備手順が必要です。 この手順は、 DebugBreak 関数を呼び出してサービス アプリケーションをデバッガーに分割する場合にも必要です。
注 初期化コードのデバッグを有効にしている場合 (「初期化コードのデバッグを有効にする」のサブセクションで説明されている手順) は、この手順をスキップする必要があります。 初期化コードのデバッグが有効になっている場合、デバッガーは起動時にサービス アプリケーションにアタッチされます。これにより、すべてのクラッシュ、例外、および DebugBreak の呼び出しが、追加の準備を必要とせずにデバッガーにルーティングされます。
この準備手順では、選択したデバッガーを事後デバッガーとして登録します。 これは、デバッガーのコマンド ラインで -iae または -iaec オプションを使用して行います。 次のコマンドをお勧めしますが、変更する場合は、「 事後デバッグの有効化」の構文の詳細を参照してください。
ローカルでデバッグする場合は、次のようなコマンドを使用します。
windbg -iae
Windows Vista 以降のバージョンの Windows を実行している場合は、このオプションを選択しないでください。
リモート デバッグを使用する場合は、-noio オプションを指定して NTSD を指定します。 これにより、NTSD は独自のコンソールなしで実行され、リモート接続経由でのみアクセスできます。 -server パラメーターを含む事後デバッガーをインストールするには、レジストリを手動で編集する必要があります。 詳細については、「 事後デバッグの有効化」を参照してください。 たとえば、 AeDebug キーの デバッガー 値は次のようになります。
ntsd -server npipe:pipe=myproc%x -noio -p %ld -e %ld -g -y SymbolPath
パイプ仕様では、 %x トークンはデバッガーを起動するプロセスのプロセス ID に置き換えられます。 これにより、複数のプロセスが事後デバッガーを起動した場合、それぞれが一意のパイプ名を持つことになります。 Windows が完全に読み込まれる前にデバッグ セッションが開始されると、リモート共有からシンボルにアクセスできない可能性があります。このような場合は、ローカル シンボルを使用する必要があります。 ServerTransport では、TCP や NPIPE などのユーザー モード サービスとやり取りせずに、Windows カーネルによって実装されるトランスポート プロトコルを指定する必要があります。 ServerTransport の構文については、「 デバッグ サーバーのアクティブ化」を参照してください。
カーネル モード デバッガーからユーザー モード デバッガーを制御する場合は、-d オプションを指定して NTSD を指定します。 次に例を示します。
ntsd -iaec -d -y SymbolPath
この方法を選択し、シンボル サーバーからユーザー モード シンボルにアクセスする場合は、このメソッドをリモート デバッグと組み合わせる必要があります。 この場合は、-ddefer オプションを指定して NTSD を指定します。 TCP や NPIPE などのユーザー モード サービスとインターフェイスせずに、Windows カーネルによって実装されるトランスポート プロトコルを選択します。 -server パラメーターを含む事後デバッガーをインストールするには、レジストリを手動で編集する必要があります。 詳細については、「 事後デバッグの有効化」を参照してください。 たとえば、 AeDebug キーの デバッガー 値は次のようになります。
ntsd -server npipe:pipe=myproc%x -ddefer -p %ld -e %ld -g -y SymbolPath
詳細については、「 カーネル デバッガー からのユーザーモード デバッガーの制御」を参照してください.
これらのコマンドのいずれかを発行すると、事後分析デバッガーが登録されます。 このデバッガーは、サービス アプリケーションを含むユーザー モード プログラムが例外を検出するか、 DebugBreak 関数を実行するたびに起動されます。
サービス アプリケーションのタイムアウトの調整
デバッガーを自動的に起動する場合 (サービスの起動時または例外が発生した場合)、この準備手順が必要です。
次のレジストリ キーを見つけます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
このキーの下で、 ServicesPipeTimeout という DWORD データ値を見つけるか、作成します。 このエントリを、サービスがタイムアウトするまで待機する時間 (ミリ秒単位) に設定します。たとえば、値 60,000 は 1 分で、値 86,400,000 は 24 時間です。 このレジストリ値が設定されていない場合、既定のタイムアウトは約 30 秒です。
この値の意味は、各サービスが起動されたときにクロックの実行が開始され、タイムアウト値に達すると、サービスにアタッチされているデバッガーが終了することです。 そのため、選択する値は、サービスの起動からデバッグ セッションの完了までの合計時間よりも長くする必要があります。
この設定は、レジストリの編集が完了した後に開始または再起動されるすべてのサービスに適用されます。 一部のサービスがクラッシュまたはハングしてもこの設定が有効な場合、Windows では問題は検出されません。 そのため、この設定はデバッグ中にのみ使用し、デバッグが完了した後にレジストリ キーを元の値に戻す必要があります。
サービスの分離
1 つのサービス ホスト (Svchost) プロセスで複数のサービスが結合される場合があります。 このようなサービスをデバッグする場合は、最初に別の Svchost プロセスに分離する必要があります。
サービスを分離するには、3 つの方法があります。 Microsoft では、次のように、サービスを独自のグループに移動する方法をお勧めします。 別の方法 (サービスの種類の変更と SvcHost バイナリの複製) は、デバッグのために一時的に使用できますが、サービスの実行方法が変更されるため、最初の方法ほど信頼性が高くはありません。
推奨される方法: サービスを独自のグループに移動する
次のサービス構成ツール (Sc.exe) コマンドを発行します ServiceName はサービスの名前です。
sc qc ServiceName
これにより、サービスの現在の構成値が表示されます。 目的の値はBINARY_PATH_NAMEであり、サービス制御プログラムの起動に使用されるコマンド ラインを指定します。 このシナリオでは、サービスがまだ分離されていないため、このコマンド ラインにはディレクトリ パス、Svchost.exe、一部の SvcHost パラメーター (-k スイッチを含む)、その後にグループ名が含まれます。 たとえば、次のようになります:
%SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork
このパスとグループ名を覚えておいてください。これらは、手順 5 と 6 で使用されます。
次のレジストリ キーを見つけます。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost
一意の名前 ( TempGrpなど) を使用して新しいREG_MULTI_SZ値を作成します。
この新しい値は、分離するサービスの名前と同じ値に設定します。 ディレクトリ パスまたはファイル名拡張子は含めないでください。 たとえば、新しい値 TempGrp を MyService に設定できます。
同じレジストリ キーの下に、手順 2 で使用したのと同じ名前の新しいキーを作成します。 次に例を示します。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp
これで、SvcHost キーに新しい名前の値が含まれるようになり、この同じ名前の下位キーも含まれます。
手順 1 で見つけたグループと同じ名前の SvcHost キーの下位にある別のキーを探します。 このようなキーが存在する場合は、その中のすべての値を調べて、手順 4 で作成した新しいキーでそれらの重複を作成します。
たとえば、古いキーの名前は次のようになります。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\LocalServiceNoNetwork
また、 CoInitializeSecurityParam、 AuthenticationCapabilities、その他の値が含まれている場合があります。 新しく作成されたキーに移動します。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp
名前、型、データと古いキーの値と同じ値を作成します。
古いキーが存在しない場合は、新しいキーを作成する必要はありません。
次のサービス構成ツール コマンドを使用して、手順 1 で見つかったパスを変更します。
sc config ServiceName binPath= "RevisedPath"
このコマンドでは、 ServiceName はサービスの名前であり 、 RevisedPath はBINARY_PATH_NAMEに指定する新しい値です。 RevisedPath の場合は、手順 1 で表示したものとまったく同じパスを使用します。その行に表示されるすべてのオプションを含めて、1 つの変更のみを行います。-k スイッチの後のパラメーターを、手順 2 で作成した新しいレジストリ値の名前に置き換えます。 RevisedPath を引用符で囲みます。 等号の後のスペースは必須です。
たとえば、コマンドは次のようになります。
sc config MyService binPath= "%SystemRoot%\System32\svchost.exe -k TempGrp"
sc qc コマンドをもう一度使用して、行った変更を確認することができます。
これらの設定は、次回サービスが開始されたときに有効になります。 古いサービスの影響をクリアするには、サービスを再起動するのではなく、Windows を再起動することをお勧めします。
デバッグが完了したら、このサービスを共有サービス ホストに返す場合は、 sc config コマンドをもう一度使用してバイナリ パスを元の値に戻し、作成した新しいレジストリ キーと値を削除します。
代替方法: サービスの種類を変更する
次のサービス構成ツール (Sc.exe) コマンドを発行します ServiceName はサービスの名前です。
sc config ServiceName type= own
等号の後のスペースは必須です。
次のコマンドを使用してサービスを再起動します。
net stop ServiceName net start ServiceName
この代替方法は、サービスの動作を変更する可能性があるため、推奨される方法ではありません。 このメソッドを使用する場合は、デバッグが完了した後、次のコマンドを使用して通常の動作に戻します。
sc config ServiceName type= share
別の方法: SvcHost バイナリの複製
Svchost.exe実行可能ファイルは、Windows の system32 ディレクトリにあります。 このファイルのコピーを作成し、svhost2.exe名前を付け、system32 ディレクトリにも配置します。
次のサービス構成ツール (Sc.exe) コマンドを発行します ServiceName はサービスの名前です。
sc qc ServiceName
このコマンドは、サービスの現在の構成値を表示します。 目的の値はBINARY_PATH_NAMEであり、サービス制御プログラムの起動に使用されるコマンド ラインを指定します。 このシナリオでは、サービスがまだ分離されていないため、このコマンド ラインにはディレクトリ パス、Svchost.exe、およびおそらくいくつかの SvcHost パラメーターが含まれます。 たとえば、次のようになります:
%SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork
このパスを修正するには、次のコマンドを発行します。
sc config ServiceName binPath= "RevisedPath"
このコマンドでは、 ServiceName はサービスの名前であり 、 RevisedPath はBINARY_PATH_NAMEに指定する新しい値です。 RevisedPath の場合は、手順 2 で表示したものとまったく同じパスを使用します。その行に表示されるすべてのオプションを含めて、変更を 1 つだけ行います。Svchost.exeを Svchost2.exe に置き換えます。 RevisedPath を引用符で囲みます。 等号の後のスペースは必須です。
たとえば、コマンドは次のようになります。
sc config MyService binPath= "%SystemRoot%\System32\svchost2.exe -k LocalServiceNoNetwork"
sc qc コマンドを再度使用して、行った変更を確認できます。
次のコマンドを使用してサービスを再起動します:
net stop ServiceName net start ServiceName
この代替方法は、サービスの動作を変更する可能性があるため、推奨される方法ではありません。 このメソッドを使用する場合は、 sc config コマンドを使用して、デバッグが完了した後、パスを元の値に戻します。