I have a service application built in Delphi that works great. It does exactly what I want it to do and all is happy. All is fine until I want to run two (or more) instances of that service on a single machine. Since the service name is hard coded into the program (via the Name property of the service), I can only install the service once on any given computer. If I try to modify the Name property at run-time, the service does not respond unless the Name property is set to the same thing that was set during design time.
I have done a workaround for this where I have all of the code that is not interacting directly with the service control manager encapsulated out into separate unit(s). Then I write a separate Delphi project for each instance that I want of the service that has just enough code to launch itself and start running the main code.
This method is, in my opinion, ugly and is certainly inefficient. It works okay for two instances, but then we need a third and a fourth and ...
Is there any way that I can modify my code so that I have just one Delphi project that can install and run itself as multiple service instances with some simple run-time input (e.g. command line flag)?
Or perhaps a broader question: Is there a "right way" to accomplish goal?
You haven't made it clear what you have tried to change in the TService subclass.
Have you added a "BeforeInstall" handler?
Something like:
procedure TServiceMain.ServiceLoadInfo(Sender : TObject);// new method, not an override
begin
Name := ParamStr(2);
DisplayName := ParamStr(3);
end;
procedure TServiceMain.ServiceBeforeInstall(Sender: TService);
begin
ServiceLoadInfo(Self);
end;
procedure TServiceMain.ServiceCreate(Sender: TObject);
begin
ServiceLoadInfo(Self);
end;
If you do this regularly, subclass TService to do thie in the Constructor instead.
You should do the same in the BeforeUninstall as well - point both events at the same method.
C:\>servicename /install MyService "My Service Description"
You can create your service with multiple threads internally, each one acting like it's own version/copy of the service. You control it with the Service Controller API, IIRC.
Well yes it is possible to install multiple instances of the same service, you simply need to dynamically alter the name at install time (not runtime) however this does not make it desireable. (there is some sample code on Code project http://www.codeproject.com/KB/dotnet/MultipleInstNetWinService.aspx)
I would however be inclined to rethink your approach, service processes themselves are really meant to be singleton, if you need multiple instances of a process being run, maybe your service should just control and manage the multiple processes rather than being the process.
The accepted answer above was awfully helpful.
Code I used:
procedure TService1.ServiceAfterInstall(Sender: TService);
begin
//http://stackoverflow.com/questions/612587/is-it-possible-to-install-multiple-instances-of-the-same-delphi-service-applicati
//http://www.c-sharpcorner.com/UploadFile/timosten/DynamicServiceInCSharp11262005062503AM/DynamicServiceInCSharp.aspx?ArticleID=4d5020e4-7317-425c-ab29-5bf37a1db421
//http://support.microsoft.com/kb/137890
SaveRegSetting('\SYSTEM\CurrentControlSet\Services\' + Name, 'ImagePath', ParamStr(0) + ' --name=' + Name, HKEY_LOCAL_MACHINE)
end;
procedure TService1.ServiceCreate(Sender: TObject);
begin
Name := Trim(FCommandLineOptions.Values['name']);
DisplayName := Name;
end;
SaveRegSetting is my own procedure and FCommandLineOptions is an object that tokenises the command line parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With