C# 控制创建的windows服务(安装、卸载、启动、停止)
功能描述:实时从数据库获取数据做相关处理
步骤:
1 创建服务;
2 创建控制服务应用程序;
一:创建服务
1 新建-Windows Service,出现如图
2 右键-添加安装程序
出现
分别设置相关服务信息略
3 编写服务相关代码,Service1.cs类,此处实现每隔10分钟从数据库读取数据进行逻辑处理
public partial class Service1 : ServiceBase { System.Timers.Timer t = null; public Service1() { t = new System.Timers.Timer(10*60*1000); t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed); InitializeComponent(); } void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //获取学员 //模拟数据 for(int i=0;i<1000;i++) { /// Thread.Sleep(5000); } } protected override void OnStart(string[] args) { t.Start(); } protected override void OnStop() { t.Stop(); t.Dispose(); } }
4 安装服务
4-1 此处通过vs 工具命令行InstallUtil 服务路径/xxx.exe、InstallUtil /u 服务路径/xxx.exe分别进行安装、卸载
问题:太过繁琐,安装客户端麻烦(可以通过新建安装包进行安装卸载服务,但如果更改服务代码需要安装卸麻烦)
4-2 通过打包安装程序进行安装卸载服务:
问题:有时候某些原因卸载不彻底,如果改动服务代码太繁琐
二 控制服务程序
1 解决方案如图
分别对应:SendMsgService:服务、ServiceControl服务控制应用程序、ServiceManager服务帮助类
一处模拟实时获取数据,此处通过配置文件,可以进行包括时间间隔、数据库配置等更改
2 详细
ServiceManager服务帮助类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceProcess; using System.Runtime.InteropServices; using System.Collections.Specialized; using System.IO; namespace ServiceManager { public class IniHelper { public string FileName; //INI文件名 //声明读写INI文件的API函数 [DllImport("kernel32")] private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath); [DllImport("kernel32")] private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath); //类的构造函数,传递INI文件名 public IniHelper(string iniFileName) { // 判断文件是否存在 FileInfo fileInfo = new FileInfo(iniFileName); if ((!fileInfo.Exists)) { fileInfo.Create(); } //必须是完全路径,不能是相对路径 FileName = fileInfo.FullName; } //写INI文件 public void WriteString(string Section, string Ident, string Value) { if (!WritePrivateProfileString(Section, Ident, Value, FileName)) { throw (new ApplicationException("写Ini文件出错")); } } //读取INI文件指定 public string GetString(string Section, string Ident, string Default) { Byte[] Buffer = new Byte[65535]; int bufLen = GetPrivateProfileString(Section, Ident, Default, Buffer, Buffer.GetUpperBound(0), FileName); //必须设定0(系统默认的代码页)的编码方式,否则无法支持中文 string s = Encoding.GetEncoding(0).GetString(Buffer); s = s.Substring(0, bufLen); return s.Trim(); } //读整数 public int GetInteger(string Section, string Ident, int Default) { string intStr = GetString(Section, Ident, Convert.ToString(Default)); try { return Convert.ToInt32(intStr); } catch { return Default; } } //写整数 public void WriteInteger(string Section, string Ident, int Value) { WriteString(Section, Ident, Value.ToString()); } //读布尔 public bool GetBool(string Section, string Ident, bool Default) { try { return Convert.ToBoolean(GetString(Section, Ident, Convert.ToString(Default))); } catch { return Default; } } //写Bool public void WriteBool(string Section, string Ident, bool Value) { WriteString(Section, Ident, Convert.ToString(Value)); } //从Ini文件中,将指定的Section名称中的所有Ident添加到列表中 public void GetSection(string Section, StringCollection Idents) { Byte[] Buffer = new Byte[16384]; int bufLen = GetPrivateProfileString(Section, null, null, Buffer, Buffer.GetUpperBound(0), FileName); //对Section进行解析 GetStringsFromBuffer(Buffer, bufLen, Idents); } private void GetStringsFromBuffer(Byte[] Buffer, int bufLen, StringCollection Strings) { Strings.Clear(); if (bufLen != 0) { int start = 0; for (int i = 0; i < bufLen; i++) { if ((Buffer[i] == 0) && ((i - start) > 0)) { String s = Encoding.GetEncoding(0).GetString(Buffer, start, i - start); Strings.Add(s); start = i + 1; } } } } //从Ini文件中,读取所有的Sections的名称 public void GetSections(StringCollection SectionList) { //Note:必须得用Bytes来实现,StringBuilder只能取到第一个Section byte[] Buffer = new byte[65535]; int bufLen = 0; bufLen = GetPrivateProfileString(null, null, null, Buffer, Buffer.GetUpperBound(0), FileName); GetStringsFromBuffer(Buffer, bufLen, SectionList); } //读取指定的Section的所有Value到列表中 public void GetSectionValues(string Section, NameValueCollection Values) { StringCollection KeyList = new StringCollection(); GetSection(Section, KeyList); Values.Clear(); foreach (string key in KeyList) { Values.Add(key, GetString(Section, key, "")); } } //清除某个Section public void EraseSection(string Section) { if (!WritePrivateProfileString(Section, null, null, FileName)) { throw (new ApplicationException("无法清除Ini文件中的Section")); } } //删除某个Section下的键 public void DeleteKey(string Section, string Ident) { WritePrivateProfileString(Section, Ident, null, FileName); } //检查某个Section下的某个键值是否存在 public bool ValueExists(string Section, string Ident) { StringCollection Idents = new StringCollection(); GetSection(Section, Idents); return Idents.IndexOf(Ident) > -1; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.ServiceProcess; namespace ServiceManager { public class ServiceHelper { #region DLLImport [DllImport("advapi32.dll")] public static extern IntPtr OpenSCManager(string lpMachineName, string lpSCDB, int scParameter); [DllImport("Advapi32.dll")] public static extern IntPtr CreateService(IntPtr SC_HANDLE, string lpSvcName, string lpDisplayName, int dwDesiredAccess, int dwServiceType, int dwStartType, int dwErrorControl, string lpPathName, string lpLoadOrderGroup, int lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword); [DllImport("advapi32.dll")] public static extern void CloseServiceHandle(IntPtr SCHANDLE); [DllImport("advapi32.dll")] public static extern int StartService(IntPtr SVHANDLE, int dwNumServiceArgs, string lpServiceArgVectors); [DllImport("advapi32.dll", SetLastError = true)] public static extern IntPtr OpenService(IntPtr SCHANDLE, string lpSvcName, int dwNumServiceArgs); [DllImport("advapi32.dll")] public static extern int DeleteService(IntPtr SVHANDLE); [DllImport("kernel32.dll")] public static extern int GetLastError(); #endregion DLLImport //服务名称 private string sname; //服务程序绝对路径 private string spath; /// <summary> /// 初始化 /// </summary> /// <param name="serviceName">服务名称</param> /// <param name="serviceFilePath">服务程序绝对路径</param> public ServiceHelper(string serviceName, string serviceFilePath) { this.sname = serviceName; this.spath = serviceFilePath; } /// <summary> /// 服务是否已安装 /// </summary> /// <returns></returns> public bool IsInstalled() { return ServiceController.GetServices().Any(x => string.Compare(x.ServiceName, sname, true) == 0); } /// <summary> /// 服务是否正在运行 /// </summary> /// <returns></returns> public bool IsRunning() { if (IsInstalled()) { var control = new ServiceController(sname); control.Refresh(); return control.Status == ServiceControllerStatus.Running; } return false; } /// <summary> /// 安装服务 /// </summary> /// <returns></returns> public void Install() { if (IsInstalled()) { return; } #region Constants declaration. int SC_MANAGER_CREATE_SERVICE = 0x0002; int SERVICE_WIN32_OWN_PROCESS = 0x00000010; int SERVICE_ERROR_NORMAL = 0x00000001; int STANDARD_RIGHTS_REQUIRED = 0xF0000; int SERVICE_QUERY_CONFIG = 0x0001; int SERVICE_CHANGE_CONFIG = 0x0002; int SERVICE_QUERY_STATUS = 0x0004; int SERVICE_ENUMERATE_DEPENDENTS = 0x0008; int SERVICE_START = 0x0010; int SERVICE_STOP = 0x0020; int SERVICE_PAUSE_CONTINUE = 0x0040; int SERVICE_INTERROGATE = 0x0080; int SERVICE_USER_DEFINED_CONTROL = 0x0100; int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL); int SERVICE_AUTO_START = 0x00000002; #endregion Constants declaration. IntPtr sc_handle = OpenSCManager(null, null, SC_MANAGER_CREATE_SERVICE); if (sc_handle.ToInt32() != 0) { IntPtr svc_handle = CreateService(sc_handle, sname, sname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, spath, null, 0, null, null, null); CloseServiceHandle(svc_handle); } CloseServiceHandle(sc_handle); } /// <summary> /// 卸载服务 /// </summary> public void UnInstall() { if (IsInstalled()) { if (IsRunning()) { this.Stop(); } int GENERIC_WRITE = 0x40000000; IntPtr sc_hndl = OpenSCManager(null, null, GENERIC_WRITE); if (sc_hndl.ToInt32() != 0) { int DELETE = 0x10000; IntPtr svc_hndl = OpenService(sc_hndl, sname, DELETE); if (svc_hndl.ToInt32() != 0) { DeleteService(svc_hndl); } CloseServiceHandle(svc_hndl); } CloseServiceHandle(sc_hndl); } } /// <summary> /// 启动服务 /// </summary> public void Start() { if (IsRunning()) { return; } try { var control = new ServiceController(sname); control.Start(); control.WaitForStatus(ServiceControllerStatus.Running); control.Refresh(); } catch (Exception ex) { throw; } } /// <summary> /// 停止服务 /// </summary> public void Stop() { if (IsRunning()) { var control = new ServiceController(sname); control.Stop(); control.WaitForStatus(ServiceControllerStatus.Stopped); control.Refresh(); } } } }
ps:需引用dll
SendMsgService服务
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace SendMsgService { public class Logger { private string logRoot = "c:\\"; public string LogRoot { get { return logRoot; } set { logRoot = value; } } private object syslock = new object(); public void WriteLog(string msg) { lock (syslock) { string filename = Path.Combine(logRoot, DateTime.Today.ToString("yyyy-MM-dd") + ".log"); StreamWriter sw = File.AppendText(filename); sw.WriteLine(string.Format("{0}\t{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msg)); sw.Close(); } } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using System.IO; using System.Configuration; using System.Data.OracleClient; using System.Threading; using ServiceManager; namespace SendMsgService { public partial class Service1 : ServiceBase { private string Account = ""; private string Pwd = ""; //数据库连接字符串 private string ConStr = ""; private string iniFileName = "config.ini"; private string logRoot = "c:\\"; private Logger logger; System.Timers.Timer t = null; public Service1() { //获取根目录下ini配置文件 iniFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, iniFileName); IniHelper ini = new IniHelper(iniFileName); Account = ini.GetString("SetInfo", "Account", ""); Pwd = ini.GetString("SetInfo", "Pwd", ""); ConStr = ini.GetString("SetInfo", "ConStr", ""); logRoot = ini.GetString("Logger", "dir", "log"); if (logRoot.Length > 2 && logRoot[1] != ':') { logRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logRoot); } if (!Directory.Exists(logRoot)) { Directory.CreateDirectory(logRoot); } logger = new Logger(); logger.LogRoot = logRoot; t = new System.Timers.Timer(Convert.ToInt32(ini.GetString("SetInfo", "TimeTick", ""))); t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed); InitializeComponent(); } void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //逻辑部分 /// //日志 logger.WriteLog(""); logger.WriteLog("-------------------"); Thread.Sleep(5000); } protected override void OnStart(string[] args) { t.Start(); } protected override void OnStop() { t.Stop(); t.Dispose(); } } }
ServiceControl服务控制
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; using ServiceManager; using System.IO; using System.Diagnostics; namespace ServiceControl { public partial class MainForm : Form { private ServiceHelper service; private string iniFileName = "config.ini"; private string logPath; public MainForm() { InitializeComponent(); //初始化 IniHelper ini = new IniHelper(iniFileName); //获取服务名、服务对应可执行文件即此处SendMsgService string sname = ini.GetString("Service_Info", "ServiceName", "Service"); string spath = ini.GetString("Service_Info", "ServiceFilePath", "SendMsgService.exe"); logPath = ini.GetString("Logger", "DirRoot", "log"); FileInfo sfi = new FileInfo(spath); if (sfi.Exists) { service = new ServiceHelper(sname, sfi.FullName); this.UpdateButtonStatus(); } else { MessageBox.Show(string.Format("服务程序不存在,请检查配置文件!\n{0}", sfi.FullName), "错误"); this.Enabled = false; } } private void UpdateButtonStatus() { if (service.IsInstalled()) { btnInstall.Text = "卸载"; btnStart.Enabled = true; if (service.IsRunning()) { btnStart.Text = "停止"; } else { btnStart.Text = "启动"; } } else { btnStart.Enabled = false; btnInstall.Text = "安装"; } btnInstall.Enabled = true; btnLog.Enabled = true; } private void btnInstall_Click_1(object sender, EventArgs e) { btnInstall.Enabled = false; if (service.IsInstalled()) { service.UnInstall(); } else { service.Install(); } this.UpdateButtonStatus(); } private void btnStart_Click_1(object sender, EventArgs e) { btnStart.Enabled = false; if (service.IsRunning()) { service.Stop(); } else { service.Start(); } this.UpdateButtonStatus(); } private void btnLog_Click_1(object sender, EventArgs e) { this.Enabled = false; Process.Start("explorer.exe", logPath); this.Enabled = true; } } }
SendMsgService:服务、ServiceControl服务控制应用程序、ServiceManager服务帮助类 编译生成文件需设置在同一文件夹下
config.ini配置文件
此处SendMsgService.exe即为服务程序集名称
编译 生成,测试