共用方式為


準備除錯服務應用程式

本主題列出偵錯服務應用程式之前可能需要的所有準備工作。 案例中需要哪些步驟取決於您所選擇的附加選項,以及您選擇的偵錯組態。 如需這些選項的清單,請參閱 選擇對服務應用程式進行偵錯的最佳方法

本主題所述的每個準備步驟都會指定其必要條件。 這些步驟可以依任何順序完成。

啟用初始化程式代碼的偵錯

如果您打算從執行開始偵錯服務應用程式,包括其初始化程序代碼,則需要此準備步驟。

找出或建立下列登錄機碼,其中 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 必須指定 Windows 核心所實作的傳輸通訊協定,而不需與使用者模式服務互動,例如 TCP 或 NPIPE。 如需 ServerTransport 的語法,請參閱 啟用偵錯伺服器

  • 如果您打算從內核模式調試程式控制使用者模式調試程式,請使用 -d 選項指定 NTSD。 例如:

    c:\Debuggers\ntsd.exe -d -y SymbolPath 
    

    如果您打算使用此方法,而且使用者模式符號將從符號伺服器存取,您應該將此方法與遠端偵錯結合。 在此情況下,請使用 -ddefer 選項指定 NTSD。 選擇 Windows 核心所實作的傳輸通訊協定,而不與使用者模式服務互動,例如 TCP 或 NPIPE。 例如:

    c:\Debuggers\ntsd.exe -server ServerTransport -ddefer -y SymbolPath 
    

    如需詳細資訊,請參閱 從核心調試程式控制 User-Mode 調試程式

完成此登錄編輯之後,每當啟動或重新啟動具有此名稱的服務時,調試程式就會啟動。

讓服務應用程式進入調試程式

如果您希望服務應用程式在當機或遇到例外狀況時中斷調試程式,則需要此準備步驟。 如果您想要服務應用程式藉由呼叫 DebugBreak 函式來中斷調試程式,也需要此步驟。

注意 如果您已啟用初始化程式代碼的偵錯(啟用初始化程式代碼偵錯小節中所述的步驟),您應該略過此步驟。 啟用初始化代碼偵錯時,偵錯工具會在服務應用程式啟動時自動附加進去,這樣會導致所有崩潰、例外狀況及對 DebugBreak 的呼叫都自動路由至偵錯工具,無需額外準備。

這個準備步驟牽涉到將選定的調試程式註冊為死後調試器。 這是使用調試程式命令行上的 -iae 或 -iaec 選項來完成。 建議您使用下列命令,但如果您想要變更它們,請參閱 啟用事後偵錯中的語法詳情。

  • 如果您打算在本機除錯,請使用下列命令:

    windbg -iae 
    

    如果您正在執行 Windows Vista 或更新版本的 Windows,請勿選擇此選項。

  • 如果您打算使用遠端偵錯,請使用 -noio 選項指定 NTSD。 這會導致 NTSD 在沒有自己的任何控制台的情況下執行,且只能透過遠端連線存取。 若要安裝包含 -server 參數的驗屍調試程式,您必須手動編輯登錄;如需詳細資訊,請參閱 啟用事後偵錯。 例如,AeDebug 機碼的Debugger 值可能是以下內容:

    ntsd -server npipe:pipe=myproc%x -noio -p %ld -e %ld -g -y SymbolPath 
    

    在管線規格中, %x 令牌被替換為啟動偵錯工具的進程 ID。 這可確保如果多個進程啟動驗屍調試程式,則每個進程都有唯一的管道名稱。 如果您的偵錯會話在 Windows 完全載入之前開始,您可能無法從遠端共用存取符號。在這種情況下,您必須使用本機符號。 ServerTransport 必須指定 Windows 核心所實作的傳輸通訊協定,而不需與使用者模式服務互動,例如 TCP 或 NPIPE。 如需 ServerTransport 的語法,請參閱 啟用偵錯伺服器

  • 如果您打算從內核模式調試程式控制使用者模式調試程式,請使用 -d 選項指定 NTSD。 例如:

    ntsd -iaec -d -y SymbolPath 
    

    如果您選擇此方法,並想要從符號伺服器存取使用者模式符號,您應該將此方法與遠端偵錯結合。 在此情況下,請使用 -ddefer 選項指定 NTSD。 選擇 Windows 核心所實作的傳輸通訊協定,而不與使用者模式服務互動,例如 TCP 或 NPIPE。 若要安裝包含 -server 參數的驗屍調試程式,您必須手動編輯登錄;如需詳細資訊,請參閱 啟用事後偵錯。 例如,AeDebug 機碼的偵錯器值可能是如下:

    ntsd -server npipe:pipe=myproc%x -ddefer -p %ld -e %ld -g -y SymbolPath 
    

    如需詳細資訊,請參閱 從核心調試程式控制 User-Mode 調試程式

