Delphi XE2服务无法正常停止

时间:2012-02-13 16:33:47

标签: delphi service delphi-xe2

我在Delphi 7中构建了一些服务并且没有这个问题。现在我在XE2中启动了一个新的服务应用程序,它将无法正常停止。我不知道这是不是我做错了,或者它是否是XE2服务中的错误。

执行过程如下所示:

procedure TMySvc.ServiceExecute(Sender: TService);
begin
  try
    CoInitialize(nil);
    Startup;
    try
      while not Terminated do begin
        DoSomething; //Problem persists even when nothing's here
      end;
    finally
      Cleanup;
      CoUninitialize;
    end;
  except
    on e: exception do begin
      PostLog('EXCEPTION in Execute: '+e.Message);
    end;
  end;
end;

我从来没有例外,因为你可以看到我记录任何异常。 PostLog保存到INI文件,工作正常。现在我使用ADO组件,因此我使用CoInitialize()CoUninitialize。它确实连接到数据库并正常工作。问题只发生在我停止此服务时。 Windows给了我以下消息:

First stop failure

然后服务继续。我必须第二次停下来。它第二次停止,但有以下消息:

Second stop failure

日志文件表明该服务已成功免费(已记录OnDestroy事件),但它从未成功停止(OnStop从未记录过。)

在上面的代码中,我有两个程序StartupCleanup。这些只是创建/销毁和初始化/取消初始化我必要的东西......

procedure TMySvc.Startup;
begin
  FUpdateThread:= TMyUpdateThread.Create;
    FUpdateThread.OnLog:= LogUpdate;
    FUpdateThread.Resume;
end;

procedure TMySvc.Cleanup;
begin
  FUpdateThread.Terminate;
end;

如您所见,我有一个辅助线程正在运行。这个服务实际上有很多线程像这样运行,主服务线程只记录每个线程的事件。每个线程都有不同的职责。线程报告正确,它们也正在正确终止。

什么可能导致此停止失败?如果我发布的代码没有公开任何内容,那么我可以稍后发布更多代码 - 只需要因为内部命名等而“转换”它。

修改

我刚刚在Delphi XE2中启动了新服务项目,并且遇到了同样的问题。这是我的所有代码:

unit JDSvc;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, JDSvcMgr;

type
  TJDService = class(TService)
    procedure ServiceExecute(Sender: TService);
  private
    FAfterInstall: TServiceEvent;
  public
    function GetServiceController: TServiceController; override;
  end;

var
  JDService: TJDService;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  JDService.Controller(CtrlCode);
end;

function TJDService.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TJDService.ServiceExecute(Sender: TService);
begin
  while not Terminated do begin

  end;
end;

end.

1 个答案:

答案 0 :(得分:6)

查看Execute方法的源代码:

procedure TServiceThread.Execute;
var
  msg: TMsg;
  Started: Boolean;
begin
  PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); { Create message queue }
  try
    // Allow initialization of the Application object after
    // StartServiceCtrlDispatcher to prevent conflicts under
    // Windows 2003 Server when registering a class object with OLE.
    if Application.DelayInitialize then
      Application.Initialize;
    FService.Status := csStartPending;
    Started := True;
    if Assigned(FService.OnStart) then FService.OnStart(FService, Started);
    if not Started then Exit;
    try
      FService.Status := csRunning;
      if Assigned(FService.OnExecute) then
        FService.OnExecute(FService)
      else
        ProcessRequests(True);
      ProcessRequests(False);
    except
      on E: Exception do
        FService.LogMessage(Format(SServiceFailed,[SExecute, E.Message]));
    end;
  except
    on E: Exception do
      FService.LogMessage(Format(SServiceFailed,[SStart, E.Message]));
  end;
end;

正如您所看到的,如果您没有分配OnExecute方法,Delphi将处理SCM请求(Service Start,Stop,...),直到服务停止。 在Service.Execute中创建循环时,必须通过调用ProcessRequests(False)来自行处理SCM请求。一个好习惯是不要使用Service.execute并在Service.OnStart事件中启动你的workerthread并在Service.OnStop事件中终止/释放它。

正如评论中所说,另一个问题在于FUpdateThread.Terminate部分。 大卫·赫弗南(David Heffernan)在Free / WaitFor评论中名列前茅。 确保使用同步对象以正确的方式结束线程。