Search code examples
delphiwinapiwindows-servicesdelphi-11-alexandria

Delphi Windows service stuck at START_PENDING


I'm using Delphi 11 and I'm trying to learn about Windows services.

I've created a very basic minimalistic service that should basically just start and sleep in a loop until stopped. I got most of the code directly from Embarcadero's blog "Developing Windows Services in Windows 11: Best Practices and Tools". But when I install the service with this Powershell command with Administrator access:

sc create TestSvc binPath= "C:\Actual\Path\TestSvc.exe" start= demand

and then try to run it via sc start TestSvc the outcome is:

SERVICE_NAME: TestSvc
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 7292
        FLAGS              :

And it stays forever stuck in the START_PENDING state, while the Task Manager keeps showing it as:

Starting

My TService1 class has only these few methods:

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

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

procedure TService1.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
  Continued := True;
end;

procedure TService1.ServiceExecute(Sender: TService);
begin
  while not Terminated do
  begin
    TThread.Sleep(1000);
  end;
end;

procedure TService1.ServicePause(Sender: TService; var Paused: Boolean);
begin
  Paused := True;
end;

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  //  TFile.AppendAllText('log.txt', 'ServiceStart tries to initialize PeriodicThread...')
  Started := True;
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  Stopped := True;
end;

The ServiceStart(), ServiceStop(), ServicePause(), ServiceContinue() and ServiceExecute() methods are all correctly hooked to corresponding events of TService1 (I can see them in the Object Inspector just fine). But when I try to add a line that would write a message to a log file (now commented out), the message is never written. It's almost like the ServiceStart() method never gets executed and the service just keeps hanging there in some limbo without even trying to start.

What am I missing?


Edit:

To clarify: I used the article Developing Windows Services in Windows 11: Best Practices and Tools to guide me.

I did try the version with the ServiceThread.ProcessRequests(false); line in the ServiceExecute() loop, and I did try even adding the FBackgroundThread, but the results were always exactly the same.


Solution

  • So I found the solution, even though I'm not 100% sure why it works. When Remy Lebeau pointed out it has to be an initialization issue, I went through dpr file and noticed this bit:

    // Application.DelayInitialize := True;
    //
    if not Application.DelayInitialize or Application.Installing then
      Application.Initialize;
    

    As Remy said, DelayInitialize should be false by default and this bit doesn't suggest otherwise (the line that would set it True has been commented out since the begining), so initialization should happen. But being completely out of any better ideas, I decided to inspect the Installing part of the condition. I found it simply ment whether the service exe was run with /install parameter or not. So I tried that. I used

    C:\Actual\Path\TestSvc.exe /install
    

    instead of

    sc create TestSvc binPath= "C:\Actual\Path\TestSvc.exe" start= demand
    

    and now I can start it by sc start Service1 without an issue. I later added a background thread to do any work and got rid of ServiceExecute just as suggested and it keeps working fine. So for whatever reason, using different command to install the service did the trick.

    I kept asking around and someone said it appears to be a "known issue" with Delphi and TServiceThread, though I couldn't find any mention of it anywhere online.