簡體   English   中英

如何重新啟動用 Delphi 編寫的 Windows 服務應用程序?

[英]How can I restart a Windows service application written in Delphi?

我有一個用 Delphi 編寫的 Windows 服務。 它使用的第三方資源之一偶爾會損壞,我發現解決這種情況的唯一方法是退出並重新啟動程序。 我可以從程序中檢測到資源何時損壞,我可以告訴 Windows 在服務停止后重新啟動服務,但我不知道如何讓服務告訴自己停止。

該程序非常簡單。 我以看似正常的方式創建了一個服務應用程序。 我有一個 TService 的子類來管理服務,而所有功能都發生在一個單獨的線程中。 TService 子類幾乎只是管理子線程的執行,我將在子線程中檢測損壞。

作為參考,這里是服務和子線程的 header 信息。

type
  TScannerThread = class(TThread)
   private     
    Scanner    : TScanner;
    DefaultDir : String;
    ImageDir   : String;
    procedure CheckScanner;
   public      
    Parent     : TComponent;
    procedure Execute; override;
  end;         

  TCardScanSvc   = class(TService)
    procedure ServiceCreate(Sender: TObject);
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServicePause(Sender: TService; var Paused: Boolean);
    procedure ServiceContinue(Sender: TService; var Continued: Boolean);
   private        
    ScannerThread : TScannerThread;
   public         
    function GetServiceController: TServiceController; override;
  end;            

var
  CardScanSvc : TCardScanSvc;

在 GUI 應用程序中,我會調用 Application.Terminate,但 TServiceApplication 似乎沒有該方法。 我可以終止子線程,但主線程永遠不會注意到,Windows 認為服務仍在運行。 我真的想不出還有什么可以嘗試的。

該程序最初是在 Delphi 5 中創建的,我目前正在使用 Delphi 2007,以防萬一。


編輯:

使用mghie的代碼,我可以停止服務,但是Windows只會在意外失敗的情況下重新啟動服務,而不是在正常停止的情況下。 我要做的是制作一個單獨的服務應用程序,如果有問題,讓第一個信號發出第二個信號,然后讓第二個重新啟動第一個。

服務停止本身沒有問題 - 我只是嘗試使用我自己的服務之一,用 Delphi 4 編寫(不使用TService類)。 以下例程對我有用:

procedure TTestService.StopService;
var
  Scm, Svc: SC_Handle;
  Status: SERVICE_STATUS;
begin
  Scm := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if Scm <> 0 then begin
    Svc := OpenService(Scm, PChar(ServiceName), SERVICE_ALL_ACCESS);
    if Svc <> 0 then begin
      ControlService(Svc, SERVICE_CONTROL_STOP, Status);
      // handle Status....
      CloseServiceHandle(Svc);
    end;
    CloseServiceHandle(Scm);
  end;
end;

您需要檢查它是否也適用於您的工作線程。

您應該能夠使用 WMI (Windows Management Instrumentation) 重新啟動服務,即使是在服務本身內。 不知道這是否會導致任何奇怪的問題,但它應該可以工作。 是一篇關於使用 Delphi 進行 WMI 的文章。

更新:好吧,我假設(我的錯誤)只有一個 WMI 服務重啟命令,例如您可以在服務管理列表中單擊的按鈕。 顯然不是。
您可以改為編寫一個控制台應用程序,該服務在數據損壞時啟動。 控制台應用程序將從單獨的進程重新啟動服務。

我找到了一個更簡單的替代方案。 您可以向您的 TService 子類添加一個方法:

procedure TSomeService.StopService;
begin
  Controller(SERVICE_CONTROL_STOP);
end;

我使用與 OP 相同的設置 - 具體來說,一個 TService 后代,它只是啟動一個工作線程,然后除了處理 Windows 消息之外什么都不做。 不幸的是,您不能從工作線程調用 Controller,因為它受到保護。 當然,解決它的簡單方法是創建一個我上面展示的公共方法。 要從工作線程中使用它,您需要引用從工作線程內訪問的 TService object。 為此,我將 TService object 傳遞到線程構造函數中的工作線程中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM