Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug a Delphi written service on Windows?

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.

like image 642
Sara Avatar asked Nov 05 '25 08:11

Sara


2 Answers

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;
like image 137
Remy Lebeau Avatar answered Nov 07 '25 12:11

Remy Lebeau


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

like image 23
whosrdaddy Avatar answered Nov 07 '25 13:11

whosrdaddy