Does anyone know how to debug a Delphi-written service (Service Application) on Windows?
I am making an API that get data from rclone and show it on an interface, and I want to make that into a Windows service. If there is anything that you think that can help me, I'd appreciate it.
You can debug it like any other app. The only trick is you have to start the service first in the SCM, and then you can attach Delphi's debugger to the service process, and then debugging works normally.
In my own services, I usually add code in the TService.OnStart event to look for a /debugger-style parameter in the TService.Param property, and if present then use IsDebuggerPresent() in a wait loop until the debugger attaches before continuing with my normal service logic. That value can be passed in the SCM startup parameters. For example:
procedure TMyService.ServiceStart(Sender: TObject;
var Started: Boolean);
var
I: Integer;
StartTicks: DWORD;
begin
for I := 0 to Self.ParamCount-1 do
begin
if Self.Param[I] = '/debugger' then
begin
StartTicks := GetTickCount;
repeat
Sleep(Self.WaitHint-100);
Self.ReportStatus;
until IsDebuggerPresent or
((GetTickCount - StartTicks) >= 30000);
end;
end;
Started := True;
end;
if you encapsulate the main service logic in a thread it becomes very easy to make a separate test application (console or forms).
the test application and service reference the same source file where the thread is defined.
service code:
uses mythread;
...
procedure TMyService.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started := False;
try
MyThread := TMyThread.Create;
MyThread.Start; //Mythread is a global var in unit mythread
NTEventLog.Add(Eventlog_Success, STR_INFO_SVC_STARTED);
Started := True;
except
on E : Exception do
begin
// add event in eventlog with reason why the service couldn't start
NTEventLog.Add(Eventlog_Error_Type, Format(STR_INFO_SVC_STARTFAIL, [E.Message]));
end;
end;
end;
test application:
uses mythread; // reference same unit from service
...
procedure TTestForm.FormCreate(Sender: TObject)
begin
ReportMemoryLeaksOnShutdown := True;
MyThread := TMyThread.Create; //Mythread is a global var in unit mythread
MyThread.Start;
end;
And voila you can test/develop your service without actually needing to install a service. (Destructor part is left out here but you get the idea...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With