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

后端 未结 2 451
野趣味
野趣味 2021-02-04 08:12

I have a bunch of win services written in .NET that use same exact executable with different configs. All services write to the same log file. However since I use the same .exe

相关标签:
2条回答
  • 2021-02-04 08:58

    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.
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-04 09:10

    I use this function in VB

    Private Function GetServiceName() As String
        Try
            Dim processId = Process.GetCurrentProcess().Id
            Dim query = "SELECT * FROM Win32_Service where ProcessId  = " & processId.ToString
            Dim searcher As New Management.ManagementObjectSearcher(query)
            Dim share As Management.ManagementObject
            For Each share In searcher.Get()
                Return share("Name").ToString()
            Next share
        Catch ex As Exception
            Dim a = 0
        End Try
        Return "DefaultServiceName"
    End Function
    
    0 讨论(0)
提交回复
热议问题