Receive ServiceName as Argument using SCM?

G

Guest

I have wrote a Windows Service using C# classes, which contains only one service
I have installed multiple instance of this service
e.g. First service name is "MyService1" and second service name is "MyService2"
They both run same executable, but with different parameter. And I am storing that parameter unde
"..\CurrentControlSet\Services\MyService1\Parameters" and "..\CurrentControlSet\Services\MyService2\Parameters
respectively during installation in registry

I want to receive ServiceName as argument When user Start service with "Service Control Manager"

In my C++ version of the Service, I was using following cod

SERVICE_TABLE_ENTRY st[]

{ L"", ServiceMain }
{ NULL, NULL
}

StartServiceCtrlDispatcher( st )

Which was passing ServiceName in ServiceMain() argument list upon the Start of the Service through "Service Control Manager"

I am looking for similar mechanism in C# code, which I am unable to find
I have tried to call System.ServiceProcess.ServiceBase.Run( new MyServiceBase() ) with blank ServiceName in MyServiceBase class, which does not work

I wrote separate executable to help me start and stop service, where I am passing ServiceName as argument while calling ServiceController.Start()
It works fine, but we don't want to use this executable in our production environment, instead we want to use "Service Control Manager"

I am running out of idea, so any suggestion will help me.
 
M

mwazir

Hi

I had exactly the same problem and I think I have it resolved. I think that
the framework documentation is insufficient in this area as there is not
enough information. I hope MS addresses it. I have my solution implemented
in VB.NET and not C# but I dont think you should have any difficultly
following it.

There are two approaches to having multiple service instances
1 - Where you have multiple instances but one process
2 - Where you have one process for each instance

I find the second option more favourable becauses mutiple service instances
in the same process will share the static functions.

This is how is I did it for the second approach
1. Created 2 Installer classes in my service application
2. Both installer classes have a) ServiceProcessInstaller b)
ServiceInstaller
3. Set the servicename and displaynames in the installer classes to what
ever you want (eg. service1 and service2. There are lots of examples in MSDN
to create the serviceprocessinstaller and serviceinstaller)

4. Override the Install function in both the installer classes

In VB.NET this function is defined as:
Public Overrides Sub Install(ByVal stateSaver As
System.Collections.IDictionary)
' This function is overridden because we need to do some more
installation
' actions "after" the actual installation process.

' Let the project installer do its job
MyBase.Install(stateSaver)

Dim oKey As RegistryKey =
Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Services\" &
Me.ServiceInstaller1.ServiceName, True)
Dim sValue As Object = oKey.GetValue("ImagePath")
sValue = sValue & " " & Me.ServiceInstaller1.ServiceName
oKey.SetValue("ImagePath", sValue)
oKey.SetValue("Description", "Service description.")
oKey.SetValue("ConfigFile", "C:\Program Files\MyServices\" &
Me.ServiceInstaller1.ServiceName & ".xml")
End Sub

5. Allow the Main function to accept the arguments
The ImagePath registry value has been edited to have the servicename as an
argument. This argument is passed to the Main function of the service. I
changed the default Main function to allow args parameter.

' The main entry point for the process
<MTAThread()>_
Shared Sub Main(ByVal args() As String)
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
If args.Length > 0 Then
Dim oService As New myService()
oService.ServiceName = args(0)
ServicesToRun = New System.ServiceProcess.ServiceBase() {oService}
Else
ServicesToRun = New System.ServiceProcess.ServiceBase() {New
myService()}
End If
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
End Sub

The two Installer classes will ensure that there are two seperate service
processes installed pointing to the same exe. This can be confirmed by
looking in the registry under SYSTEM\CurrentControlSet\Services\. The main
entry point is executed twice, once each for the two installer and thus you
will be able to identify the service name for each of your process
instances.

Finally in my OnStart event I now need the name of my config file. The
servicename is now known to us in our instance so I implement a simple
function to return the configuration file location from the registry. I also
make sure I add the configuration file in my setup project to the same
location I have coded in the Install function.

Private Function getConfigFile() As String
' Gets the location of the config file from the windows registry
' Location in the registry
Dim sServiceName As String = Me.ServiceName
Dim oKey As Microsoft.Win32.RegistryKey =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\S
ervices\" & Me.ServiceName, True)
Dim sValue As Object = oKey.GetValue("ConfigFile")
Return sValue
End Function

I hope this helps.

Regards,
Mujahid



Tina said:
I have wrote a Windows Service using C# classes, which contains only one service.
I have installed multiple instance of this service.
e.g. First service name is "MyService1" and second service name is "MyService2".
They both run same executable, but with different parameter. And I am storing that parameter under
"..\CurrentControlSet\Services\MyService1\Parameters" and "..\CurrentControlSet\Services\MyService2\Parameters"
respectively during installation in registry.

I want to receive ServiceName as argument When user Start service with "Service Control Manager".

In my C++ version of the Service, I was using following code

SERVICE_TABLE_ENTRY st[] =
{
{ L"", ServiceMain },
{ NULL, NULL }
};

StartServiceCtrlDispatcher( st );


Which was passing ServiceName in ServiceMain() argument list upon the
Start of the Service through "Service Control Manager".
I am looking for similar mechanism in C# code, which I am unable to find.
I have tried to call System.ServiceProcess.ServiceBase.Run( new
MyServiceBase() ) with blank ServiceName in MyServiceBase class, which does
not work.
I wrote separate executable to help me start and stop service, where I am
passing ServiceName as argument while calling ServiceController.Start().
It works fine, but we don't want to use this executable in our production
environment, instead we want to use "Service Control Manager".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top