3

Has anyone ever tried to attach delphi to his own windows service(32 bit app.) process under Windows Server 2008 64 bit?

When I try to do this I get the error: Unable to create the process. The parameter is incorrect.

if anyone of you know how to do this, that help would be really appreciated.

Thanks!

John
  • 41
  • 6
  • Did you try attaching the Delphi 7 debugger to the 64 bit services.exe? If so, it's supposed to fail! Delphi 7 is a 32 bit process, it can't debug a 64 bit process. – Cosmin Prund Jul 06 '11 at 06:33
  • @Cosmin Prund I wanted to attach to my windows service created also in delphi 7, which is 32 bit application, with no luck .. – John Jul 06 '11 at 06:36
  • 1
    I don't have much experience in that area; But I'd start by running the service under *my user account*, and I'd edit the question to make it clear I'm debugging my own 32bit service, because your calling it "the windows service"! – Cosmin Prund Jul 06 '11 at 06:41
  • Whilst you can debug a Delphi service there are a number of hoops that you need to jump through to make it work. I never bother and simply ensure that my services can run either as a service or as a standard app. When I want to debug I run as a standard app and so sidestep all the headaches. One of the main benefits of this approach is that the startup code can be debugged easily. – David Heffernan Jul 06 '11 at 08:33
  • @DavidHeffernan, how do you manage to run the service from delphi ide as a standard app? Don't you need some env. faking run,stop,suspend - service operations? – John Jul 06 '11 at 09:01
  • @John If you are interested in how I do this then I can publish my code. – David Heffernan Jul 06 '11 at 09:01
  • @David: What *I'd* like to know is, how you managed not only to read the question directly from John's mind but also to post the answer at exactly the same time as when John posted his question. Does it require much practicing? :) – Andriy M Jul 06 '11 at 09:15
  • @Andriy That was my mistake(the comment was deleted and posted again later) :) I was just playing with "stackoverflow" trying to figure out why in some comments when I write the: "@author" it is visible, sometimes it is not .. anyway I haven't found the answer ... – John Jul 06 '11 at 09:55
  • @John: I see, thanks for explaining. :) I've noticed that ambiguity too, by the way. I think, apart from the cases when your comment is a response to the post's author's comment, one other case of omitting the "@nick" in your comment for which I've noticed the notification definitely works is when you are responding a person who's the only other person (apart from you) having commented in the same comment thread. And possibly *you* have to be the author of the post to which the comments belong, too. I'm not yet certain of that, though. – Andriy M Jul 06 '11 at 11:57
  • Are you sure you're attaching the right process? Anyway up to Delphi 2009 the debugger is known to have issues under 64 bit OSes, but I never had problems to attach a service of mine, regardless the user it is run with. –  Jul 06 '11 at 13:07
  • @Idsandon well, I am 100% sure I am attaching the right, mine process. Neither i can attach the process nor I can remote debug the windows process due to the mentioned error. However I am able to run the app and debug it, so David Heffernan's solution helped me in turning the windows service into standalone forms app and debug it from the beginning (which is normally not possible to debug the winsows service from the 1 line of code) – John Jul 06 '11 at 13:58

2 Answers2

10

Whilst you can debug a Delphi service there are a number of hoops that you need to jump through to make it work. I never bother and simply ensure that my services can run either as a service or as a standard app. When I want to debug I run as a standard app and so sidestep all the headaches.

I've hacked out all the code into a single file for the purpose of this answer, but you'd want to structure it a bit differently.

program MyService;

uses
  SysUtils, Classes, Windows, Forms, SvcMgr;

type
  TMyService = class(TService)
  private
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServicePause(Sender: TService; var Paused: Boolean);
    procedure ServiceExecute(Sender: TService);
    procedure ServiceContinue(Sender: TService; var Continued: Boolean);
  protected
    FDescription: string;
    FEventLogSourceName: string;
    procedure Initialise; virtual; abstract;
    class function CreateRunner: TObject; virtual; abstract;
  public
    constructor Create(AOwner: TComponent); override;
    function GetServiceController: TServiceController; override;
  end;
  TMyServiceClass = class of TMyService;

