How to debug a windows service with Delphi?

25,749

Solution 1

It's actually quite easy. Just use the standard DEBUG compiler directive to start the service as a console application instead of a service.

program MyServiceApp;

{$ifdef DEBUG}
  {$APPTYPE CONSOLE}
{$endif}

uses
  System.SysUtils,

[..]

begin
  {$ifdef DEBUG}
  try
    // In debug mode the server acts as a console application.
    WriteLn('MyServiceApp DEBUG mode. Press enter to exit.');

    // Create the TService descendant manually.
    ServerContainer1 := TServerContainer.Create(nil);

    // Simulate service start.
    ServerContainer1.ServiceStart(ServerContainer1, MyDummyBoolean);

    // Keep the console box running (ServerContainer1 code runs in the background)
    ReadLn;

    // On exit, destroy the service object.
    FreeAndNil(ServerContainer1);
  except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);
      WriteLn('Press enter to exit.');
      ReadLn;
    end;
  end;
  {$else}
  // Run as a true windows service (release).
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TServerContainer, ServerContainer1);
  Application.Run;
  {$endif}
end.

Solution 2

You can use unitDebugService.pas from Colin Wilson's NT Low Level Utilities (page is gone, available in the wayback machine)

and then in the DPR:

begin
  if (paramCount > 0) and (SameText(ParamStr(1), '-DEBUG')) then
  begin
    FreeAndNil (Application);
    Application := TDebugServiceApplication.Create(nil);
  end;

  //... the rest of the normal DPR code
end.

This way you can run from within Delphi with debugging (by setting the project Debugger Parameters), use the EXE as a service, or run from the commandline with the -DEBUG switch, and .

Solution 3

Use Run -> Attach to process. This way you can debug a service without doing any changes to its code. The only tricky part maybe debugging the service start code, because attaching may require some time, and the start must happen in 30s (although you can tweak Windows to allow a longer time). You can use a delay (sleep...) to allow you to attach in time, or if you just need to see what happens you can use OutputDebugString() to print to the debug output (use Delphi Event View to see it).

Solution 4

Yes, there is: Debugging services: an easy way

Do you create services with Delphi? Then maybe you are also annoyed at the time consuming way of starting, restarting, killing and attaching to the service process application every time. Well, there is remedy.

You don’t need to do this. Instead run Delphi as a SYSTEM application and do some minor adaptions to the service code.

Solution 5

I've tried this, but only appears the cpu window with assembly codes.

Then you only should solve this problem.

Basically, to debug a Win2 service, there are few ways:

  • Use "Attach to process" command to attach debugger to already running service. You may insert startup delays to have time to attach debugger, if you need to attach at the very beginning. However, you would also have to tweak the system to increase service timeouts.
  • Use "Image File Execution Options" registry key to force-run Delphi's debugger at service startup. The same considerations about system timeouts apply.
  • Temporary convert service into usual application and run it under debugger normally. You may re-launch IDE under different user account to gain more priviledges for the "service".

If you for some reason has only CPU view of your service after starting debugging - this means that Delphi's debugger can't find debug information for your service. That is a different problem and you should search solution for it.

Usually, you need to do:

  1. Make sure that output folder for your service application is set to folder from which it will be loaded by the system. I.e. if your service is located in C:\Windows\System32 - then set output folder to C:\Windows\System32. Do not copy .exe file elsewhere from your output folder. For 64 systems you may try alias (sysnative/SysWOW64) or real name. I think it's best to set output path to project's folder and re-register service to be loaded from project folder.
  2. (Optional) Set output path for DCU into the same folder as .exe file.
  3. Delete all of your DCU files.
  4. Make sure to enable debug options on "Compiler" page in project options.
  5. (Optional) Additionally you may also include TD32/RSM/MAP options on "Linker" page.
  6. Make sure there is no IDE expert/extension, which may modify .exe file, debug information or file modification date for these files.
  7. Make sure there is no old files (DCU/exe) in other locations.
  8. Make a full rebuild (Project/Build all).
  9. Run your service.
Share:
25,749

Related videos on Youtube

Daniel Grillo
Author by

Daniel Grillo

https://github.com/oengenheiro

Updated on July 09, 2022

Comments

  • Daniel Grillo
    Daniel Grillo almost 2 years

    Is there a way to debug completely a windows service with Delphi?

  • Marjan Venema
    Marjan Venema almost 14 years
    RunAsSys sounds good. The example code in the article you linked uses conditional defines to select the "mode". Do you know whether RunAsSys allows for selecting debug mode without having to rebuild the app? Ie using a command line parameter to go into debug mode instead of running as a service?
  • Daniel Grillo
    Daniel Grillo almost 14 years
    I've tried this, but only appears the cpu window with assembly codes.
  • Daniel Grillo
    Daniel Grillo almost 14 years
    I have the same app with forms and service. With forms it works. With services it doesn't work.
  • Mick
    Mick almost 14 years
    I am not certain, but it seems that you would be able to add that functionality yourself to it.
  • Remy Lebeau
    Remy Lebeau over 10 years
    Attach to Process works fine. When the debugger first connects to the service process, the CPU window does appear, but you can simply dismiss it and press F9 or the Run button to continue executing the service normally, and then you can debug its code as needed like any other project.
  • GolezTrol
    GolezTrol over 10 years
    This is working fine. If you don't want the CPU window to popup, you can uncheck the 'pause after attach' checkbox.
  • Carlos B. Feitoza Filho
    Carlos B. Feitoza Filho over 8 years
    This is far, a very good approach! We need to write code, really, but no 3rd part units, functions or complicated windows registry configurations
  • Spongebob Comrade
    Spongebob Comrade over 6 years
    @Marjan Venema In which unit DebugService is located?
  • Marjan Venema
    Marjan Venema over 6 years
    @SpongebobComrade there is none. It's something you write yourself. What it should do is mentioned in the first paragraph under the code. Check the other answers for more information.
  • Shahram Banazadeh
    Shahram Banazadeh about 5 years
    where is TServerContainer in delphi 10.2?which unit?
  • Massimo Fazzolari
    Massimo Fazzolari over 4 years
    @ShahramBanazadeh TServerContainer is the class name you gave to your Service. By Default is TService1
  • J...
    J... almost 3 years
    Except running from the console runs the service in ring 3 instead of ring 2, no?
  • Dreamer64
    Dreamer64 almost 3 years
    what is MyDummyBoolean? just anything ?