• Windows服务安装与控制


    Windows服务安装与控制

    1、建立服务

      (1)定义一个ServiceInstaller

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WindowService
    {
        [System.ComponentModel.RunInstaller(true)]
        public class ServiceInstaller : System.Configuration.Install.Installer
        {
            System.ServiceProcess.ServiceProcessInstaller processInstaller;
            System.ServiceProcess.ServiceInstaller serviceInstaller;
            public ServiceInstaller()
            {
                processInstaller = new System.ServiceProcess.ServiceProcessInstaller();
                processInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
                Installers.Add(processInstaller);
    
                serviceInstaller = new System.ServiceProcess.ServiceInstaller();
                serviceInstaller.DisplayName = "000000000";
                serviceInstaller.ServiceName = "000000000";
                serviceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
                
                Installers.Add(serviceInstaller);
            }
            protected override void OnAfterInstall(System.Collections.IDictionary savedState)
            {
                base.OnAfterInstall(savedState);
    
            }
        }
    }

    (2)定义一个服务

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    
    namespace WindowService
    {
        partial class Service : ServiceBase
        {
            public Service()
            {
                InitializeComponent();
            }
            
            protected override void OnStart(string[] args)
            {
                
                // TODO:  在此处添加代码以启动服务。
            }
    
            protected override void OnStop()
            {
                // TODO:  在此处添加代码以执行停止服务所需的关闭操作。
            }
        }
    }

    (3)定义自己的安装方式:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    
    namespace WindowService
    {
        public class ServiceMaster
        {
            static string appPath = Assembly.GetExecutingAssembly().Location;
            public static void Main(string[] args)
            {
                if (args != null && args.Length > 0)
                {
                    if (args[0] == "-i")
                    {
                        InstallService();
                    }
                    else if (args[0] == "-u")
                    {
                        UninstallService();
                    }
    
                }
                else
                {
                    var s = new Service() { ServiceName = "aaaaa" };
                    Service.Run(s);
                }
            }
            public static void InstallService()
            {
                System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { appPath });
            }
    
            public static void UninstallService()
            {
                System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { "-u", appPath });
            }
        }
    }

    安装时,使用管理员权限运行cmd,输入程序带参数"-i"执行即可安装。这是使用的ManagedInstallerClass类的安装。接下来对上面这个服务使用另一种安装方式。

    2、Windows Api安装方式。

    (1)辅助类的设计

    using System;
    using System.ComponentModel;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    
    namespace Yihe.Service
    {
        #region 异常定义
    
        /// <summary>
        /// 服务不存在异常
        /// </summary>
        public class ServiceNotExistException : ApplicationException
        {
            public ServiceNotExistException() : base("服务不存在!") { }
    
            public ServiceNotExistException(string message) : base(message) { }
        }
    
        #endregion
    
        #region 枚举定义
    
        /// <summary>
        /// 服务启动类型
        /// </summary>
        public enum ServiceStartType
        {
            Boot,
            System,
            Auto,
            Manual,
            Disabled
        }
    
        /// <summary>
        /// 服务运行帐户
        /// </summary>
        public enum ServiceAccount
        {
            LocalSystem,
            LocalService,
            NetworkService,
        }
    
        #endregion
    
        /// <summary>
        /// Windows 服务辅助类
        /// </summary>
        public static class ServiceHelper
        {
            #region 公开方法
    
            /// <summary>
            /// 安装服务
            /// </summary>
            /// <param name="serviceName">服务名</param>
            /// <param name="displayName">友好名称</param>
            /// <param name="binaryFilePath">映像文件路径,可带参数</param>
            /// <param name="description">服务描述</param>
            /// <param name="startType">启动类型</param>
            /// <param name="account">启动账户</param>
            /// <param name="dependencies">依赖服务</param>
            public static void Install(string serviceName, string displayName, string binaryFilePath, string description, ServiceStartType startType, ServiceAccount account = ServiceAccount.LocalSystem, string[] dependencies = null)
            {
                IntPtr scm = OpenSCManager();
    
                IntPtr service = IntPtr.Zero;
                try
                {
    
                    service = Win32Class.CreateService(scm, serviceName, displayName, Win32Class.SERVICE_ALL_ACCESS, Win32Class.SERVICE_WIN32_OWN_PROCESS, startType, Win32Class.SERVICE_ERROR_NORMAL, binaryFilePath, null, IntPtr.Zero, ProcessDependencies(dependencies), GetServiceAccountName(account), null);
    
                    if (service == IntPtr.Zero)
                    {
                        if (Marshal.GetLastWin32Error() == 0x431)//ERROR_SERVICE_EXISTS
                        { throw new ApplicationException("服务已存在!"); }
    
                        throw new ApplicationException("服务安装失败!");
                    }
    
                    //设置服务描述
                    Win32Class.SERVICE_DESCRIPTION sd = new Win32Class.SERVICE_DESCRIPTION();
                    try
                    {
                        sd.description = Marshal.StringToHGlobalUni(description);
                        Win32Class.ChangeServiceConfig2(service, 1, ref sd);
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(sd.description); //释放
                    }
                }
                finally
                {
                    if (service != IntPtr.Zero)
                    {
                        Win32Class.CloseServiceHandle(service);
                    }
                    Win32Class.CloseServiceHandle(scm);
                }
            }
    
            /// <summary>
            /// 卸载服务
            /// </summary>
            /// <param name="serviceName">服务名</param>
            public static void Uninstall(string serviceName)
            {
                IntPtr scmHandle = IntPtr.Zero;
                IntPtr service = IntPtr.Zero;
    
                try
                {
                    service = OpenService(serviceName, out scmHandle);
    
                    StopService(service); //停止服务。里面会递归停止从属服务
    
                    if (!Win32Class.DeleteService(service) && Marshal.GetLastWin32Error() != 0x430) //忽略已标记为删除的服务。ERROR_SERVICE_MARKED_FOR_DELETE
                    {
                        throw new ApplicationException("删除服务失败!");
                    }
                }
                catch (ServiceNotExistException) { } //忽略服务不存在的情况
                finally
                {
                    if (service != IntPtr.Zero)
                    {
                        Win32Class.CloseServiceHandle(service);
                        Win32Class.CloseServiceHandle(scmHandle);//放if里面是因为如果服务打开失败,在OpenService里就已释放SCM
                    }
                }
            }
    
            #endregion
    
            #region 辅助方法
    
            /// <summary>
            /// 转换帐户枚举为有效参数
            /// </summary>
            public static string GetServiceAccountName(ServiceAccount account)
            {
                if (account == ServiceAccount.LocalService)
                {
                    return @"NT AUTHORITYLocalService";
                }
                if (account == ServiceAccount.NetworkService)
                {
                    return @"NT AUTHORITYNetworkService";
                }
                return null;
            }
    
            /// <summary>
            /// 处理依赖服务参数
            /// </summary>
            public static string ProcessDependencies(string[] dependencies)
            {
                if (dependencies == null || dependencies.Length == 0)
                {
                    return null;
                }
    
                StringBuilder sb = new StringBuilder();
                foreach (string s in dependencies)
                {
                    sb.Append(s).Append('');
                }
                sb.Append('');
    
                return sb.ToString();
            }
    
            #endregion
    
            #region API 封装方法
    
            /// <summary>
            /// 打开服务管理器
            /// </summary>
            public static IntPtr OpenSCManager()
            {
                IntPtr scm = Win32Class.OpenSCManager(null, null, Win32Class.SC_MANAGER_ALL_ACCESS);
    
                if (scm == IntPtr.Zero)
                {
                    throw new ApplicationException("打开服务管理器失败!");
                }
    
                return scm;
            }
    
            /// <summary>
            /// 打开服务
            /// </summary>
            /// <param name="serviceName">服务名称</param>
            /// <param name="scmHandle">服务管理器句柄。供调用者释放</param>
            public static IntPtr OpenService(string serviceName, out IntPtr scmHandle)
            {
                scmHandle = OpenSCManager();
    
                IntPtr service = Win32Class.OpenService(scmHandle, serviceName, Win32Class.SERVICE_ALL_ACCESS);
    
                if (service == IntPtr.Zero)
                {
                    int errCode = Marshal.GetLastWin32Error();
    
                    Win32Class.CloseServiceHandle(scmHandle); //关闭SCM
    
                    if (errCode == 0x424) //ERROR_SERVICE_DOES_NOT_EXIST
                    {
                        throw new ServiceNotExistException();
                    }
    
                    throw new Win32Exception();
                }
    
                return service;
            }
            private static bool ExistService(string serviceName)
            {
                IntPtr scmHandle = IntPtr.Zero;
                IntPtr handle = IntPtr.Zero;
                try
                {
                    handle = OpenService(serviceName, out scmHandle);
                    if (handle == IntPtr.Zero)
                    {
                        int errCode = Marshal.GetLastWin32Error();
                        if (errCode == 0x424)
                        { return false; }
                    }
                }
                catch (ServiceNotExistException e) { return false; }
                finally
                {
                    Win32Class.CloseServiceHandle(scmHandle); //关闭SCM
                    Win32Class.CloseServiceHandle(handle); //关闭服务
                }
                return true;
            }
            public static bool StartService(string serviceName, TimeSpan timeSpan)
            {
                if (!ExistService(serviceName)) return false;
                System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(serviceName);
                if (sc.Status != System.ServiceProcess.ServiceControllerStatus.Running && sc.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
                {
                    sc.Start();
                }
                sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running, timeSpan);
                return sc.Status == System.ServiceProcess.ServiceControllerStatus.Running;
            }
    
    
            public static bool StopService(string serviceName, TimeSpan timeSpan)
            {
                if (!ExistService(serviceName)) return false;
                System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(serviceName);
                if (sc.Status != System.ServiceProcess.ServiceControllerStatus.Stopped && sc.Status != System.ServiceProcess.ServiceControllerStatus.StopPending)
                {
                    sc.Stop();
                }
                sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped, timeSpan);
                var isok = sc.Status == System.ServiceProcess.ServiceControllerStatus.Stopped;
                sc.Close();
                sc.Dispose();
                return isok;
            }
            /// <summary>
            /// 停止服务
            /// </summary>
            public static void StopService(IntPtr service)
            {
                ServiceState currState = GetServiceStatus(service);
    
                if (currState == ServiceState.Stopped)
                {
                    return;
                }
    
                if (currState != ServiceState.StopPending)
                {
                    //递归停止从属服务
                    string[] childSvs = EnumDependentServices(service, EnumServiceState.Active);
                    if (childSvs.Length != 0)
                    {
                        IntPtr scm = OpenSCManager();
                        try
                        {
                            foreach (string childSv in childSvs)
                            {
                                StopService(Win32Class.OpenService(scm, childSv, Win32Class.SERVICE_STOP));
                            }
                        }
                        finally
                        {
                            Win32Class.CloseServiceHandle(scm);
                        }
                    }
    
                    Win32Class.SERVICE_STATUS status = new Win32Class.SERVICE_STATUS();
                    Win32Class.ControlService(service, Win32Class.SERVICE_CONTROL_STOP, ref status); //发送停止指令
                }
    
                if (!WaitForStatus(service, ServiceState.Stopped, new TimeSpan(0, 0, 30)))
                {
                    throw new ApplicationException("停止服务失败!");
                }
            }
    
            /// <summary>
            /// 遍历从属服务
            /// </summary>
            /// <param name="serviceHandle"></param>
            /// <param name="state">选择性遍历(活动、非活动、全部)</param>
            public static string[] EnumDependentServices(IntPtr serviceHandle, EnumServiceState state)
            {
                int bytesNeeded = 0; //存放从属服务的空间大小,由API返回
                int numEnumerated = 0; //从属服务数,由API返回
    
                //先尝试以空结构获取,如获取成功说明从属服务为空,否则拿到上述俩值
                if (Win32Class.EnumDependentServices(serviceHandle, state, IntPtr.Zero, 0, ref bytesNeeded, ref numEnumerated))
                {
                    return new string[0];
                }
                if (Marshal.GetLastWin32Error() != 0xEA) //仅当错误值不是大小不够(ERROR_MORE_DATA)时才抛异常
                {
                    throw new Win32Exception();
                }
    
                //在非托管区域创建指针
                IntPtr structsStart = Marshal.AllocHGlobal(new IntPtr(bytesNeeded));
                try
                {
                    //往上述指针处塞存放从属服务的结构组,每个从属服务是一个结构
                    if (!Win32Class.EnumDependentServices(serviceHandle, state, structsStart, bytesNeeded, ref bytesNeeded, ref numEnumerated))
                    {
                        throw new Win32Exception();
                    }
    
                    string[] dependentServices = new string[numEnumerated];
                    int sizeOfStruct = Marshal.SizeOf(typeof(Win32Class.ENUM_SERVICE_STATUS)); //每个结构的大小
                    long structsStartAsInt64 = structsStart.ToInt64();
                    for (int i = 0; i < numEnumerated; i++)
                    {
                        Win32Class.ENUM_SERVICE_STATUS structure = new Win32Class.ENUM_SERVICE_STATUS();
                        IntPtr ptr = new IntPtr(structsStartAsInt64 + i * sizeOfStruct); //根据起始指针、结构次序和结构大小推算各结构起始指针
                        Marshal.PtrToStructure(ptr, structure); //根据指针拿到结构
                        dependentServices[i] = structure.serviceName; //从结构中拿到服务名
                    }
    
                    return dependentServices;
                }
                finally
                {
                    Marshal.FreeHGlobal(structsStart);
                }
            }
    
            /// <summary>
            /// 获取服务状态
            /// </summary>
            public static ServiceState GetServiceStatus(IntPtr service)
            {
                Win32Class.SERVICE_STATUS status = new Win32Class.SERVICE_STATUS();
    
                if (!Win32Class.QueryServiceStatus(service, ref status))
                {
                    throw new ApplicationException("获取服务状态出错!");
                }
    
                return status.currentState;
            }
    
            /// <summary>
            /// 等候服务至目标状态
            /// </summary>
            public static bool WaitForStatus(IntPtr serviceHandle, ServiceState desiredStatus, TimeSpan timeout)
            {
                DateTime startTime = DateTime.Now;
    
                while (GetServiceStatus(serviceHandle) != desiredStatus)
                {
                    if (DateTime.Now - startTime > timeout) { return false; }
    
                    Thread.Sleep(200);
                }
    
                return true;
            }
    
            #endregion
    
            #region 嵌套类
    
            /// <summary>
            /// Win32 API相关
            /// </summary>
            private static class Win32Class
            {
                #region 常量定义
    
                /// <summary>
                /// 打开服务管理器时请求的权限:全部
                /// </summary>
                public const int SC_MANAGER_ALL_ACCESS = 0xF003F;
    
                /// <summary>
                /// 服务类型:自有进程类服务
                /// </summary>
                public const int SERVICE_WIN32_OWN_PROCESS = 0x10;
    
                /// <summary>
                /// 打开服务时请求的权限:全部
                /// </summary>
                public const int SERVICE_ALL_ACCESS = 0xF01FF;
    
                /// <summary>
                /// 打开服务时请求的权限:停止
                /// </summary>
                public const int SERVICE_STOP = 0x20;
    
                /// <summary>
                /// 服务操作标记:停止
                /// </summary>
                public const int SERVICE_CONTROL_STOP = 0x1;
    
                /// <summary>
                /// 服务出错行为标记
                /// </summary>
                public const int SERVICE_ERROR_NORMAL = 0x1;
    
                #endregion
    
                #region API所需类和结构定义
    
                /// <summary>
                /// 服务状态结构体
                /// </summary>
                [StructLayout(LayoutKind.Sequential)]
                public struct SERVICE_STATUS
                {
                    public int serviceType;
                    public ServiceState currentState;
                    public int controlsAccepted;
                    public int win32ExitCode;
                    public int serviceSpecificExitCode;
                    public int checkPoint;
                    public int waitHint;
                }
    
                /// <summary>
                /// 服务描述结构体
                /// </summary>
                [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
                public struct SERVICE_DESCRIPTION
                {
                    public IntPtr description;
                }
    
                /// <summary>
                /// 服务状态结构体。遍历API会用到
                /// </summary>
                [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
                public class ENUM_SERVICE_STATUS
                {
                    public string serviceName;
                    public string displayName;
                    public int serviceType;
                    public int currentState;
                    public int controlsAccepted;
                    public int win32ExitCode;
                    public int serviceSpecificExitCode;
                    public int checkPoint;
                    public int waitHint;
                }
    
                #endregion
    
                #region API定义
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool ChangeServiceConfig2(IntPtr serviceHandle, uint infoLevel, ref SERVICE_DESCRIPTION serviceDesc);
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern IntPtr OpenSCManager(string machineName, string databaseName, int dwDesiredAccess);
    
                [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
                public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, int dwDesiredAccess);
                [DllImport("advapi32.dll")]
                public static extern int StartService(IntPtr SVHANDLE, int dwNumServiceArgs, string lpServiceArgVectors);
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, int dwDesiredAccess, int dwServiceType, ServiceStartType dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword);
    
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool CloseServiceHandle(IntPtr handle);
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool QueryServiceStatus(IntPtr hService, ref SERVICE_STATUS lpServiceStatus);
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool DeleteService(IntPtr serviceHandle);
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool ControlService(IntPtr hService, int dwControl, ref SERVICE_STATUS lpServiceStatus);
    
                [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
                public static extern bool EnumDependentServices(IntPtr serviceHandle, EnumServiceState serviceState, IntPtr bufferOfENUM_SERVICE_STATUS, int bufSize, ref int bytesNeeded, ref int numEnumerated);
    
                #endregion
            }
    
            #endregion
    
            /// <summary>
            /// 服务状态枚举。用于遍历从属服务API
            /// </summary>
            public enum EnumServiceState
            {
                Active = 1,
                InActive = 2,
                All = 3
            }
    
            /// <summary>
            /// 服务状态
            /// </summary>
            public enum ServiceState
            {
                Stopped = 1,
                StartPending = 2,
                StopPending = 3,
                Running = 4,
                ContinuePending = 5,
                PausePending = 6,
                Paused = 7
            }
        }
    }

    (2)测试例子:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace Yihe.Service
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                //安装服务
                ServiceHelper.Install("aaaaa", "aaaaa", Application.StartupPath + "\WindowService.exe", "无描述", ServiceStartType.Auto);
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                //卸载服务
                ServiceHelper.Uninstall("aaaaa");
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                //启动服务
                var isok = ServiceHelper.StartService("aaaaa", TimeSpan.FromSeconds(30));
                MessageBox.Show("是否成功:" + isok.ToString());
            }
    
            private void button4_Click(object sender, EventArgs e)
            {
                //停止服务
                var isok = ServiceHelper.StopService("aaaaa", TimeSpan.FromSeconds(30));
                MessageBox.Show("是否成功:" + isok.ToString());
            }
        }
    }
  • 相关阅读:
    如何保持mysql和redis中数据的一致性?
    秒杀系统设计&测试
    缓存穿透、缓存击穿、缓存雪崩区别和解决方案
    数据库关联子查询和非关联子查询
    mysql中 = 与in区别_浅析mysql中 exists 与 in 的区别,空判断
    mysql关键字执行顺序
    python中字典删除元素
    Python list根据下标插入/删除元素
    nginx504网关超时解决方法
    CDN加速
  • 原文地址:https://www.cnblogs.com/songxingzhu/p/4828513.html
Copyright © 2020-2023  润新知