Служба Delphi Windows не запускается, сразу переходит от создания к уничтожению

#windows #delphi #service

Вопрос:

Я пишу базовую службу Delphi MS-Windows. Я устанавливаю его с помощью /install directove. Это работает. В списке служб Windows он существует. Я начинаю с этого. Windows говорит, что все началось успешно. Он отображается как запущенный. Но ничего не выполняется, кроме onCreate и onDestroy.

Он на самом деле НЕ работает, в то время как Windows утверждает, что он работает.

Я попробовал Delpi 10.2 и последнюю версию 10.4.

Что здесь происходит не так? Это самая простая из возможных Услуг.

Вывод журнала выглядит следующим образом:

 Create
AfterInstall
Destroy
Create
Destroy
Create
Destroy
 
 program BartServiceTwo;

uses
  Vcl.SvcMgr,
  Unit1 in 'Unit1.pas' {BartService: TService};

{$R *.RES}

begin
  // Windows 2003 Server requires StartServiceCtrlDispatcher to be
  // called before CoRegisterClassObject, which can be called indirectly
  // by Application.Initialize. TServiceApplication.DelayInitialize allows
  // Application.Initialize to be called from TService.Main (after
  // StartServiceCtrlDispatcher has been called).
  //
  // Delayed initialization of the Application object may affect
  // events which then occur prior to initialization, such as
  // TService.OnCreate. It is only recommended if the ServiceApplication
  // registers a class object with OLE and is intended for use with
  // Windows 2003 Server.
  //
  // Application.DelayInitialize := True;
  //
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TBartService, BartService);
  Application.Run;
end.
 
 unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.SvcMgr;

type
  TBartService = class(TService)
    procedure ServiceExecute(Sender: TService);
    procedure ServiceCreate(Sender: TObject);
    procedure ServiceDestroy(Sender: TObject);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceAfterInstall(Sender: TService);
  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    procedure Log(Line:string);
    { Public declarations }
  end;

var
  BartService: TBartService;
  LogFile: text;
  Logfilename: string;

implementation

{$R *.dfm}

procedure TBartService.Log(Line:string);
begin
   if Logfilename = '' then
  begin
    Logfilename := 'Log.txt';
    Assignfile(LogFile,Logfilename);
  end;
  try
    if FileExists(Logfilename)
    then append(LogFile)
    else rewrite(LogFile);
    writeln(LogFile,line);
    Closefile(LogFile);

  except
    on E:Exception do;
  end;
end;


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

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

procedure TBartService.ServiceAfterInstall(Sender: TService);
begin
  Log('AfterInstall');
end;

procedure TBartService.ServiceCreate(Sender: TObject);
begin
  Log('Create');
  messagebeep(0);
end;

procedure TBartService.ServiceDestroy(Sender: TObject);
begin
  Log('Destroy');
end;

procedure TBartService.ServiceExecute(Sender: TService);
begin
  Log('ServiceExecute Start. Terminated=' Terminated.ToString(true));
  while not Terminated do
  begin
    try
      ServiceThread.ProcessRequests(false);
      Log('ServiceExecute');
      // messagebeep(0);
      sleep(1000);
    except
      on E:Exception do
      begin
        Log('ERROR: ServiceExecute: Final: ' E.Message);
      end;
    end;
  end;
  Log('ServiceExecute Out of loop.');
end;

procedure TBartService.ServiceStart(Sender: TService; var Started: Boolean);
begin
  Log('ServiceStart');
end;

procedure TBartService.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  Log('ServiceStop');
end;

end.
 

Комментарии:

1. » Windows утверждает, что она запущена » — просто обновите список служб (F5) или снова откройте окно сведений, оба не обновляются. Говорят ли что — нибудь журналы событий ?

2. Есть ли причина, по которой вы регистрируетесь в файле (и почему вы закрываете и снова открываете его при каждом сообщении), а не регистрируетесь в журнале системных событий ? TService есть LogMessage() метод для этой цели. В любом случае, можете ли вы показать свои DFM ? Вы УВЕРЕНЫ, что ваши обработчики событий на самом деле подключены правильно? Можете ли вы проверить это во время выполнения? Мне действительно кажется любопытным, что вы не получаете OnStart и OnExecute события уволены. Я использую TService его уже много лет (хотя и в более старых версиях), и он отлично работает для меня. Я не могу представить, чтобы Embarcadero нарушил его в современных версиях…

3. … Вы пробовали включить отладочные контроллеры постоянного тока, а затем войти в TService исходный код во время выполнения, чтобы увидеть, что происходит на самом деле? Чтобы убедиться ServiceThread , что он действительно запущен? В вашем журнале показано 2 набора Create Destroy, после установки службы, были ли это 2 отдельные попытки запустить службу?

4. @RemyLebeau; Я TService ежедневно использую Delphi 10.4. Это работает просто отлично.

5. @AndreasRejbrand Я уверен, что это действительно работает. TService на самом деле он не изменился за последние годы. Это меня не удивляет. Что меня действительно удивляет, так это то, что описал ОП. Таким образом, здесь должен быть какой-то другой фактор, который еще не был описан/замечен.

Ответ №1:

Я предполагаю, что во время отладки вы скопировали и вставили код в устройство из другого проекта, но вы не «подключили» события должным образом. Откройте проект на Delphi и откройте сервисный модуль. Нажмите на вкладку События в Инспекторе объектов, и я предполагаю, что все они пусты. (Просмотрите источник файла .dfm, и, скорее всего, не будут определены события OnExecute, onStop, onStop и т. Д.)

Например, дважды щелкните событие OnExecute, и я предполагаю, что среда IDE автоматически создаст новое событие OnExecute, а не перейдет к вашему событию OnExecute в блоке.

Просто повторно подключите свои мероприятия, и, скорее всего, все будет работать так, как ожидалось.

Ответ №2:

Решенный. После использования системы ‘LogMessage() я обнаружил, что служба фактически запущена. Но случилось то, что папка назначения моего простого файла журнала была перенесена из локального исполняемого каталога в C:WindowsSystem32 и там были все остальные данные журнала… Я никогда не ожидал, что 🙁

Спасибо за всю помощь, Барт

Комментарии:

1. Подумайте о добавлении отметок времени в каждую строку вашего журнала, так как это делает такие ошибки более очевидными.