2

I write a basic Delphi MS-Windows service. I install it with the /install directove. This works. In the Windows Services list it exists. I START it from there. Windows says it started successfully. It shows as running. But nothing is executed, except the OnCreate and OnDestroy.

It is in fact NOT running, while Windows claims it IS running.

I tried Delpi 10.2 and the latest 10.4.

What is going wrong here? It is the most basic Service possible.

The Log output looks like this:

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.
Bart Kindt
  • 142
  • 13
  • "_Windows claims it IS running_" - just update the service list (F5) or reopen the details window, both don't refresh themselves. Do the [event logs](https://en.wikipedia.org/wiki/Event_Viewer) tell something? – AmigoJack Jul 05 '21 at 17:46
  • Is there a reason why you are logging to a file (and why you are closing and reopening it on each message), rather than logging to the System Event Log ? `TService` has a `LogMessage()` method for that purpose. In any case, can you show your `DFM`? Are you SURE your event handlers are actually hooked up correctly? Can you verify that at runtime? I do find it curious that you are not getting `OnStart` and `OnExecute` events fired. I have used `TService` for many years (albeit in older versions) and it works just fine for me. I can't imagine Embarcadero has broken it in modern versions... – Remy Lebeau Jul 05 '21 at 18:26
  • ... Have you tried enabling Debug DCUs and then stepping into `TService`'s source code at runtime to see what is really happening? To make sure the `ServiceThread` is actually started? Your log shows 2 sets of Create+Destroy, after the service is installed, were those from 2 separate attempts to run the service? – Remy Lebeau Jul 05 '21 at 18:38
  • @RemyLebeau; I use `TService` daily in Delphi 10.4. It works just fine. – Andreas Rejbrand Jul 05 '21 at 21:05
  • @AndreasRejbrand I'm sure it does work. `TService` hasn't really changed in years. That doesn't surprise me. What does surprise me is what the OP described. So, there has to be some other factor at play here that hasn't been described/observed yet. – Remy Lebeau Jul 05 '21 at 21:29
  • That Comment is a bit off Topic, but when you start with Service now you should look for some better performing code skelleton like this one: https://stackoverflow.com/questions/10537267/delphi-windows-service-design/10538102#10538102 If you use a Thread for your Service it will be much easier in the future to prevent your Service of freezing. – fisi-pjm Jul 06 '21 at 06:11
  • Can you put your messagebeep(0) in ServiceCreate into try except block and see what happens? – fisi-pjm Jul 06 '21 at 06:17
  • Hi,Sorry I just discovered that I do not immediately get emails from posts. Have to change my settings. – Bart Kindt Jul 06 '21 at 20:40
  • Okay, I have started a whole new TService from the basic one supplied within Delphi. Then I clicked on all OnXXX events, and added a Log entry there (and yes, I also had messagebeeps everywhere too initially) – Bart Kindt Jul 06 '21 at 20:41
  • Bugger I keep pressing . So except for the AfterInstall and Create and Destroy non are *ever* fires. But I will try the LogMessage later today. Don't think it will make any difference. I am running all this on my Windows 10 Profesional PC. I have not tried to run it on another PC. So the whole thing is an of-the-Delphi-shelf Service. Totally basic. And it does not Start oe Execute. – Bart Kindt Jul 06 '21 at 20:44
  • Update: In the Windows Event Log, Custom Views>Administrative Events, I have events marked as ERROR, with the text: "Operation completed successfully", but when I click on Details, I see "The service process could not connect to the service controller". Also, when I "START" the service via the Services window, it claims is is Running afterwards, but in fact the service has not even been Created. When I call the service from the command prompt, without any switch, then it IS Created and then Destroyed emmidiately afterwards. – Bart Kindt Jul 06 '21 at 23:28

2 Answers2

0

I assume that during your debugging you have copy and pasted code into the unit from another project but you have not 'hooked up' the events properly. Bring up the project in Delphi and open the service module. Click on the Events tab in the Object Inspector and my guess is that they are all blank. (View the source of the .dfm and there is likely no OnExecute, OnStop, OnStop, etc events defined)

For example - double click the OnExecute event and I assume the IDE will automatically create a new OnExecute event rather than navigating to your OnExecute event in the unit.

Simply rehook up your events and it will most likely work as expected.

Darian Miller
  • 7,808
  • 3
  • 43
  • 62
0

Solved. After using the 'LogMessage() system, I found that the service is in fact running. But what happened, is that the destination folder of my simple Log file was transfered from the local executable directory to C:\Windows\System32\ and there was all the rest of the Log data... I never expected that :(

Thanks for all help, Bart

Bart Kindt
  • 142
  • 13
  • Consider adding timestamps with every line of your log, as that makes such mistakes more clear. – AmigoJack Jul 07 '21 at 15:00
  • //System.IOUtils var string ExePath := TPath.GetDirectoryName(GetModuleName(HInstance)); LogFileName := TPath.Combine(ExePath, 'Log.txt'); – Nihila Feb 03 '22 at 17:38