當您發出下列其中一個命令時,會註冊事後調試程式。 每當任何使用者模式程式,包括服務應用程式、遇到例外狀況或執行 DebugBreak 函式時,就會啟動此調試程式。

調整服務應用程式逾時時間設定

如果您打算自動啟動調試程式(服務啟動時或遇到例外狀況時),則需要此準備步驟。

找到下列登錄機碼:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

在此機碼下,找出或建立名為 ServicesPipeTimeout 的 DWORD 資料值。 將這個項目設定為您希望服務在逾時之前等候的時間量,以毫秒為單位。例如,值為 60,000 是一分鐘,而值為 86,400,000 則為 24 小時。 未設定此登錄值時,預設逾時約為 30 秒。

這個值的意義在於時鐘會在啟動每個服務時開始執行,而達到逾時值時,附加至服務的任何調試程式都會終止。 因此,您選擇的值應該比啟動服務與偵錯會話完成之間經過的總時間長度還要長。

此設定適用於登錄編輯完成後啟動或重新啟動的每個服務。 如果某些服務當機或停止回應,且此設定仍然有效,則 Windows 不會偵測到問題。 因此,您應該只在偵錯時使用此設定,並在偵錯完成之後,將登錄機碼傳回其原始值。

隔離服務

有時候,多個服務會在單一服務主機 (Svchost) 程序中合併。 如果您想要偵錯這類服務,您必須先將其隔離到個別的 Svchost 進程。

有三種方法可讓您隔離服務。 Microsoft建議將服務移至其自己的群組方法,如下所示。 替代方法(變更服務類型和複製 SvcHost 二進位檔)可以暫時用於偵錯,但因為它們會改變服務執行的方式,所以它們不如第一個方法那麼可靠。

慣用方法:將服務移至其自己的群組

  1. 發出下列服務組態工具 (Sc.exe) 命令,其中 ServiceName 是服務的名稱:

    sc qc ServiceName 
    

    這會顯示服務的目前組態值。 感興趣的值是BINARY_PATH_NAME,它會指定用來啟動服務控制程式的命令行。 在此案例中,由於您的服務尚未隔離,因此此命令行包含目錄路徑、Svchost.exe,以及一些 SvcHost 參數,包括 -k 參數,後面接著組名。 例如,它看起來可能像這樣:

    %SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork 
    

    請記住此路徑和組名;它們用於步驟 5 和 6。

  2. 找到下列登錄機碼:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost 
    

    建立具有唯一名稱的新REG_MULTI_SZ值(例如 TempGrp)。

  3. 將這個新值設定為等於您想要隔離的服務名稱。 請勿包含任何目錄路徑或擴展名。 例如,您可以將新值 TempGrp 設定為等於 MyService

  4. 在相同的登錄機碼下,使用您在步驟 2 中使用的相同名稱建立新的密鑰。 例如:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp 
    

    現在,SvcHost 索引鍵包含具有新名稱的值,而且具有同名的次級索引鍵。

  5. 尋找 SvcHost 金鑰下具有與您在步驟 1 中找到之群組相同名稱的另一個子金鑰。 如果存在這類索引鍵,請檢查其中的所有值,並在您在步驟 4 中建立的新索引鍵中建立這些值複本。

    例如,舊金鑰可能命名如下:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\LocalServiceNoNetwork 
    

    而且它可能包含 CoInitializeSecurityParamAuthenticationCapabilities 和其他值。 您會移至新建立的金鑰:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp 
    

    並建立與舊索引鍵中名稱、類型和數據相同的值。

    如果舊金鑰不存在,您就不需要建立新的金鑰。

  6. 使用下列服務組態工具命令來修改步驟 1 找到的路徑:

    sc config ServiceName binPath= "RevisedPath" 
    

    在此命令中, ServiceName 是服務的名稱, 而 RevisedPath 是您針對 BINARY_PATH_NAME 提供的新值。 針對 RevisedPath,請使用與步驟 1 中所顯示完全相同的路徑,包括該行上顯示的所有選項,只進行一項變更:以您在步驟 2 中建立的新登錄值名稱取代 -k 參數後面的參數。 以引號括住 RevisedPath 。 相等符號之後需要空格。

    例如,您的命令可能看起來會像這樣:

    sc config MyService binPath= "%SystemRoot%\System32\svchost.exe -k TempGrp" 
    

    您可能想要再次使用 sc qc 命令來檢閱您所做的變更。

