【问题标题】:How can I restart a Windows service application written in Delphi?如何重新启动用 Delphi 编写的 Windows 服务应用程序?
【发布时间】:2010-10-14 15:11:47
【问题描述】:

我有一个用 Delphi 编写的 Windows 服务。它使用的第三方资源之一偶尔会损坏,我发现解决这种情况的唯一方法是退出并重新启动程序。我可以从程序中检测资源何时损坏,我可以告诉 Windows 在服务停止后重新启动服务,但我不知道如何让服务告诉自己停止。

程序非常简单。我以看似正常的方式创建了一个服务应用程序。我有一个 TService 的子类来管理服务,而所有功能都发生在一个单独的线程中。 TService 子类几乎只是管理子线程的执行,我将在子线程中检测损坏。

作为参考,这里是服务和子线程的标头信息。

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 winapi windows-services


    【解决方案1】:

    我找到了一个更简单的替代方案。你可以给你的 TService 子类添加一个方法:

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

    我使用与 OP 相同的设置 - 具体来说,是一个 TService 后代,它只是启动一个工作线程,然后除了处理 Windows 消息之外什么都不做。不幸的是,您不能从工作线程调用 Controller,因为它是受保护的。当然,解决它的简单方法是创建一个我上面展示的公共方法。要从工作线程中使用它,您需要一个对可从工作线程内访问的 TService 对象的引用。我通过将 TService 对象传递到线程构造函数中的工作线程来做到这一点。

    【讨论】:

      【解决方案2】:

      您应该能够使用 WMI (Windows Management Instrumentation) 重新启动服务,即使是在服务本身内。不知道这是否会导致任何奇怪的问题,但它应该可以工作。 Here's 一篇关于用 Delphi 做 WMI 的文章。

      更新:好吧,我假设(我的错误)只有一个 WMI 服务重启命令,例如您可以在服务管理列表中单击的按钮。显然不是。
      您可以改为编写一个控制台应用程序,该服务在数据损坏时启动。控制台应用程序将从单独的进程重新启动服务。

      【讨论】:

      • 别让我们挂了!重启服务的 WMI 命令是什么?
      【解决方案3】:

      服务自行停止没有问题 - 我只是尝试使用我自己的一项服务,用 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;
      

      您需要检查它是否也适用于您的工作线程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-19
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 2011-05-22
        相关资源
        最近更新 更多