Как получить название службы Windows изнутри самой службы - PullRequest
11 голосов
/ 21 апреля 2009

У меня есть несколько win-сервисов, написанных на .NET, которые используют один и тот же исполняемый файл с разными конфигами. Все сервисы записывают в один и тот же файл журнала. Однако, поскольку я использую тот же .exe, служба не знает своего собственного имени службы для добавления в файл журнала.

Есть ли способ, которым мой сервис может программно получить собственное имя?

Ответы [ 2 ]

15 голосов
/ 22 апреля 2009

Понимание можно получить, посмотрев, как 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.

Команды установки / удаления

Чтобы установить службу (можно опустить / Имя для использования DEFAULT_SERVICE_NAME):

installutil.exe /Name=YourServiceName YourService.exe

Чтобы удалить службу (имя не требуется, поскольку оно хранится в 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.
        }
    }
}
10 голосов
/ 03 июня 2011

Я использую эту функцию в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...