How Can a Windows Service Determine Its Servicename

How can a Windows Service determine its ServiceName?

From: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387024

Here is a WMI solution. Overriding the ServiceBase.ServiceMainCallback() might also work, but this seems to work for me...

    protected String GetServiceName()
{
// Calling System.ServiceProcess.ServiceBase::ServiceNamea allways returns
// an empty string,
// see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387024

// So we have to do some more work to find out our service name, this only works if
// the process contains a single service, if there are more than one services hosted
// in the process you will have to do something else

int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
String query = "SELECT * FROM Win32_Service where ProcessId = " + processId;
System.Management.ManagementObjectSearcher searcher =
new System.Management.ManagementObjectSearcher(query);

foreach (System.Management.ManagementObject queryObj in searcher.Get()) {
return queryObj["Name"].ToString();
}

throw new Exception("Can not get the ServiceName");
}

How can I get the ServiceName in a Windows Service written in C#?

Your service needs to inherit ServiceBase from System.ServiceProcess.dll.

When you will have that you will be able to access this.ServiceName property.

Sample:

public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
string test = this.ServiceName;
}

protected override void OnStop()
{
}
}

If you want to access it from Main() (Program class), then you can do something like this:

namespace WindowsService1
{
static class Program
{
static ServiceBase[] _servicesToRun;

static void Main()
{
_servicesToRun = new ServiceBase[]
{
new Service1()
};

string serviceName = _servicesToRun[0].ServiceName;

ServiceBase.Run(_servicesToRun);
}
}
}

How to get name of windows service from inside the service itself

Insight can be gained by looking at how Microsoft does this for the SQL Server service. In the Services control panel, we see:

Service name: MSSQLServer

Path to executable: "C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe" -sMSSQLSERVER

Notice that the name of the service is included as a command line argument. This is how it is made available to the service at run time. With some work, we can accomplish the same thing in .NET.

Basic steps:

  1. Have the installer take the service name as an installer parameter.
  2. Make API calls to set the command line for the service to include the service name.
  3. Modify the Main method to examine the command line and set the ServiceBase.ServiceName property. The Main method is typically in a file called Program.cs.

Install/uninstall commands

To install the service (can omit /Name to use DEFAULT_SERVICE_NAME):

installutil.exe /Name=YourServiceName YourService.exe

To uninstall the service (/Name is never required since it is stored in the stateSaver):

installutil.exe /u YourService.exe

Installer code sample:

using System;
using System.Collections;
using System.Configuration.Install;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;

namespace TestService
{
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private const string DEFAULT_SERVICE_NAME = "TestService";
private const string DISPLAY_BASE_NAME = "Test Service";

private ServiceProcessInstaller _ServiceProcessInstaller;
private ServiceInstaller _ServiceInstaller;

public ProjectInstaller()
{
_ServiceProcessInstaller = new ServiceProcessInstaller();
_ServiceInstaller = new ServiceInstaller();

_ServiceProcessInstaller.Account = ServiceAccount.LocalService;
_ServiceProcessInstaller.Password = null;
_ServiceProcessInstaller.Username = null;

this.Installers.AddRange(new System.Configuration.Install.Installer[] {
_ServiceProcessInstaller,
_ServiceInstaller});
}

public override void Install(IDictionary stateSaver)
{
if (this.Context != null && this.Context.Parameters.ContainsKey("Name"))
stateSaver["Name"] = this.Context.Parameters["Name"];
else
stateSaver["Name"] = DEFAULT_SERVICE_NAME;

ConfigureInstaller(stateSaver);

base.Install(stateSaver);

IntPtr hScm = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (hScm == IntPtr.Zero)
throw new Win32Exception();
try
{
IntPtr hSvc = OpenService(hScm, this._ServiceInstaller.ServiceName, SERVICE_ALL_ACCESS);
if (hSvc == IntPtr.Zero)
throw new Win32Exception();
try
{
QUERY_SERVICE_CONFIG oldConfig;
uint bytesAllocated = 8192; // Per documentation, 8K is max size.
IntPtr ptr = Marshal.AllocHGlobal((int)bytesAllocated);
try
{
uint bytesNeeded;
if (!QueryServiceConfig(hSvc, ptr, bytesAllocated, out bytesNeeded))
{
throw new Win32Exception();
}
oldConfig = (QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(ptr, typeof(QUERY_SERVICE_CONFIG));
}
finally
{
Marshal.FreeHGlobal(ptr);
}

string newBinaryPathAndParameters = oldConfig.lpBinaryPathName + " /s:" + (string)stateSaver["Name"];

if (!ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
newBinaryPathAndParameters, null, IntPtr.Zero, null, null, null, null))
throw new Win32Exception();
}
finally
{
if (!CloseServiceHandle(hSvc))
throw new Win32Exception();
}
}
finally
{
if (!CloseServiceHandle(hScm))
throw new Win32Exception();
}
}

public override void Rollback(IDictionary savedState)
{
ConfigureInstaller(savedState);
base.Rollback(savedState);
}

public override void Uninstall(IDictionary savedState)
{
ConfigureInstaller(savedState);
base.Uninstall(savedState);
}

private void ConfigureInstaller(IDictionary savedState)
{
_ServiceInstaller.ServiceName = (string)savedState["Name"];
_ServiceInstaller.DisplayName = DISPLAY_BASE_NAME + " (" + _ServiceInstaller.ServiceName + ")";
}

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr OpenSCManager(
string lpMachineName,
string lpDatabaseName,
uint dwDesiredAccess);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct QUERY_SERVICE_CONFIG
{
public uint dwServiceType;
public uint dwStartType;
public uint dwErrorControl;
public string lpBinaryPathName;
public string lpLoadOrderGroup;
public uint dwTagId;
public string lpDependencies;
public string lpServiceStartName;
public string lpDisplayName;
}

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool QueryServiceConfig(
IntPtr hService,
IntPtr lpServiceConfig,
uint cbBufSize,
out uint pcbBytesNeeded);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig(
IntPtr hService,
uint dwServiceType,
uint dwStartType,
uint dwErrorControl,
string lpBinaryPathName,
string lpLoadOrderGroup,
IntPtr lpdwTagId,
string lpDependencies,
string lpServiceStartName,
string lpPassword,
string lpDisplayName);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseServiceHandle(
IntPtr hSCObject);

private const uint SERVICE_NO_CHANGE = 0xffffffffu;
private const uint SC_MANAGER_ALL_ACCESS = 0xf003fu;
private const uint SERVICE_ALL_ACCESS = 0xf01ffu;
}
}

