【问题标题】:How to get name of windows service from inside the service itself如何从服务本身内部获取 Windows 服务的名称
【发布时间】:2009-04-21 17:28:42
【问题描述】:

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

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

【问题讨论】:

    标签: .net windows-services


    【解决方案1】:

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

    服务名称:MSSQLServer

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

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

    基本步骤:

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

    安装/卸载命令

    要安装服务(可以省略 /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.
            }
        }
    }
    

    【讨论】:

    • 我正在使用 WiX 安装我的服务,所以我不需要所有安装程序的东西,我可以直接在 ServiceInstaller 元素中指定参数,但是将名称作为参数传递的整个想法非常棒,非常感谢您的回答!!!
    • 优秀的文章。应该包含在 MSDN 关于设置服务的文章中。
    • 感谢您分享如何通过检查 MSSQLSERVER 服务得出结论。帖子stackoverflow.com/a/5634199/571213 展示了一个非常简单的替代方案。
    【解决方案2】:

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

    【讨论】:

    • 我不知道您可以通过 ProcessId 从 WMI 获取 ServiceName,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 2020-11-03
    • 1970-01-01
    相关资源
    最近更新 更多