{ TMyService }

constructor TMyService.Create(AOwner: TComponent);
begin
  inherited;
  Initialise;
  OnStart := ServiceStart;
  OnStop := ServiceStop;
  OnPause := ServicePause;
  OnExecute := ServiceExecute;
  OnContinue := ServiceContinue;
end;

procedure TMyService.ServiceStart(Sender: TService; var Started: Boolean);
begin
  Started := True;
end;

procedure TMyService.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  Stopped := True;
end;

procedure TMyService.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
  ServiceStart(Sender, Continued);
end;

procedure TMyService.ServicePause(Sender: TService; var Paused: Boolean);
begin
  ServiceStop(Sender, Paused);
end;

procedure TMyService.ServiceExecute(Sender: TService);
var
  Runner: TObject;
begin
  Runner := CreateRunner;
  Try
    while not Terminated do begin
      ServiceThread.ProcessRequests(True);
    end;
  Finally
    FreeAndNil(Runner);
  End;
end;

var
  Service: TMyService;

procedure ServiceController(CtrlCode: DWORD); stdcall;
begin
  Service.Controller(CtrlCode);
end;

function TMyService.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure RunAsService(ServiceClass: TMyServiceClass; var Service);
var
  Application: TServiceApplication;
begin
  Application := SvcMgr.Application;
  Application.Initialize;
  Application.CreateForm(ServiceClass, Service);
  Application.Run;
end;

procedure RunAsStandardExecutable(ServiceClass: TMyServiceClass);
var
  Application: TApplication;
  Runner: TObject;
begin
  Application := Forms.Application;
  Application.Initialize;
  Runner := ServiceClass.CreateRunner;
  Try
    while True do begin
      Try
        Application.HandleMessage;
      Except
        Application.HandleException(Application);
      End;
    end;
  Finally
    FreeAndNil(Runner);
  End;
end;

procedure ServiceMain(ServiceClass: TMyServiceClass);
begin
  if FindCmdLineSwitch('RunAsApp', ['-', '/'], True) then begin
    RunAsStandardExecutable(ServiceClass);
  end else begin
    RunAsService(ServiceClass, Service);
  end;
end;

begin
  ServiceMain(TMyService);
end.

To use this you need to create a new class, inherited from TMyService, and implement Initialise and CreateRunner. CreateRunner is the key. In my services this creates an object which in turn opens a listening socket ready for clients to communicate over.

The standard app code is pretty basic. It doesn't even have a mechanism to terminate—it runs inside a while True loop. That doesn't matter for my debugging needs.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks, I've adopted your code. Thanks so much, as well as for the ability to read directly from my mind :) – John Jul 06 '11 at 11:31
  • @John You're welcome. We aim to provide a full service here at Stack Overflow! ;-) – David Heffernan Jul 06 '11 at 11:34
  • This way you're not debugging your service in its real environment, with the correct user the service will run with. I never had issues attaching to and debugging services, even under 64 bit OSes. –  Jul 06 '11 at 12:55
  • @Idsandon That's a very valid point. It all depends on what exactly you are searching for with the debugger. Much of the service debugging that I have had to do has concerned the primary functionality of the service and how it interacts with clients. My approach works well. If you are working on problems relating to permissions, sessions, desktops etc. then I agree that in situ debugging is what you want. – David Heffernan Jul 06 '11 at 13:25
1

Did you try running the IDE as Administrator?

I've already done such process attach under Win64, but I had to run the IDE with Administrator rights, as far as I remember.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • Yes, error is the same. i was also trying to change compatibility level of delphi ide, but still the same error pops up – John Jul 06 '11 at 08:57
  • DO you run the service under the SYSTEM account? – Warren P Jul 06 '11 at 16:48
  • @Warren Service was tested under system, also under the account i was logged in. None of these has worked .. – John Jul 07 '11 at 13:14