這些設定會在下次啟動服務時生效。 若要清除舊服務的效果,建議您重新啟動 Windows,而不只是重新啟動服務。

完成偵錯之後,如果您想要將此服務傳回至共用服務主機,請再次使用 sc config 命令,將二進位路徑傳回其原始值,並刪除您建立的新登錄機碼和值。

替代方法:變更服務類型

  1. 發出下列服務組態工具 (Sc.exe) 命令,其中 ServiceName 是服務的名稱:

    sc config ServiceName type= own 
    

    相等符號之後需要空格。

  2. 使用下列命令重新啟動服務:

    net stop ServiceName 
    net start ServiceName 
    

這個替代方法不是建議的方法,因為它可以改變服務的行為。 如果您使用此方法,請在完成偵錯之後,使用下列命令還原為正常行為:

sc config ServiceName type= share 

替代方法:複製 SvcHost 二進位檔

  1. Svchost.exe 可執行文件位於 Windows 的 system32 目錄中。 製作此檔案的複本、將它命名為 svhost2.exe,並將它放在 system32 目錄中。

  2. 發出下列服務組態工具 (Sc.exe) 命令,其中 ServiceName 是服務的名稱:

    sc qc ServiceName 
    

    此命令會顯示服務的目前組態值。 感興趣的值是BINARY_PATH_NAME,它會指定用來啟動服務控制程式的命令行。 在此案例中,由於您的服務尚未隔離,因此此命令行會包含目錄路徑、Svchost.exe,以及一些 SvcHost 參數。 例如,它看起來可能像這樣:

    %SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork 
    
  3. 若要修改此路徑,請發出下列命令:

    sc config ServiceName binPath= "RevisedPath" 
    

    在此命令中, ServiceName 是服務的名稱, 而 RevisedPath 是您針對 BINARY_PATH_NAME 提供的新值。 針對 RevisedPath,請使用與步驟 2 中顯示的相同路徑,包括該行上顯示的所有選項,只進行一個變更:將 Svchost.exe 取代為 Svchost2.exe。 以引號括住 RevisedPath 。 相等符號之後需要空格。

    例如,您的命令可能看起來會像這樣:

    sc config MyService binPath= "%SystemRoot%\System32\svchost2.exe -k LocalServiceNoNetwork" 
    

    您可以再次使用 sc qc 命令來檢閱您所做的變更。

  4. 使用下列命令重新啟動服務:

    net stop ServiceName 
    net start ServiceName 
    

這個替代方法不是建議的方法,因為它可以改變服務的行為。 如果您使用此方法,請在完成偵錯之後,使用 sc config 命令將路徑變更回其原始值。