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.
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.