如何从服务本身获取Windows服务的名称

时间:2009-04-21 17:28:42

标签: .net windows-services

我有一堆用.NET编写的win服务,它们使用相同的可执行文件和不同的配置。所有服务都写入同一个日志文件。但是,由于我使用相同的.exe,服务不知道自己的服务名称要放在日志文件中。

我的服务是否可以以编程方式检索自己的名称?

2 个答案:

答案 0 :(得分:15)

通过查看Microsoft如何为SQL Server服务执行此操作,可以获得洞察力。在“服务”控制面板中,我们看到:

服务名称: MSSQLServer

可执行文件的路径:“C:\ Program Files \ Microsoft SQL Server \ MSSQL.1 \ MSSQL \ Binn \ sqlservr.exe”-s MSSQLSERVER

请注意,服务名称包含在命令行参数中。这是它在运行时可用于服务的方式。通过一些工作,我们可以在.NET中完成同样的事情。

基本步骤:

  1. 让安装程序将服务名称作为安装程序参数。
  2. 进行API调用,将服务的命令行设置为包含服务名称。
  3. 修改Main方法以检查命令行并设置ServiceBase.ServiceName属性。 Main方法通常位于名为Program.cs的文件中。
  4. 安装/卸载命令

    要安装服务(可以省略/ Name以使用DEFAULT_SERVICE_NAME):

    installutil.exe /Name=YourServiceName YourService.exe
    

    要卸载服务(/ Name永远不需要,因为它存储在stateSaver中):

    installutil.exe /u YourService.exe
    

    安装程序代码示例:

    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;
        }
    }
    

    主要代码示例:

    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.
            }
        }
    }
    

答案 1 :(得分:10)

我在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