【问题标题】:How to install a windows service programmatically in C#?如何在 C# 中以编程方式安装 Windows 服务?
【发布时间】:2010-09-26 09:36:18
【问题描述】:

我的 VS 解决方案中有 3 个项目。其中一个是 Web 应用程序,第二个是 Windows 服务,最后一个是我的 Web 应用程序的安装项目。

我想要的是在我的安装项目中安装网络应用程序结束时,在我的自定义操作中尝试安装我的 Windows 服务,因为那时我已经有了程序集的位置。

【问题讨论】:

    标签: c# .net windows-services setup-project visual-studio-setup-proje


    【解决方案1】:

    我在您重用的代码中发现了几个错误,并已修复这些错误并对其进行了一些清理。同样,原始代码取自here

    public static class ServiceInstaller
    {
        private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
        private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
    
        [StructLayout(LayoutKind.Sequential)]
        private class SERVICE_STATUS
        {
            public int dwServiceType = 0;
            public ServiceState dwCurrentState = 0;
            public int dwControlsAccepted = 0;
            public int dwWin32ExitCode = 0;
            public int dwServiceSpecificExitCode = 0;
            public int dwCheckPoint = 0;
            public int dwWaitHint = 0;
        }
    
        #region OpenSCManager
        [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess);
        #endregion
    
        #region OpenService
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess);
        #endregion
    
        #region CreateService
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
        #endregion
    
        #region CloseServiceHandle
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseServiceHandle(IntPtr hSCObject);
        #endregion
    
        #region QueryServiceStatus
        [DllImport("advapi32.dll")]
        private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus);
        #endregion
    
        #region DeleteService
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteService(IntPtr hService);
        #endregion
    
        #region ControlService
        [DllImport("advapi32.dll")]
        private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus);
        #endregion
    
        #region StartService
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors);
        #endregion
    
        public static void Uninstall(string serviceName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
                if (service == IntPtr.Zero)
                    throw new ApplicationException("Service not installed.");
    
                try
                {
                    StopService(service);
                    if (!DeleteService(service))
                        throw new ApplicationException("Could not delete service " + Marshal.GetLastWin32Error());
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        public static bool ServiceIsInstalled(string serviceName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus);
    
                if (service == IntPtr.Zero)
                    return false;
    
                CloseServiceHandle(service);
                return true;
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        public static void InstallAndStart(string serviceName, string displayName, string fileName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
    
                if (service == IntPtr.Zero)
                    service = CreateService(scm, serviceName, displayName, ServiceAccessRights.AllAccess, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, fileName, null, IntPtr.Zero, null, null, null);
    
                if (service == IntPtr.Zero)
                    throw new ApplicationException("Failed to install service.");
    
                try
                {
                    StartService(service);
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        public static void StartService(string serviceName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Start);
                if (service == IntPtr.Zero)
                    throw new ApplicationException("Could not open service.");
    
                try
                {
                    StartService(service);
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        public static void StopService(string serviceName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Stop);
                if (service == IntPtr.Zero)
                    throw new ApplicationException("Could not open service.");
    
                try
                {
                    StopService(service);
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        private static void StartService(IntPtr service)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
            StartService(service, 0, 0);
            var changedStatus = WaitForServiceStatus(service, ServiceState.StartPending, ServiceState.Running);
            if (!changedStatus)
                throw new ApplicationException("Unable to start service");
        }
    
        private static void StopService(IntPtr service)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
            ControlService(service, ServiceControl.Stop, status);
            var changedStatus = WaitForServiceStatus(service, ServiceState.StopPending, ServiceState.Stopped);
            if (!changedStatus)
                throw new ApplicationException("Unable to stop service");
        }
    
        public static ServiceState GetServiceStatus(string serviceName)
        {
            IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
    
            try
            {
                IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus);
                if (service == IntPtr.Zero)
                    return ServiceState.NotFound;
    
                try
                {
                    return GetServiceStatus(service);
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            finally
            {
                CloseServiceHandle(scm);
            }
        }
    
        private static ServiceState GetServiceStatus(IntPtr service)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
    
            if (QueryServiceStatus(service, status) == 0)
                throw new ApplicationException("Failed to query service status.");
    
            return status.dwCurrentState;
        }
    
        private static bool WaitForServiceStatus(IntPtr service, ServiceState waitStatus, ServiceState desiredStatus)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
    
            QueryServiceStatus(service, status);
            if (status.dwCurrentState == desiredStatus) return true;
    
            int dwStartTickCount = Environment.TickCount;
            int dwOldCheckPoint = status.dwCheckPoint;
    
            while (status.dwCurrentState == waitStatus)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.
    
                int dwWaitTime = status.dwWaitHint / 10;
    
                if (dwWaitTime < 1000) dwWaitTime = 1000;
                else if (dwWaitTime > 10000) dwWaitTime = 10000;
    
                Thread.Sleep(dwWaitTime);
    
                // Check the status again.
    
                if (QueryServiceStatus(service, status) == 0) break;
    
                if (status.dwCheckPoint > dwOldCheckPoint)
                {
                    // The service is making progress.
                    dwStartTickCount = Environment.TickCount;
                    dwOldCheckPoint = status.dwCheckPoint;
                }
                else
                {
                    if (Environment.TickCount - dwStartTickCount > status.dwWaitHint)
                    {
                        // No progress made within the wait hint
                        break;
                    }
                }
            }
            return (status.dwCurrentState == desiredStatus);
        }
    
        private static IntPtr OpenSCManager(ScmAccessRights rights)
        {
            IntPtr scm = OpenSCManager(null, null, rights);
            if (scm == IntPtr.Zero)
                throw new ApplicationException("Could not connect to service control manager.");
    
            return scm;
        }
    }
    
    
    public enum ServiceState
    {
        Unknown = -1, // The state cannot be (has not been) retrieved.
        NotFound = 0, // The service is not known on the host server.
        Stopped = 1,
        StartPending = 2,
        StopPending = 3,
        Running = 4,
        ContinuePending = 5,
        PausePending = 6,
        Paused = 7
    }
    
    [Flags]
    public enum ScmAccessRights
    {
        Connect = 0x0001,
        CreateService = 0x0002,
        EnumerateService = 0x0004,
        Lock = 0x0008,
        QueryLockStatus = 0x0010,
        ModifyBootConfig = 0x0020,
        StandardRightsRequired = 0xF0000,
        AllAccess = (StandardRightsRequired | Connect | CreateService |
                     EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
    }
    
    [Flags]
    public enum ServiceAccessRights
    {
        QueryConfig = 0x1,
        ChangeConfig = 0x2,
        QueryStatus = 0x4,
        EnumerateDependants = 0x8,
        Start = 0x10,
        Stop = 0x20,
        PauseContinue = 0x40,
        Interrogate = 0x80,
        UserDefinedControl = 0x100,
        Delete = 0x00010000,
        StandardRightsRequired = 0xF0000,
        AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig |
                     QueryStatus | EnumerateDependants | Start | Stop | PauseContinue |
                     Interrogate | UserDefinedControl)
    }
    
    public enum ServiceBootFlag
    {
        Start = 0x00000000,
        SystemStart = 0x00000001,
        AutoStart = 0x00000002,
        DemandStart = 0x00000003,
        Disabled = 0x00000004
    }
    
    public enum ServiceControl
    {
        Stop = 0x00000001,
        Pause = 0x00000002,
        Continue = 0x00000003,
        Interrogate = 0x00000004,
        Shutdown = 0x00000005,
        ParamChange = 0x00000006,
        NetBindAdd = 0x00000007,
        NetBindRemove = 0x00000008,
        NetBindEnable = 0x00000009,
        NetBindDisable = 0x0000000A
    }
    
    public enum ServiceError
    {
        Ignore = 0x00000000,
        Normal = 0x00000001,
        Severe = 0x00000002,
        Critical = 0x00000003
    }
    

    如果有人发现此代码有任何问题,请告诉我!

    【讨论】:

    • 我正在尝试使用此代码。但我有一个问题。我的服务中的代码取决于(需要)服务的名称。虽然我使用这个方法InstallService 和一个特定的服务名称,但如果我在我的服务中查询ServiceBaseServiceName 属性,它总是返回给我别的东西。有关如何从服务内部实际获取该名称的任何建议?
    • 您将如何将它与 ServiceInstaller 和 ServiceProcessInstaller 结合使用?
    • 非常感谢拉斯!这段代码似乎完全符合我的需要,但我不得不改变一些事情,因为它不耐烦。 “WaitForServiceStatus”功能中断,我收到“无法启动服务”错误,即使服务实际上正在启动。我摆脱了很多检查,现在我有一个潜在的无限循环,但它可以工作......也许你知道为什么函数没有等待?
    • 据我记忆,服务状态变化的速度是高度不可预测的(卸载也是如此)。我认为文档也提到了这一点。
    • 该代码在哪个许可证下?我可以在 MS-PL 项目中使用它吗?
    【解决方案2】:

    好的,这对我来说真的很有效,它已经在多台具有不同操作系统(Vista、XP、Win2k、Win2003 服务器)的机器上进行了测试

    代码取自here,因此完全归功于编写这段代码的人。

    一旦您将 dll 或源文件添加到您的项目中,请确保添加 ServiceTools 命名空间,然后您就可以访问一些非常方便的功能,例如...

    //Installs and starts the service
    ServiceInstaller.InstallAndStart("MyServiceName", "MyServiceDisplayName", "C:\\PathToServiceFile.exe");
    
    //Removes the service
    ServiceInstaller.Uninstall("MyServiceName");
    
    //Checks the status of the service
    ServiceInstaller.GetServiceStatus("MyServiceName");
    
    //Starts the service
    ServiceInstaller.StartService("MyServiceName");
    
    //Stops the service
    ServiceInstaller.StopService("MyServiceName");
    
    //Check if service is installed
    ServiceInstaller.ServiceIsInstalled("MyServiceName");
    

    我希望这会有所帮助。

    【讨论】:

    • 我已经发布了一个答案,其中包含对您发布的代码的一些错误修复。查看您在其中找到代码的讨论帖,您会发现代码的作者意识到其中存在一些错误。
    • 我参考的帖子是:tech-archive.net/Archive/VB/microsoft.public.vb.winapi/2006-08/… 另外,我发现了另外一两个错误,服务句柄没有释放。
    • 当你想要的只是在公园里安静地散步时,这个解决方案看起来就像是与一只 25 头的九头蛇搏斗......必须有一个更简单的方法
    • 如何设置服务应该在哪个用户和密码下运行?我也可以使用上面提到的ServiceInstaller吗?
    • 如果安装时间超过10秒,会报失败。
    【解决方案3】:

    请查看this article


    有时您可能希望以编程方式安装 Windows 服务,但目标计算机没有 InstallUtil.exe。

    添加对System.Configuration.Install的引用

    使用下面的代码。

    请注意,exeFileName 是 InstallerClass .exe 而不是 ServiceClass .exe。

    public static void InstallService(string exeFilename)
    {
        string[] commandLineOptions = new string[1] { "/LogFile=install.log" };
    
        System.Configuration.Install.AssemblyInstaller installer = new System.Configuration.Install.AssemblyInstaller(exeFilename, commandLineOptions);
    
        installer.UseNewContext = true;    
        installer.Install(null);    
        installer.Commit(null);
    
    }
    

    卸载:

    public static void UninstallService(string exeFilename)
    {
        string[] commandLineOptions = new string[1] { "/LogFile=uninstall.log" };
    
        System.Configuration.Install.AssemblyInstaller installer = new System.Configuration.Install.AssemblyInstaller(exeFilename, commandLineOptions);
    
        installer.UseNewContext = true;    
        installer.Uninstall(null);
    
    }
    

    【讨论】:

    • 我已经尝试过了,但它不起作用。没有例外或其他什么,它只是不安装服务
    • 可能是完整路径或凭据问题> 你可以尝试编写一个简单的服务。您是否也尝试过使用上面的 url,其中 SCM 在 C# 中使用 P/Invoke 调用适当的 API
    • 我的编译器抱怨说 AssemblyInstaller(ExeFilename) 消耗了多个参数 - 它实际上似乎有 3 个重载 - 一个没有参数,另外两个每个有 2 个参数。自从你们发布后,有什么变化吗?
    • 这是将程序集安装为服务的正确方法。如果它不适合你,那么你做错了什么!您不需要所有其他第三部分代码。谢谢 lakshmanaraj!
    • 这应该是公认的答案。这很简单,而且很有效。 (由于缺少第二个参数,我建议进行编辑。此外,您应该引用 InstallerClass 而不是 ServiceClass 作为 exeFileName)。
    【解决方案4】:

    在为我的服务(非常基本)创建安装程序类的实例后,我所要做的就是调用:

    ManagedInstallerClass.InstallHelper(new string[] { 
        Assembly.GetExecutingAssembly().Location });
    

    安装它并

    ManagedInstallerClass.InstallHelper(new string[] { "/u", 
        Assembly.GetExecutingAssembly().Location });
    

    卸载服务。此处,调用代码与服务可执行文件位于同一程序集中。

    要通过命令行安装服务,我所要做的就是通过命令行参数将其连接到可执行文件并测试System.Environment.UserInteractive 以了解它是正在执行的服务还是有人试图安装-卸载它瞧……没有时髦的互操作的东西……没有指针泄漏……

    总共大约 20 行代码分布在两个类中。

    要替换 InstallUtil,只需查看 ManagedInstallerClass.InstallHelper

    【讨论】:

    • 简单。在反映到 InstallUtil.exe 时,您可能会得出相同的结论。它做同样的事情。此外,它还有一些有趣的控制台编码修正。安装和卸载工作正常。 (记得以管理员身份运行...)
    【解决方案5】:

    通过使用Topshelf 项目,您可以通过调用可执行文件来安装:

    MyService.exe install
    

    Topshelf 还负责其他 Windows 服务管道。

    【讨论】:

      【解决方案6】:

      因为我面临以编程方式安装在特定用户下运行的服务的挑战。我扩展了InstallAndStart 方法以使用lplpPassword...

      不多,但可能会有所帮助。

      public static void InstallAndStart(
          string serviceName, 
          string displayName, 
          string fileName, 
          string username, 
          string password)
      {
          IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess);
      
          try
          {
              IntPtr service = OpenService(
                  scm, 
                  serviceName, 
                  ServiceAccessRights.AllAccess);
      
              if (service == IntPtr.Zero)
                  service = CreateService(
                      scm, 
                      serviceName, 
                      displayName, 
                      ServiceAccessRights.AllAccess, 
                      SERVICE_WIN32_OWN_PROCESS, 
                      ServiceBootFlag.AutoStart, 
                      ServiceError.Normal, 
                      fileName, 
                      null, 
                      IntPtr.Zero, 
                      null, 
                      username, 
                      password);
      
              if (service == IntPtr.Zero)
                  throw new ApplicationException("Failed to install service.");
      
              try
              {
                  StartService(service);
              }
              finally
              {
                  CloseServiceHandle(service);
              }
          }
          finally
          {
              CloseServiceHandle(scm);
          }
      }
      

      【讨论】:

        【解决方案7】:

        我使用 Lars answer 来管理我的服务,它运行良好。但是我需要将参数传递给服务,我花了几个小时才弄清楚如何去做。因此,我决定发布具有使用参数启动服务的能力的更改类:

            public static class ServiceHelper
            {
                private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
                private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
        
                [StructLayout(LayoutKind.Sequential)]
                private class SERVICE_STATUS
                {
                    public int dwServiceType = 0;
                    public ServiceState dwCurrentState = 0;
                    public int dwControlsAccepted = 0;
                    public int dwWin32ExitCode = 0;
                    public int dwServiceSpecificExitCode = 0;
                    public int dwCheckPoint = 0;
                    public int dwWaitHint = 0;
                }
        
                #region OpenSCManager
                [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
                static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess);
                #endregion
        
                #region OpenService
                [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
                static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess);
                #endregion
        
                #region CreateService
                [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
                private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
                #endregion
        
                #region CloseServiceHandle
                [DllImport("advapi32.dll", SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                static extern bool CloseServiceHandle(IntPtr hSCObject);
                #endregion
        
                #region QueryServiceStatus
                [DllImport("advapi32.dll")]
                private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus);
                #endregion
        
                #region DeleteService
                [DllImport("advapi32.dll", SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                private static extern bool DeleteService(IntPtr hService);
                #endregion
        
                #region ControlService
                [DllImport("advapi32.dll")]
                private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus);
                #endregion
        
                #region StartService
                [DllImport("advapi32.dll", SetLastError = true)]
                private static extern int StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
                #endregion
        
                public static void Uninstall(string serviceName)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
                        if (service == IntPtr.Zero)
                            throw new ApplicationException("Service not installed.");
        
                        try
                        {
                            StopService(service);
                            if (!DeleteService(service))
                                throw new ApplicationException("Could not delete service " + Marshal.GetLastWin32Error());
                        }
                        finally
                        {
                            CloseServiceHandle(service);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                public static bool ServiceIsInstalled(string serviceName)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus);
        
                        if (service == IntPtr.Zero)
                            return false;
        
                        CloseServiceHandle(service);
                        return true;
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                public static void InstallAndStart(string serviceName, string displayName, string fileName,string[] args)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.AllAccess);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
        
                        if (service == IntPtr.Zero)
                            service = CreateService(scm, serviceName, displayName, ServiceAccessRights.AllAccess, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, fileName, null, IntPtr.Zero, null, null, null);
        
                        if (service == IntPtr.Zero)
                            throw new ApplicationException("Failed to install service.");
        
                        try
                        {
                            StartService(service,args);
                        }
                        finally
                        {
                            CloseServiceHandle(service);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                public static void StartService(string serviceName,string[] args)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Start);
                        if (service == IntPtr.Zero)
                            throw new ApplicationException("Could not open service.");
        
                        try
                        {
                            StartService(service,args);
                        }
                        finally
                        {
                            CloseServiceHandle(service);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                public static void StopService(string serviceName)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Stop);
                        if (service == IntPtr.Zero)
                            throw new ApplicationException("Could not open service.");
        
                        try
                        {
                            StopService(service);
                        }
                        finally
                        {
                            CloseServiceHandle(service);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                private static void StartService(IntPtr service,string[] args)
                {
                    SERVICE_STATUS status = new SERVICE_STATUS();
                    StartService(service, args.Length, args);
                    var changedStatus = WaitForServiceStatus(service, ServiceState.StartPending, ServiceState.Running);
                    if (!changedStatus)
                        throw new ApplicationException("Unable to start service");
                }
        
                private static void StopService(IntPtr service)
                {
                    SERVICE_STATUS status = new SERVICE_STATUS();
                    ControlService(service, ServiceControl.Stop, status);
                    var changedStatus = WaitForServiceStatus(service, ServiceState.StopPending, ServiceState.Stopped);
                    if (!changedStatus)
                        throw new ApplicationException("Unable to stop service");
                }
        
                public static ServiceState GetServiceStatus(string serviceName)
                {
                    IntPtr scm = OpenSCManager(ScmAccessRights.Connect);
        
                    try
                    {
                        IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus);
                        if (service == IntPtr.Zero)
                            return ServiceState.NotFound;
        
                        try
                        {
                            return GetServiceStatus(service);
                        }
                        finally
                        {
                            CloseServiceHandle(service);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(scm);
                    }
                }
        
                private static ServiceState GetServiceStatus(IntPtr service)
                {
                    SERVICE_STATUS status = new SERVICE_STATUS();
        
                    if (QueryServiceStatus(service, status) == 0)
                        throw new ApplicationException("Failed to query service status.");
        
                    return status.dwCurrentState;
                }
        
                private static bool WaitForServiceStatus(IntPtr service, ServiceState waitStatus, ServiceState desiredStatus)
                {
                    SERVICE_STATUS status = new SERVICE_STATUS();
        
                    QueryServiceStatus(service, status);
                    if (status.dwCurrentState == desiredStatus) return true;
        
                    int dwStartTickCount = Environment.TickCount;
                    int dwOldCheckPoint = status.dwCheckPoint;
        
                    while (status.dwCurrentState == waitStatus)
                    {
                        // Do not wait longer than the wait hint. A good interval is
                        // one tenth the wait hint, but no less than 1 second and no
                        // more than 10 seconds.
        
                        int dwWaitTime = status.dwWaitHint / 10;
        
                        if (dwWaitTime < 1000) dwWaitTime = 1000;
                        else if (dwWaitTime > 10000) dwWaitTime = 10000;
        
                        Thread.Sleep(dwWaitTime);
        
                        // Check the status again.
        
                        if (QueryServiceStatus(service, status) == 0) break;
        
                        if (status.dwCheckPoint > dwOldCheckPoint)
                        {
                            // The service is making progress.
                            dwStartTickCount = Environment.TickCount;
                            dwOldCheckPoint = status.dwCheckPoint;
                        }
                        else
                        {
                            if (Environment.TickCount - dwStartTickCount > status.dwWaitHint)
                            {
                                // No progress made within the wait hint
                                break;
                            }
                        }
                    }
                    return (status.dwCurrentState == desiredStatus);
                }
        
                private static IntPtr OpenSCManager(ScmAccessRights rights)
                {
                    IntPtr scm = OpenSCManager(null, null, rights);
                    if (scm == IntPtr.Zero)
                        throw new ApplicationException("Could not connect to service control manager.");
        
                    return scm;
                }
            }
        
        
            public enum ServiceState
            {
                Unknown = -1, // The state cannot be (has not been) retrieved.
                NotFound = 0, // The service is not known on the host server.
                Stopped = 1,
                StartPending = 2,
                StopPending = 3,
                Running = 4,
                ContinuePending = 5,
                PausePending = 6,
                Paused = 7
            }
        
            [Flags]
            public enum ScmAccessRights
            {
                Connect = 0x0001,
                CreateService = 0x0002,
                EnumerateService = 0x0004,
                Lock = 0x0008,
                QueryLockStatus = 0x0010,
                ModifyBootConfig = 0x0020,
                StandardRightsRequired = 0xF0000,
                AllAccess = (StandardRightsRequired | Connect | CreateService |
                             EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
            }
        
            [Flags]
            public enum ServiceAccessRights
            {
                QueryConfig = 0x1,
                ChangeConfig = 0x2,
                QueryStatus = 0x4,
                EnumerateDependants = 0x8,
                Start = 0x10,
                Stop = 0x20,
                PauseContinue = 0x40,
                Interrogate = 0x80,
                UserDefinedControl = 0x100,
                Delete = 0x00010000,
                StandardRightsRequired = 0xF0000,
                AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig |
                             QueryStatus | EnumerateDependants | Start | Stop | PauseContinue |
                             Interrogate | UserDefinedControl)
            }
        
            public enum ServiceBootFlag
            {
                Start = 0x00000000,
                SystemStart = 0x00000001,
                AutoStart = 0x00000002,
                DemandStart = 0x00000003,
                Disabled = 0x00000004
            }
        
            public enum ServiceControl
            {
                Stop = 0x00000001,
                Pause = 0x00000002,
                Continue = 0x00000003,
                Interrogate = 0x00000004,
                Shutdown = 0x00000005,
                ParamChange = 0x00000006,
                NetBindAdd = 0x00000007,
                NetBindRemove = 0x00000008,
                NetBindEnable = 0x00000009,
                NetBindDisable = 0x0000000A
            }
        
            public enum ServiceError
            {
                Ignore = 0x00000000,
                Normal = 0x00000001,
                Severe = 0x00000002,
                Critical = 0x00000003
            }
        

        【讨论】:

          【解决方案8】:

          在这篇文章中,我阅读了所有帖子和 cmets 但我仍然不知道如何设置帐户类型和 StartType 方法,当我要添加 Windows 服务时。这个代码示例在我这边运行良好,它只是添加了一个服务自己的本地系统)但是我准备安装程序我必须考虑 StartModeUser Account Type 方法,因为客户系统。 ServiceBootFlag 枚举似乎提供了 StartType,但 Account Type 仍然是个问题。

              [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")]
          
              private static extern IntPtr CreateService(IntPtr hSCManager, string
          
              lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int
          
              dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl,
          
              string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string
          
              lpDependencies, string lp, string lpPassword); 
          

          【讨论】:

            【解决方案9】:

            使用以下代码使用 C# 安装 windows 服务:

            public void InstallWinService(string winServicePath)
            {
                    try
                    {
                        ManagedInstallerClass.InstallHelper(new string[] { winServicePath});
                    }
                    catch (Exception)
                    {
            
                        throw;
                    }
            }
            

            【讨论】:

              【解决方案10】:

              另一种方法是在命令提示符下使用 SC.exe:

               System.Diagnostics.Process process = new System.Diagnostics.Process();
               System.Diagnostics.ProcessStartInfo startInfo = new 
               System.Diagnostics.ProcessStartInfo();
               startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
               startInfo.FileName = "cmd.exe";
               startInfo.Arguments = "/C sc create MyService binpath=\"c:\\...\\MyService.exe\"";
               process.StartInfo = startInfo;
               process.Start();
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-04-07
                • 1970-01-01
                • 2023-03-25
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多