Main code sample:

using System;
using System.ServiceProcess;

namespace TestService
{
class Program
{
static void Main(string[] args)
{
string serviceName = null;
foreach (string s in args)
{
if (s.StartsWith("/s:", StringComparison.OrdinalIgnoreCase))
{
serviceName = s.Substring("/s:".Length);
}
}

if (serviceName == null)
throw new InvalidOperationException("Service name not specified on command line.");

// Substitute the name of your class that inherits from ServiceBase.

TestServiceImplementation impl = new TestServiceImplementation();
impl.ServiceName = serviceName;
ServiceBase.Run(impl);
}
}

class TestServiceImplementation : ServiceBase
{
protected override void OnStart(string[] args)
{
// Your service implementation here.
}
}
}

NET START SERVICE - how/where to get the service name?

  1. Start → Run
  2. Then type: services.msc.
  3. Double click on the service that you're interested in.

You should see:

Sample Image

How can I find my service name during startup of a service exe

I found an alternative way to achieve my goal, after reading https://stackoverflow.com/a/7981644/862344

During the install of the webservice, the install program (which happens to be the same program, but with a command-line parameter of "install") knows which settings file to use (because there is a command-line parameter "settings=").

The linked question shows there is a simple way to get that command-line parameter passed to the service every time it starts, by overriding the OnBeforeInstall (and OnBeforeUninstall) methods of the Installer class.

protected override void OnBeforeInstall(System.Collections.IDictionary savedState) {
if (HasCommandParameter("settings")) {
// NB: Framework will surround this value with quotes when storing in registry
Context.Parameters["assemblypath"] += "\" \"settings=" + CommandParameter("settings");
}
base.OnBeforeInstall(savedState);
}

protected override void OnBeforeUninstall(System.Collections.IDictionary savedState) {
if (HasCommandParameter("settings")) {
// NB: Framework will surround this value with quotes when storing in registry
Context.Parameters["assemblypath"] += "\" \"settings=" + CommandParameter("settings");
}
base.OnBeforeUninstall(savedState);
}

I have found that something in the framework surrounds the Context.Parameters["assemblypath"] value with quotes before storing it in the registry (at HKLM\System\CurrentControlSet\Services\\ImagePath), so it is necessary to add '" "' between the existing value (which is the exe path) and the parameter.

How can I get the name of my Windows Service at runtime?

If the code is within the service application, you could do

String source = this.ServiceName;

How to find Display name of a service in .net?

Have you added ProjectInstaller in your windows service project? If yes than in ProjectInstaller you add ServiceInstaller for your service, and in that ServiceInstaller you can specify the display name of the service. Select that serviceinstaller and in properties set its Display Name or in InitializeComponent of ProjectInstaller.Designer.cs or ProjectInstaller.Designer.vb you can specify the display name as:

this.yourServiceInstaller.DisplayName = "Service Display Name";


Related Topics



Leave a reply



Submit