ServiceHelper.cs
来源:互联网 发布:聊城行知中学 编辑:程序博客网 时间:2024/06/04 18:12
namespace EMAS.Helper{ using System; using System.ComponentModel; using System.Linq; using System.Management; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Text; using System.Threading; #region 异常定义 /// <summary> /// 服务不存在异常 /// </summary> public class ServiceNotExistException : ApplicationException { public ServiceNotExistException() : base("服务不存在!") { } public ServiceNotExistException(string message) : base(message) { } } #endregion #region 结构定义 /// <summary> /// 服务配置对象 /// </summary> public struct ServiceConfig { /// <summary> /// 服务名称:启动和关闭服务时使用的名称,可以与显示名称相同 /// </summary> public string ServiceName; /// <summary> /// 显示名称:服务列表中显示的名称 /// </summary> public string DisplayName; /// <summary> /// 描述:服务列表中描述该服务的功能 /// </summary> public string Description; /// <summary> /// 可执行文件的路径,可带参数 /// <para>若路径有空格,需给路径(不含参数)套上双引号,例如:@"""C:\新建 文件夹\test.exe"" /s"</para> /// <para>举例说明: 要启动的服务路径为 D:\srv.exe ,启动参数为 -s ,则填写路径@"D:\srv.exe -s"</para> /// </summary> public string ExeFilePath; /// <summary> /// 启动类型:设置服务启动的方式,自动或手动等 /// </summary> public ServiceStartMode StartType; /// <summary> /// 登录身份:为了避免不必要的权限问题,建议设置为LocalSystem /// </summary> public ServiceAccount Account; /// <summary> /// 登录名称 /// </summary> public string Username; /// <summary> /// 登录密码 /// </summary> public string Password; /// <summary> /// 依赖服务:当启动服务时同时启动依赖服务时需要设置此参数,否则设置为null /// </summary> public string[] ServicesDependedOn; } #endregion #region 枚举定义 /// <summary> /// 服务状态枚举。用于遍历从属服务API /// </summary> public enum EnumServiceState { Active = 1, InActive = 2, All = 3 } #endregion /// <summary> /// Windows 服务辅助类 /// </summary> public static class ServiceHelper { /// <summary> /// 超时等待时间(秒) /// </summary> public static int TimeOut = 30; /// <summary> /// 当前工作目录 /// </summary> public static string CurrentDirectory => Environment.CurrentDirectory; /// <summary> /// 当前调用可执行文件的路径 /// </summary> public static string InvokeFileName => System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; #region 日志方法 /// <summary> /// 日志记录 /// </summary> /// <param name="fileName">文件名称</param> /// <param name="contents">日志内容</param> public static void Log(string fileName, string contents) { System.IO.File.AppendAllText($"{Environment.CurrentDirectory}\\{fileName}.log", $"{contents}\r\n"); } #endregion #region 服务管理 /// <summary> /// 安装服务 /// </summary> /// <param name="config">服务配置对象,描述了服务相关的配置信息</param> public static void Install(ServiceConfig config) { var scm = OpenScManager(); var service = IntPtr.Zero; try { service = Win32Class.CreateService( scm, config.ServiceName, config.DisplayName, Win32Class.SERVICE_ALL_ACCESS, Win32Class.SERVICE_WIN32_OWN_PROCESS, config.StartType, Win32Class.SERVICE_ERROR_NORMAL, config.ExeFilePath, null, IntPtr.Zero, ProcessDependencies(config.ServicesDependedOn), GetServiceAccountName(config.Account), null ); if (service == IntPtr.Zero) { if (Marshal.GetLastWin32Error() == 0x431) //ERROR_SERVICE_EXISTS { throw new ApplicationException("服务已存在!"); } throw new ApplicationException("服务安装失败!"); } //设置服务描述 var sd = new Win32Class.SERVICE_DESCRIPTION(); try { sd.description = Marshal.StringToHGlobalUni(config.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) { var scmHandle = IntPtr.Zero; var 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 } } } /// <summary> /// 启动服务 /// </summary> /// <param name="serviceName">服务名称</param> /// <returns>成功:true,失败:false</returns> public static bool StartService(string serviceName) { if (!IsExists(serviceName)) return false; var sc = new ServiceController(serviceName); if (sc.Status != ServiceControllerStatus.Running && sc.Status != ServiceControllerStatus.StartPending) { sc.Start(); } sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, TimeOut)); return sc.Status == ServiceControllerStatus.Running; } /// <summary> /// 停止服务 /// </summary> /// <param name="serviceName">服务名称</param> /// <returns>成功:true,失败:false</returns> public static bool StopService(string serviceName) { bool isDone; var scmHandle = IntPtr.Zero; var service = IntPtr.Zero; try { service = OpenService(serviceName, out scmHandle); StopService(service); isDone = true; } catch { isDone = false; } finally { if (service != IntPtr.Zero) { Win32Class.CloseServiceHandle(service); Win32Class.CloseServiceHandle(scmHandle); } } return isDone; } /// <summary> /// 运行服务,用于安装服务后的服务调用 /// </summary> /// <param name="services"> 一组 ServiceBase 实例,指示要启动的服务</param> public static void RunService(params ServiceBase[] services) { ServiceBase.Run(services); } /// <summary> /// 检查服务是否运行 /// </summary> /// <param name="serviceName">服务名称</param> /// <returns>运行:true,停止:false</returns> public static bool IsRunning(string serviceName) { return ServiceController.GetServices().Where(t => t.ServiceName.ToLower().Equals(serviceName.ToLower())).Any(t => t.Status == ServiceControllerStatus.Running); } /// <summary> /// 检查服务是否存在 /// </summary> /// <param name="serviceName">服务名称</param> /// <returns>存在:true,不存在:false</returns> public static bool IsExists(string serviceName) { return ServiceController.GetServices().Any(t => t.ServiceName.ToLower().Equals(serviceName.ToLower())); } /// <summary> /// 设置服务允许与桌面交互 /// </summary> /// <param name="serviceName">服务名称</param> public static void DesktopInteract(string serviceName) { var co = new ConnectionOptions { Impersonation = ImpersonationLevel.Impersonate }; var ms = new ManagementScope(@"root/CIMV2", co); ms.Connect(); using (var wmiService = new ManagementObject($"Win32_Service.Name='{serviceName}'")) using (var inParam = wmiService.GetMethodParameters("Change")) { inParam["DesktopInteract"] = true; wmiService.InvokeMethod("Change", inParam, null); } } #endregion #region 接口方法 /// <summary> /// 打开服务管理器 /// </summary> public static IntPtr OpenScManager() { var 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="scManagerHandle">服务管理器句柄</param> public static IntPtr OpenService(string serviceName, out IntPtr scManagerHandle) { scManagerHandle = OpenScManager(); var serviceHandle = Win32Class.OpenService(scManagerHandle, serviceName, Win32Class.SERVICE_ALL_ACCESS); if (serviceHandle != IntPtr.Zero) return serviceHandle; var errCode = Marshal.GetLastWin32Error(); Win32Class.CloseServiceHandle(scManagerHandle); //关闭SCM if (errCode == 0x424) //ERROR_SERVICE_DOES_NOT_EXIST { throw new ServiceNotExistException(); } throw new Win32Exception(); } /// <summary> /// 停止服务 /// </summary> /// <param name="serviceHandle">服务管理器句柄</param> public static void StopService(IntPtr serviceHandle) { var currState = GetServiceStatus(serviceHandle); if (currState == ServiceControllerStatus.Stopped) { return; } if (currState != ServiceControllerStatus.StopPending) { //递归停止从属服务 var childSvs = EnumDependentServices(serviceHandle, EnumServiceState.Active); if (childSvs.Length != 0) { var scm = OpenScManager(); try { foreach (var childSv in childSvs) { StopService(Win32Class.OpenService(scm, childSv, Win32Class.SERVICE_STOP)); } } finally { Win32Class.CloseServiceHandle(scm); } } var status = new Win32Class.SERVICE_STATUS(); Win32Class.ControlService(serviceHandle, Win32Class.SERVICE_CONTROL_STOP, ref status); //发送停止指令 } if (!WaitForStatus(serviceHandle, ServiceControllerStatus.Stopped, new TimeSpan(0, 0, TimeOut))) { throw new ApplicationException("停止服务失败!"); } } /// <summary> /// 等候服务至目标状态 /// </summary> /// <param name="serviceHandle">服务管理器句柄</param> /// <param name="desiredStatus">服务状态描述</param> /// <param name="timeout">超时时间</param> public static bool WaitForStatus(IntPtr serviceHandle, ServiceControllerStatus desiredStatus, TimeSpan timeout) { var startTime = DateTime.Now; while (GetServiceStatus(serviceHandle) != desiredStatus) { if (DateTime.Now - startTime > timeout) { return false; } Thread.Sleep(200); } return true; } /// <summary> /// 遍历从属服务 /// </summary> /// <param name="serviceHandle">服务管理器句柄</param> /// <param name="state">要遍历的服务状态(活动、非活动、全部)</param> public static string[] EnumDependentServices(IntPtr serviceHandle, EnumServiceState state) { var bytesNeeded = 0; //存放从属服务的空间大小,由API返回 var 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(); } //在非托管区域创建指针 var structsStart = Marshal.AllocHGlobal(new IntPtr(bytesNeeded)); try { //往上述指针处塞存放从属服务的结构组,每个从属服务是一个结构 if (!Win32Class.EnumDependentServices(serviceHandle, state, structsStart, bytesNeeded, ref bytesNeeded, ref numEnumerated)) { throw new Win32Exception(); } var dependentServices = new string[numEnumerated]; var sizeOfStruct = Marshal.SizeOf(typeof(Win32Class.ENUM_SERVICE_STATUS)); //每个结构的大小 var structsStartAsInt64 = structsStart.ToInt64(); for (var i = 0; i < numEnumerated; i++) { var structure = new Win32Class.ENUM_SERVICE_STATUS(); var ptr = new IntPtr(structsStartAsInt64 + i * sizeOfStruct); //根据起始指针、结构次序和结构大小推算各结构起始指针 Marshal.PtrToStructure(ptr, structure); //根据指针拿到结构 dependentServices[i] = structure.serviceName; //从结构中拿到服务名 } return dependentServices; } finally { Marshal.FreeHGlobal(structsStart); } } /// <summary> /// 获取服务状态 /// </summary> /// <param name="serviceHandle">服务管理器句柄</param> public static ServiceControllerStatus GetServiceStatus(IntPtr serviceHandle) { var status = new Win32Class.SERVICE_STATUS(); if (!Win32Class.QueryServiceStatus(serviceHandle, ref status)) { throw new ApplicationException("获取服务状态出错!"); } return status.currentState; } #endregion #region 辅助方法 /// <summary> /// 转换帐户枚举为有效参数 /// </summary> /// <param name="account">账户类型枚举</param> static string GetServiceAccountName(ServiceAccount account) { return account == ServiceAccount.LocalService ? @"NT AUTHORITY\LocalService" : (account == ServiceAccount.NetworkService ? @"NT AUTHORITY\NetworkService" : null); } /// <summary> /// 处理依赖服务参数 /// </summary> /// <param name="dependencies">依赖服务参数</param> static string ProcessDependencies(params string[] dependencies) { if (dependencies == null || dependencies.Length == 0) { return null; } var sb = new StringBuilder(); foreach (var s in dependencies) { sb.Append(s).Append('\0'); } sb.Append('\0'); return sb.ToString(); } #endregion #region 嵌套类 /// <summary> /// Win32 API相关 /// </summary> 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 ServiceControllerStatus 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", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, int dwDesiredAccess, int dwServiceType, ServiceStartMode 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 }}
阅读全文
0 0
- ServiceHelper.cs
- ServiceHelper-Windows服务辅助类
- CS..........................
- cs
- cs
- cs
- Cs
- cs
- cs
- cs
- CS
- cs
- cs,
- cs
- cs
- cs
- cs
- cs
- 线程的一些入门知识
- 能实现把一个数组元素中的奇数放左边,偶数放右边
- 电路实验
- codeforces -891B Gluttony 排列,构造题
- Android开源库V
- ServiceHelper.cs
- jdbc的简单使用及注意事项
- 程序员偷偷深爱的 9 个不良编程习惯
- TiKV架构解析
- Tensorflow安装
- Java内部类详解
- POJ 2259 Team Queue
- EM算法过程推导
- MySQL之索引详解