Introduction
I was asked to investigate how we could run multiple instance of one of our services on the same machine. Each instance needed to be passed its own run-time parameters to enable each instance of the service to work with different databases. After searching the internet for a while it became clear that a lot of people wanted to do the same thing and had discovered many different solution to the problem. Some solutions involved code changes to the service. Some solutions involved a complex list of steps involving many steps and utilities. After much experimentation and hair pulling I discovered a simple way of achieving my goal. I decided to write this article to save everyone else the hassle.
The SC Utility – Our Saviour
The Microsoft SC.exe utility program uses the Windows Service API to talk to the Service Control Manager to create, delete and generally control Windows services. SC is much faster and much more powerful than the Installutil.exe program normally used to install and remove Windows services.
Using SC.exe
In order to add additional instance of a service to the Windows Service dialog box, each service must have a unique name. In order to achieve this you will need to use the Windows SC utility. The SC utility communicates with the Service Controller and installed services. SC.exe retrieves and sets control information about services.
To install a service with a different name but using the same binaries you would invoke the SC utility with the following parameters:
sc create <ServiceName> binpath= <BinaryPathName> [displayname= <DisplayName>]
To remove a service you would use the following command:
sc delete <ServiceName>
So let assume you have an installed service called Fred that you want to run another couple of instances of. Fred's binaries are located in c:\services\Fred\currentversion. Here are the commands required to do this:
sc create Fred2 binpath= c:\services\Fred\currentversion\fred.exe
sc create Fred3 binpath= c:\services\Fred\currentversion\fred.exe
If you launched the Windows Service dialog now you would see Fred, Fred2 and Fred3 in the list. You can stop and start each service independently of the others.
One of our other requirements was for each instance of the service to be passed its own unique set of parameters. This can be achieved by using an undocumented facility of the SC utility. When you specify the 'binpath' parameter; if you enclose the specified binary path name in double quotes ("") you can append additional parameters that will be passed to the service at run-time. For example our previous example could be amended to pass parameters to Fred2 and Fred3 as follows:
sc create Fred2 binpath= "c:\services\Fred\currentversion\fred.exe fred2"
sc create Fred3 binpath= "c:\services\Fred\currentversion\fred.exe fred3"
These parameters are not passed through to the service's OnStart(string[] args) method so any parameter processing needs to be done in the program's main entry point. In C# that would be the Program class.
static void Main(string[] args)
{
if (args.Count() > 0)
{
}
Another way to pass run-time parameters to your service is via the Windows Services dialog. This allows you to specify parameters each time you start the service. These parameters are not passed to the Main(string[] args) method but are passed to the service's OnStart(string[] args) override. In C#:
protected override void OnStart(string[] args)
{
if (args.Count() > 0)
{
}
Points of Interest
The SC utility is a little flaky in that all '=' signs MUST be followed by a single space (not documented) or the command will not work. It gives no error message to indicate there is a problem with a particular parameter, it justdoesn't work!
History
30th June 2014 - Initial post.