English 中文(简体)
我该如何重新启动用Delphi编写的Windows服务应用程序?
原标题:
  • 时间:2009-03-20 19:22:20
  •  标签:

我有一个用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,如果有任何区别的话。


Edit:

通过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 管理 Instrumentation)来重新启动服务,即使在服务本身内部也是如此。不知道这是否会引起任何奇怪的问题,但应该可以工作。这里有一篇有关在 Delphi 中使用 WMI 的文章。

UPDATE: Well well, I assumed (my mistake) that there is a single WMI service restart command, such as the button you can click in the services maangement listing. Apparently not.
You could instead write a console app that the service starts when the data is corrupted. The console app would restart the service from a separate process.

我已经找到了一个更简单的替代方案,应该可以起作用。您可以向TService子类添加一个方法:

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

我正在使用与OP相同的设置 - 具体来说,是一个简单启动工作线程然后仅处理Windows消息的TService后代。不幸的是,您无法从工作线程调用Controller,因为它是受保护的。当然,简单的方法是创建一个公共方法,就像我上面所示的那样。要从工作线程中使用此方法,您需要一个对TService对象的引用,该引用可从工作线程中访问。我通过在线程的构造函数中将我的TService对象传递给我的工作线程来实现这一点。





相关问题
热门标签