如何在 C# 中以编程方式安装 Windows 服务?

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案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();

【讨论】:

以上是关于如何在 C# 中以编程方式安装 Windows 服务?的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中以编程方式设置 Windows XP Embedded 区域设置

如果应用程序具有应用程序清单,如何在 C# 中以编程方式获取?

在c#中以编程方式查询网卡的入站/出站IPv4数据包计数统计

如何在 Windows 10 及更高版本中以编程方式刷新任务栏?

如何在 C# 中以编程方式获取 Lync 会议 URL?

如何在 C# 中以编程方式搜索 PDF 文档 [关闭]