Is there a way to debug completely a windows service with Delphi?
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).
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.
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 .
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:
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:
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.
Yes there is.
In your dpr:
Application.CreateForm(TMyService, MyService);
_ServiceInDebugMode := SysUtils.FindCmdLineSwitch('DEBUG', True);
if _ServiceInDebugMode then
DebugService(MyService)
else
SvcMgr.Application.Run;
DebugService is a procedure that creates a debug form, a service control thread and kicks off everything by calling Forms.Application.Run.
You can compare the service control thread with the Windows' SCM (Service Control Manager), the debug form with an application that talks to the SCM (such as the services.msc) to start and stop services. The service should also have its own thread (service thread) to respond to control codes coming in from the SCM or our service control thread and one or many more separate threads to do its actual work. You want separate threads for the actual work (instead of coding it in the event handlers of your TService descendant) to ensure that the thread in which the TService itself runs is always free to respond to control codes from the SCM and you can still stop and start the service even when per chance a/the worker thread is frozen.
This approach allows you to debug the service app code as well, but involves a fair amount of code and placing a couple of hooks into windows api functions to work properly. Too much to show here at short notice. Maybe I'll write it up in an article some day.
In the mean time, if you don't want to code it all yourself you have two options. Either go with a library such as SVCOM or the one mentioned by Mick which do it all for you, or when in debug mode by-pass the service code all together and "simply" start your service as a "normal" forms application. You will have to disentangle the real functionality of your service from your TService descendant's code/event handlers, but that is something I'd recommend anyway for the reasons mentioned above.