A standalone Delphi application that can also be installed as windows service
Totally possible. The trick is to edit the .dpr to create main form when you want to run as an application and the service form when you want to run as a service. Like this:
if SvComFindCommand('config') then begin //When run with the /config switch, display the configuration dialog. Forms.Application.Initialize; Forms.Application.CreateForm(TfrmConfig, frmConfig); Forms.Application.Run;endelse begin SvCom_NTService.Application.Initialize; SvCom_NTService.Application.CreateForm(TscmServiceSvc, scmServiceSvc); SvCom_NTService.Application.Run;end;
The code above uses SvCom to run the service but exactly the same effect could be achieved using the standard TService.
I wrote an article about that for The Delphi Magazine many years ago. You can read it here: Many Faces Of An Application.
It'll be hard to explain but I will try :)
I've done it in my project like that (Delphi 5):
program TestSvc;uses SvcMgr, SvcMain, //the unit for TTestService inherited from TService ... ;var IsDesktopMode : Boolean;function IsServiceRunning : Boolean;var Svc: Integer; SvcMgr: Integer; ServSt : TServiceStatus;begin Result := False; SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_CONNECT); if SvcMgr = 0 then Exit; try Svc := OpenService(SvcMgr, 'TestService', SERVICE_QUERY_STATUS); if Svc = 0 then Exit; try if not QueryServiceStatus(Svc, ServSt) then Exit; Result := (ServSt.dwCurrentState = SERVICE_RUNNING) or (ServSt.dwCurrentState = SERVICE_START_PENDING); finally CloseServiceHandle(Svc); end; finally CloseServiceHandle(SvcMgr); end;end;begin if (Win32Platform <> VER_PLATFORM_WIN32_NT) or FindCmdLineSwitch('S', ['-', '/'], True) then IsDesktopMode := True else begin IsDesktopMode := not FindCmdLineSwitch('INSTALL', ['-', '/'], True) and not FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) and not IsServiceRunning; end; if IsDesktopMode then begin //desktop mode Forms.Application.Initialize; Forms.Application.Title := 'App. Title'; ShowTrayIcon(Forms.Application.Icon.Handle, NIM_ADD); // This function for create an icon to tray. You can create a popupmenu for the Icon. while GetMessage(Msg, 0, 0, 0) do begin TranslateMessage(Msg); DispatchMessage(Msg); end; ShowTrayIcon(Forms.Application.Icon.Handle, NIM_DELETE); // for delete the tray Icon end else begin // Service mode SvcMgr.Application.Initialize; SvcMgr.Application.CreateForm(TTestService, TestService); SvcMgr.Application.Run; end;end.
Another almost simpler option is available at http://cc.embarcadero.com/item/19703, you just need to include a unit and change your DPR to something like:
begin if CiaStartService('SERVICE NAME') then begin CiaService.CreateForm(TMain, Main); CiaService.Run; Exit; end; Application.Initialize; Application.Title := 'SERVICE NAME'; Application.CreateForm(TMain, Main); Application.Run;end.
While this example is now quite dated, the technique is simple enough that it still works, even with Delphi XE2. With this in place, your application will continue to operate as a non-service until you use the "/install" parameter (on an elevated command prompt). After which it will operate as a service until you use the "/uninstall" parameter (also on an elevated command prompt).