Search code examples
delphiwindows-services

Double click on Windows Service executable to configure


I wrote a Delphi Win32 Windows Service application from Delphi IDE's template, and it works very well when installed and started from Services control panel.

Now I would like to write a configuration application for it and I thought that may be it could be a configurator for itself when just double clicking on its executable.

I think so because when double clicked, the service distinguishes somehow that it wasn't executed by Service Control Management system.

So here are my questions:

  1. How does the Service app distinguishes a simple run and run as a service?
  2. Could the simple run be used to take some actions other than a service mode? Will this disturb functioning in a service mode?

Solution

  • to answer your questions:

    How does the Service app distinguishes a simple run and run as a service?

    look at the code behind TServiceApplication.CreateForm in unit Vcl.SVcMgr

    Could the simple run be used to take some actions other than a service mode?

    Yes, see below answer

    Will this disturb functioning in a service mode?

    No

    All you need to do is change your Service source code (.dpr file) to something like this:

     begin
      if FindCmdLineSwitch('config', ['-', '/'], True) then
       TMyForm.Run
      else
       begin
        if not Application.DelayInitialize or Application.Installing then
         Application.Initialize;
        Application.CreateForm(TSvc_MyService, Svc_MyService);
        Application.Run;
       end;
    end.
    

    where TMyForm.Run is defined as a class procedure on my main GUI form:

    class procedure TMyForm.Run;
    begin
     TThread.NameThreadForDebugging('FormRunner');
     ReportMemoryLeaksOnShutdown := DebugHook <> 0;
     Forms.Application.Initialize;
     Forms.Application.ShowMainForm := True;
     Forms.Application.MainFormOnTaskBar := True;
     Forms.Application.CreateForm(TMyForm, MyForm);
     Forms.Application.Run;
    end;
    

    So when you start the service executable with flag /config (or -config), it will start as a normal forms application.

    Update

    The distinction is more likely to be made here:

    procedure TServiceStartThread.Execute;
    begin
      if StartServiceCtrlDispatcher(FServiceStartTable[0]) then
        ReturnValue := 0
      else
        ReturnValue := GetLastError; //Code 1063 if started like an app
    end;
    

    This causes WM_QUIT message to be posted to message queue.

    Following loop terminates when receives WM_QUIT message.

    procedure TServiceApplication.Run;
    .....
    begin
      .....
      while not Vcl.Forms.Application.Terminated do
      try
        Vcl.Forms.Application.HandleMessage;
      except
        on E: Exception do
          DoHandleException(E);
      end;
      .....
    end;
    

    More information on the topic here: