2

I created a new Windows Service project using wizard, putted some code, compiled it, run it with /INSTALL and then I tried to start it using net start myservice but I've got an service name not found error; then I went to the Control Panel in Services and when I try to start clicking the 'Start' link the dialog windows that shows up freezes at 50% of the progress bar indefinitely.

This is my first try to make a service to update the main system I am developing, and for a test I put a Timer to tell the time every one minute. Can anyone notice what is wrong and why it is behaving like that?

The DPR file with:

{...}
begin
  if not Application.DelayInitialize or Application.Installing then
  begin
    Application.Initialize;
  end;
  Application.CreateForm(TZeusUpdateSevice, ZeusUpdateSevice);
  Application.Run;
end.

and the PAS file with:

{...}
procedure ServiceController(CtrlCode: DWord); stdcall; 
begin
  ZeusUpdateSevice.Controller(CtrlCode);
end;

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

procedure TZeusUpdateSevice.ServiceAfterInstall(Sender: TService);
var
  regEdit : TRegistry;
begin
  regEdit := TRegistry.Create(KEY_READ or KEY_WRITE);
  try
    regEdit.RootKey := HKEY_LOCAL_MACHINE;

    if regEdit.OpenKey('\SYSTEM\CurrentControlSet\Services\' + Name,False) then
    begin
      regEdit.WriteString('Description','Mantém atualizados os arquivos e as credenciais da Plataforma Zeus.');
      regEdit.CloseKey;
    end;

  finally
    FreeAndNil(regEdit);
  end;
end;

procedure TZeusUpdateSevice.ServiceStart(Sender: TService; var Started: Boolean);
begin
{ executa os processos solicitados pelo sistema }
  Timer1.Enabled := True;
  while not Terminated do ServiceThread.ProcessRequests(True);
  Timer1.Enabled := False;
end;

procedure TZeusUpdateSevice.Timer1Timer(Sender: TObject);
begin
  ShowMessage('Now, time is: ' + TimeToStr(Now));
end;
NaN
  • 8,596
  • 20
  • 79
  • 153

1 Answers1

12

There are a couple of obvious problems:

  1. You have an infinite loop in the OnStart event. This event allows you to perform one time actions when the service starts. That code belongs in OnExecute.
  2. Services cannot show UI and so ShowMessage cannot work. You'll need to use a non-visual mechanism to give feedback.

Because your OnStart doesn't return, the SCM regards your service as not having started. So I guess that item 1 above is the explanation as to why your service won't start.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • In the item 2, is it neutralized by the `Interactive` of the main unit in the Service app? – NaN Jul 22 '13 at 21:40
  • So, to fix my service I should put in OnExecute the `while not Terminated do ServiceThread.ProcessRequests(True);` or just the `ServiceThread.ProcessRequests(True);` ? – NaN Jul 22 '13 at 22:06
  • You need the while loop otherwise the service will immediately stop – David Heffernan Jul 22 '13 at 22:13
  • 3
    If you call `ProcessRequests(True)`, it will not exit until the service is terminated. If you want to loop manually, you need to use `ProcessRequests(False)` instead, and then call `Sleep()` periodically to avoid hogging the CPU. Otherwise, for such a simple example, you can just get rid of `OnExecute` altogether (don't even assign it). Let the service handle SCM requests automatically for you. Activate the `TTimer` in the `OnStart` event, and deactivate it in the `OnStop` event. That's all you really need. – Remy Lebeau Jul 22 '13 at 22:58
  • This service example I've took at delphi.about.com and couldn't possibly imagine that Zarko Gajic would make those those mistakes :-( – NaN Jul 23 '13 at 14:20