2010-05-21 96 views

回答

6

是的,有: Debugging services: an easy way

你用Delphi創建服務? 那麼也許你也在煩惱 耗時的啓動方式, 重啓,查殺和附加到 服務進程申請每 時間。那麼,有補救措施。

您不需要這樣做。而是運行 德爾福作爲一個系統應用程序,並做 一些小的適應服務 代碼。

+0

RunAsSys聽起來不錯。您鏈接的文章中的示例代碼使用條件定義來選擇「模式」。你知道RunAsSys是否允許選擇調試模式而不必重建應用程序?即使用命令行參數進入調試模式,而不是作爲服務運行? – 2010-05-21 19:43:54

+0

我不確定,但是您似乎可以自己添加該功能。 – Mick 2010-05-24 14:03:03

3

是的。

在您的DPR:

Application.CreateForm(TMyService, MyService); 

_ServiceInDebugMode := SysUtils.FindCmdLineSwitch('DEBUG', True); 
if _ServiceInDebugMode then 
    DebugService(MyService) 
else 
    SvcMgr.Application.Run; 

DebugService是創建調試形式,業務控制線程,並通過調用Forms.Application.Run揭開序幕一切的過程。

您可以將服務控制線程與Windows的SCM(服務控制管理器)進行比較,調試窗體中包含與SCM進行通信的應用程序(例如services.msc)以啓動和停止服務。該服務還應該有自己的線程(服務線程)來響應來自SCM或我們的服務控制線程的控制代碼以及一個或多個單獨的線程來完成其實際工作。你希望單獨的線程用於實際的工作(而不是在TService後裔的事件處理程序中編碼),以確保TService自身運行的線程始終可以自由地響應來自SCM的控制代碼,並且仍然可以停止並即使每工作者線程凍結的機會也會啓動服務。

該方法允許您調試服務應用程序代碼,但涉及相當數量的代碼,並將幾個掛鉤放入Windows API函數中以正常工作。在短時間內顯示在這裏太多了。也許我會在一天的文章中寫下它。與此同時,如果你不想自己編碼,你有兩種選擇。或者去SVCOM這樣的庫,或者Mick提到的那個庫,它們都是爲你做的,或者是在調試模式下繞過服務代碼,然後「簡單」地將服務作爲「普通」表單應用程序啓動。你將不得不從你的TService後代的代碼/事件處理程序中分離出你的服務的真正功能,但是由於上述原因,我推薦這麼做。

+0

我有與表單和服務相同的應用程序。使用表單工作。有了服務,它不起作用。 – 2010-05-24 12:10:15

+0

@Marjan Venema DebugService位於哪個單元? – 2017-10-12 23:54:26

+0

@SpongebobComrade沒有。這是你自己寫的東西。守則第一段提到它應該做的事。查看其他答案以獲取更多信息。 – 2017-10-13 12:40:35

25

您可以從Colin Wilson's NT Low Level Utilities(網頁已不復存在,available in the wayback machine

使用unitDebugService.pas然後在DPR:

begin 
    if (paramCount > 0) and (SameText(ParamStr(1), '-DEBUG')) then 
    begin 
    FreeAndNil (Application); 
    Application := TDebugServiceApplication.Create(nil); 
    end; 

    //... the rest of the normal DPR code 
end. 

這樣你就可以從內部德爾福調試運行(通過設置項目調試器參數),使用EXE作爲服務,或者使用-DEBUG開關和命令行運行。

13

使用運行 - >附加到進程。通過這種方式,您可以在不對代碼進行任何更改的情況下調試服務。唯一棘手的部分可能是調試服務啓動代碼,因爲連接可能需要一些時間,並且啓動必須在30幾秒內發生(儘管您可以調整Windows以允許更長的時間)。您可以使用延遲(sleep ...)讓您及時附加,或者如果您只需要查看可以使用OutputDebugString()打印到調試輸出(使用Delphi事件視圖來查看它)會發生什麼情況。

+0

我試過這個,但只出現了彙編代碼的cpu窗口。 – 2010-05-24 12:06:09

+0

