Служба 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 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 никогда не регистрировался).

В моем предыдущем коде у меня есть две процедуры Startup и Cleanup. Они просто создают/уничтожают и инициализируют/неинициализируют мои необходимые вещи...

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

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

Как вы можете видеть, у меня есть вторичный поток. Эта служба фактически имеет множество потоков, работающих как это, и основной поток службы регистрирует только события из каждого потока. Каждый поток имеет разные обязанности. Потоки сообщают правильно, и они также заканчиваются должным образом.

Что может быть причиной этого отказа остановки? Если мой опубликованный код ничего не раскрывает, я могу опубликовать больше кода позже - просто нужно "преобразовать" его из-за внутреннего именования и т.д.

ИЗМЕНИТЬ

Я только что начал проект NEW в 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

посмотрите исходный код метода 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, вы должны сами обрабатывать запросы SCM, вызывая ProcessRequests(False). Хорошей привычкой является использование Service.execute и запуск вашего workthread в событии Service.OnStart и завершение/освобождение его в событии Service.OnStop.

Как сказано в комментариях, другая проблема заключается в части FUpdateThread.Terminate. Дэвид Хеффернан был на месте с комментариями Free/WaitFor. Убедитесь, что вы закончили свой поток правильно, используя объекты синхронизации.