準備偵錯服務應用程式
本主題列出偵錯服務應用程式之前可能需要的所有準備步驟。 您的案例中需要哪些步驟取決於您選擇的附加選項,以及您所選擇的偵錯組態。 如需這些選項的清單,請參閱 選擇最佳方法。
本主題所述的每個準備步驟都會指定其必要條件。 這些步驟可以依任何順序完成。
啟用初始化程式碼的偵錯
如果您打算從服務應用程式開始偵錯其執行,包括其初始化程式碼,則需要此準備步驟。
找出或建立下列登錄機碼,其中 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機碼的偵錯工具值可能如下:
ntsd -server npipe:pipe=myproc%x -noio -p %ld -e %ld -g -y SymbolPath
在管道規格中, %x 權杖會取代為啟動偵錯工具之進程的進程識別碼。 這可確保如果有多個進程啟動事後偵錯工具,則每個進程都有唯一的管道名稱。 如果您的偵錯會話在 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 二進位) 的替代方法可以暫時用於偵錯,但因為它們會改變服務執行的方式,所以它們不如第一個方法可靠。
慣用方法:將服務移至自己的群組
發出下列服務組態工具 (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
使用唯一名稱 (建立新的REG_MULTI_SZ值,例如 TempGrp) 。
將此新值設定為等於您要隔離的服務名稱。 請勿包含任何目錄路徑或副檔名。 例如,您可以將新的 值 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 中顯示的完全相同路徑,包括該行上顯示的所有選項,只進行一項變更:以您在步驟 2 中建立的新登錄值名稱取代 -k 參數後面的參數。 以引號括住 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 Binary
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 中所顯示完全相同的路徑,包括該行上顯示的所有選項,只進行一項變更:將 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 命令,在完成偵錯之後,將路徑變更回其原始值。