'附加到進程'工作正常。當調試器第一次連接到服務進程時,CPU窗口確實出現,但您可以簡單地關閉它,然後按F9或運行按鈕繼續正常執行服務,然後像其他任何項目一樣調試其代碼。 – 2013-11-21 18:53:16

+1

這工作正常。如果您不希望CPU窗口彈出,您可以取消選中「附加後暫停」複選框。 – GolezTrol 2013-12-18 14:34:18

5

我試過這個,但只出現與彙編代碼的cpu窗口。

那麼你只應該解決這個問題。

基本上,調試WIN2服務,有幾種方法:

  • 使用「附加到進程」命令附加調試器已經在運行的服務。如果您需要在開始時附加,您可以插入啓動延遲以有時間附加調試器。但是,您還必須調整系統以增加服務超時。
  • 使用"Image File Execution Options" registry key在服務啓動時強制運行Delphi的調試器。有關係統超時的相同考慮也適用。
  • 臨時將服務轉換爲常用應用程序,並在調試器中正常運行。您可以在不同的用戶帳戶下重新啓動IDE,以獲得更多的「服務」權限。

如果由於某種原因,在開始調試後,CPU只能查看服務的CPU視圖 - 這意味着Delphi的調試器無法爲您的服務找到調試信息。這是一個不同的問題,你應該爲它尋找解決方案。

通常情況下,你需要做的:

  1. 確保輸出文件夾爲您服務應用程序設置爲文件夾,從中將由系統加載。即如果您的服務位於C:\ Windows \ System32 - 然後將輸出文件夾設置爲C:\ Windows \ System32。不要從輸出文件夾的其他位置複製.exe文件。對於64個系統,您可以嘗試別名(sysnative/SysWOW64)或真實姓名。我認爲最好將輸出路徑設置爲項目文件夾,並重新註冊從項目文件夾加載的服務。
  2. (可選)將DCU的輸出路徑設置爲與.exe文件相同的文件夾。
  3. 刪除所有的DCU文件。
  4. 確保在項目選項的「編譯器」頁面上啓用調試選項。
  5. (可選)此外,您還可以在「鏈接器」頁面上包含TD32/RSM/MAP選項。
  6. 確保沒有IDE專家/擴展程序,它可能會修改這些文件的.exe文件,調試信息或文件修改日期。
  7. 確保在其他位置沒有舊文件(DCU/exe)。
  8. 進行完全重建(項目/全部構建)。
  9. 運行您的服務。
+0

這種方法工作得很好。 – Turrican 2015-05-26 12:22:55

13

這其實很簡單。只需使用標準DEBUG編譯器指令即可啓動該服務作爲控制檯應用程序而不是服務。

program MyServiceApp; 

{$ifdef DEBUG} 
    {$APPTYPE CONSOLE} 
{$endif} 

uses 
    System.SysUtils, 

[..]

begin 
    {$ifdef DEBUG} 
    try 
    // In debug mode the server acts as a console application. 
    WriteLn('MyServiceApp DEBUG mode. Press enter to exit.'); 

    // Create the TService descendant manually. 
    ServerContainer1 := TServerContainer.Create(nil); 

    // Simulate service start. 
    ServerContainer1.ServiceStart(ServerContainer1, MyDummyBoolean); 

    // Keep the console box running (ServerContainer1 code runs in the background) 
    ReadLn; 

    // On exit, destroy the service object. 
    FreeAndNil(ServerContainer1); 
    except 
    on E: Exception do 
    begin 
     Writeln(E.ClassName, ': ', E.Message); 
     WriteLn('Press enter to exit.'); 
     ReadLn; 
    end; 
    end; 
    {$else} 
    // Run as a true windows service (release). 
    if not Application.DelayInitialize or Application.Installing then 
    Application.Initialize; 
    Application.CreateForm(TServerContainer, ServerContainer1); 
    Application.Run; 
    {$endif} 
end. 
+0

這是一個很好的方法!我們需要寫代碼,真的,但沒有第三部分單位,功能或複雜的Windows註冊表配置 – 2015-12-10 20:09:40

+0

exacly我正在尋找。謝謝。 upvoted。 – 2016-09-02 12:38:17