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 = "";
serviceInstaller.ServiceName = "";
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 > )
{
if (args[] == "-i")
{
InstallService();
}
else if (args[] == "-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, , 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 AUTHORITY\LocalService";
}
if (account == ServiceAccount.NetworkService)
{
return @"NT AUTHORITY\NetworkService";
}
return null;
} /// <summary>
/// 处理依赖服务参数
/// </summary>
public static string ProcessDependencies(string[] dependencies)
{
if (dependencies == null || dependencies.Length == )
{
return null;
} StringBuilder sb = new StringBuilder();
foreach (string s in dependencies)
{
sb.Append(s).Append('\0');
}
sb.Append('\0'); 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 != )
{
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(, , )))
{
throw new ApplicationException("停止服务失败!");
}
} /// <summary>
/// 遍历从属服务
/// </summary>
/// <param name="serviceHandle"></param>
/// <param name="state">选择性遍历(活动、非活动、全部)</param>
public static string[] EnumDependentServices(IntPtr serviceHandle, EnumServiceState state)
{
int bytesNeeded = ; //存放从属服务的空间大小,由API返回
int numEnumerated = ; //从属服务数,由API返回 //先尝试以空结构获取,如获取成功说明从属服务为空,否则拿到上述俩值
if (Win32Class.EnumDependentServices(serviceHandle, state, IntPtr.Zero, , ref bytesNeeded, ref numEnumerated))
{
return new string[];
}
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 = ; 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();
} 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 = ,
InActive = ,
All =
} /// <summary>
/// 服务状态
/// </summary>
public enum ServiceState
{
Stopped = ,
StartPending = ,
StopPending = ,
Running = ,
ContinuePending = ,
PausePending = ,
Paused =
}
}
}

(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());
MessageBox.Show("是否成功:" + isok.ToString());
} private void button4_Click(object sender, EventArgs e)
{
//停止服务
var isok = ServiceHelper.StopService("aaaaa", TimeSpan.FromSeconds());
MessageBox.Show("是否成功:" + isok.ToString());
}
}
}

Windows服务安装与控制的更多相关文章

  1. Windows服务安装与卸载

    Windows服务安装与卸载,使用到了InstallUtil.exe 安装: c: cd "C:\Windows\Microsoft.NET\Framework\v4.0.30319&quo ...

  2. Windows服务安装异常:System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志。不可 访问的日志: Security

    Windows服务安装异常:System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志.不可 访问的日志: Security 2种方法处理: 一.右键 ...

  3. C#编写的windows服务安装后启动提示“服务启动后又停止了”

    使用C#编写的windows服务安装到服务器上行后进行启动时,总是提示“服务启动后又停止了”. 检查了服务逻辑是没问题,安装在开发本地也是正常,网上查了资料说是可能是服务没有注册,我检查了服务是正常注 ...

  4. C# windows服务安装及卸载

    --C# windows服务安装及卸载   保存BAT文件  执行即可 @SET FrameworkDir=%WINDIR%\Microsoft.NET\Framework@SET Framework ...

  5. EasyDSS RTMP流媒体解决方案之Windows服务安装方案

    Windows服务安装 EasyDSS_Solution流媒体解决方案,可以通过start一键启动.在实际应用中,我们希望可以设置成系统服务,那么下面我将会介绍,如何在windows中将流媒体解决方案 ...

  6. PCB MongoDb安装与Windows服务安装

    工程MI流程指示做成Web网页形式,采用MVC框架制作,数据传输用Web API方式, 最终此网页会挂到公司各系统中访问,为了提高访问并发量,并将工程数据统一结构化管理, 采用No SQL Mongo ...

  7. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之Windows服务安装

    背景说明 EasyDSS流媒体解决方案是由安徽旭帆信息科技有限公司自主研发的一套集流媒体点播.转码.管理.直播.录像.检索.时移回看于一体的一套完整的商用流媒体解决方案.EasyDSS软件以压缩包的形 ...

  8. Windows 服务安装与卸载 (通过 Sc.exe)

    1. 安装 新建文本文件,重命名为 ServiceInstall.bat,将 ServiceInstall.bat 的内容替换为: sc create "Verity Platform De ...

  9. Windows 服务安装与卸载 (通过 installutil.exe)

    1. 安装 安装 .NET Framework ; 新建文本文件,重命名为 ServiceInstall.bat,将 ServiceInstall.bat 的内容替换为: C:\\Windows\\M ...

随机推荐

  1. Instrument 实用详解

    苹果:Instruments User Guide iPhone Memory Debugging with NSZombie and Instruments 苹果:Mac OS X Debuggin ...

  2. C#编程(六十九)----------DLR简介

    DLR 一.近年来,在TIOBE公司每个月发布的编程语言排行榜中,C#总是能挤进前十名,而在最近十年来,C#总体上呈现上升的趋势.C#能取得这样的成绩,有很多因素,其中它在语言特性上的锐意进取让人印象 ...

  3. android studio每次启动都要在fetching Android sdk compoment information停好久 怎么解决?

    网上有人给出了方案:1)进入刚安装的Android Studio目录下的bin目录.找到idea.properties文件,用文本编辑器打开.2)在idea.properties文件末尾添加一行: d ...

  4. Oracle JDBC连接服务名、SID和tnsnames.ora配置的多种方式

    昨天,领导安排去新服务器上部署项目,给了我数据库地址,服务名称,端口,用户名和密码.结果数据库一直连接不上,日志中的错误提示是监听未找到SID,我才明白原来我jdbc.properties中需要的是S ...

  5. springboot redis多数据源设置

    遇到这样一个需求:运营人员在发布内容的时候可以选择性的发布到测试库.开发库和线上库. 项目使用的是spring boot集成redis,实现如下: 1. 引入依赖 <dependency> ...

  6. SpringBoot扫描包提示找不到mapper的问题

    SpringBoot扫描包问题 报错信息:Consider defining a bean of type in your configuration 方法一: 使用注解 @ComponentScan ...

  7. Xcode打包踩过的那些坑

    一.file was built for archive which is not the architecture being linked (armv7s) 项目是基于cocos2d-x绑定lua ...

  8. 《Linux系统编程(第2版)》

    <Linux系统编程(第2版)> 基本信息 作者: (美)Robert Love 译者: 祝洪凯 李妹芳 付途 出版社:人民邮电出版社 ISBN:9787115346353 上架时间:20 ...

  9. Html-文档类型(DTD)和DOCTYPE

    在正式介绍文档类型(DTD)和DOCTYPE之前,我们需要先了解HTML和XHTML的之间的区别,现在Html5已经慢慢的成为主流,之前的数十年一直都是Html4.01的天下,Html4.01于199 ...

  10. java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值

    问题来源:我在执行sql生成json并存入数据库是报的错. 原因:存json的字段我定义其类型为varchar2. 分析:这个异常是指,用户向数据库执行插入数据操作时,某条数据的某个字段值过长,如果是 ...