使用C#开发自定义windows服务是一件十分简单的事。那么什么时候,我们需要自己开发windows服务呢,就是当我们需要计算机定期或者一 直执行我们开发的某些程序的时候。我经常看到许多人开发的windows服务安装卸载都是使用cmd命令来进行的,我觉得这样的话,部署起来比较麻烦,于是就考虑做了一个可视化的windows控制程序,方便,快捷。
这里我以一个WCF的监听服务为例,因为我是做一个局域聊天室,需要服务器端监听终端,所以我就开发了一个服务,以便控制此监听服务。然而,我们开发的windows服务,默认情况下是无法可视化的操作的,这里我就额外的开发一个工具来对此服务进行操作,效果图如下:
开发步骤
1、“新建项目”——“Window服务”
![](https://img-blog.csdn.net/20140713172607441?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvem91eXVqaWUxMTI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Program.cs代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceProcess; namespace MSMQChatService { class Program { static void Main() { #region 服务启动入口,正式用 ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MQChatService() }; ServiceBase.Run(ServicesToRun); #endregion } }
MQChatService.cs代码如下:
protected override void OnStart(string[] args) { //开启服务 这里就是你想要让服务做的操作 StartService(); }
3、切换到MQChatService的可视化界面
![](https://img-blog.csdn.net/20140713173036931?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvem91eXVqaWUxMTI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4、在可视化界面,单击鼠标右键,
![](https://img-blog.csdn.net/20140713173058210?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvem91eXVqaWUxMTI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
将会出现一个Installer为后缀的新界面,默认好像是Project Installer.cs,我这里将其重命名为ServiceInstaller.cs
分别对界面上这两个组件进行属性配置,具体的属性签名可以查看属性面板的最下面(右下角处)
好了,我们的windows服务已经开发好了,接下来就开发一个可视化的控制器,来控制服务的安装、卸载、启动和停止。
1、 新建一个windows程序,名称ServiceSetup,Form1重命名为FrmServiceSetup,
界面控件如下:
Program.cs代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace ServiceSetup { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { //获取欲启动进程名 string strProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; ////获取版本号 //CommonData.VersionNumber = Application.ProductVersion; //检查进程是否已经启动,已经启动则显示报错信息退出程序。 if (System.Diagnostics.Process.GetProcessesByName(strProcessName).Length > 1) { MessageBox.Show("程序已经运行。"); Thread.Sleep(1000); System.Environment.Exit(1); } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmServiceSetup()); } } } }
主界面代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace ServiceSetup { public partial class FrmServiceSetup : Form { string strServiceName = string.Empty; public FrmServiceSetup() { InitializeComponent(); strServiceName = string.IsNullOrEmpty(lblServiceName.Text) ? "MSMQChatService" : lblServiceName.Text; InitControlStatus(strServiceName, btnInstallOrUninstall, btnStartOrEnd, btnGetStatus, lblMsg, gbMain); } /// <summary> /// 初始化控件状态 /// </summary> /// <param name="serviceName">服务名称</param> /// <param name="btn1">安装按钮</param> /// <param name="btn2">启动按钮</param> /// <param name="btn3">获取状态按钮</param> /// <param name="txt">提示信息</param> /// <param name="gb">服务所在组合框</param> void InitControlStatus(string serviceName, Button btn1, Button btn2, Button btn3, Label txt, GroupBox gb) { try { btn1.Enabled = true; if (ServiceAPI.isServiceIsExisted(serviceName)) { btn3.Enabled = true; btn2.Enabled = true; btn1.Text = "卸载服务"; int status = ServiceAPI.GetServiceStatus(serviceName); if (status == 4) { btn2.Text = "停止服务"; } else { btn2.Text = "启动服务"; } GetServiceStatus(serviceName, txt); //获取服务版本 string temp = string.IsNullOrEmpty(ServiceAPI.GetServiceVersion(serviceName)) ? string.Empty : "(" + ServiceAPI.GetServiceVersion(serviceName) + ")"; gb.Text += temp; } else { btn1.Text = "安装服务"; btn2.Enabled = false; btn3.Enabled = false; txt.Text = "服务【" + serviceName + "】未安装!"; } } catch (Exception ex) { txt.Text = "error"; LogAPI.WriteLog(ex.Message); } } /// <summary> /// 安装或卸载服务 /// </summary> /// <param name="serviceName">服务名称</param> /// <param name="btnSet">安装、卸载</param> /// <param name="btnOn">启动、停止</param> /// <param name="txtMsg">提示信息</param> /// <param name="gb">组合框</param> void SetServerce(string serviceName, Button btnSet, Button btnOn, Button btnShow, Label txtMsg, GroupBox gb) { try { string location = System.Reflection.Assembly.GetExecutingAssembly().Location; string serviceFileName = location.Substring(0, location.LastIndexOf('\\')) + "\\" + serviceName + ".exe"; if (btnSet.Text == "安装服务") { ServiceAPI.InstallmyService(null, serviceFileName); if (ServiceAPI.isServiceIsExisted(serviceName)) { txtMsg.Text = "服务【" + serviceName + "】安装成功!"; btnOn.Enabled = btnShow.Enabled = true; string temp = string.IsNullOrEmpty(ServiceAPI.GetServiceVersion(serviceName)) ? string.Empty : "(" + ServiceAPI.GetServiceVersion(serviceName) + ")"; gb.Text += temp; btnSet.Text = "卸载服务"; btnOn.Text = "启动服务"; } else { txtMsg.Text = "服务【" + serviceName + "】安装失败,请检查日志!"; } } else { ServiceAPI.UnInstallmyService(serviceFileName); if (!ServiceAPI.isServiceIsExisted(serviceName)) { txtMsg.Text = "服务【" + serviceName + "】卸载成功!"; btnOn.Enabled = btnShow.Enabled = false; btnSet.Text = "安装服务"; //gb.Text =strServiceName; } else { txtMsg.Text = "服务【" + serviceName + "】卸载失败,请检查日志!"; } } } catch (Exception ex) { txtMsg.Text = "error"; LogAPI.WriteLog(ex.Message); } } //获取服务状态 void GetServiceStatus(string serviceName, Label txtStatus) { try { if (ServiceAPI.isServiceIsExisted(serviceName)) { string statusStr = ""; int status = ServiceAPI.GetServiceStatus(serviceName); switch (status) { case 1: statusStr = "服务未运行!"; break; case 2: statusStr = "服务正在启动!"; break; case 3: statusStr = "服务正在停止!"; break; case 4: statusStr = "服务正在运行!"; break; case 5: statusStr = "服务即将继续!"; break; case 6: statusStr = "服务即将暂停!"; break; case 7: statusStr = "服务已暂停!"; break; default: statusStr = "未知状态!"; break; } txtStatus.Text = statusStr; } else { txtStatus.Text = "服务【" + serviceName + "】未安装!"; } } catch (Exception ex) { txtStatus.Text = "error"; LogAPI.WriteLog(ex.Message); } } //启动服务 void OnService(string serviceName, Button btn, Label txt) { try { if (btn.Text == "启动服务") { ServiceAPI.RunService(serviceName); int status = ServiceAPI.GetServiceStatus(serviceName); if (status == 2 || status == 4 || status == 5) { txt.Text = "服务【" + serviceName + "】启动成功!"; btn.Text = "停止服务"; } else { txt.Text = "服务【" + serviceName + "】启动失败!"; } } else { ServiceAPI.StopService(serviceName); int status = ServiceAPI.GetServiceStatus(serviceName); if (status == 1 || status == 3 || status == 6 || status == 7) { txt.Text = "服务【" + serviceName + "】停止成功!"; btn.Text = "启动服务"; } else { txt.Text = "服务【" + serviceName + "】停止失败!"; } } } catch (Exception ex) { txt.Text = "error"; LogAPI.WriteLog(ex.Message); } } //安装or卸载服务 private void btnInstallOrUninstall_Click(object sender, EventArgs e) { btnInstallOrUninstall.Enabled = false; SetServerce(strServiceName, btnInstallOrUninstall, btnStartOrEnd, btnGetStatus, lblMsg, gbMain); btnInstallOrUninstall.Enabled = true; btnInstallOrUninstall.Focus(); } //启动or停止服务 private void btnStartOrEnd_Click(object sender, EventArgs e) { btnStartOrEnd.Enabled = false; OnService(strServiceName, btnStartOrEnd, lblMsg); btnStartOrEnd.Enabled = true; btnStartOrEnd.Focus(); } //获取服务状态 private void btnGetStatus_Click(object sender, EventArgs e) { btnGetStatus.Enabled = false; GetServiceStatus(strServiceName, lblMsg); btnGetStatus.Enabled = true; btnGetStatus.Focus(); } private void FrmServiceSetup_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) //最小化到系统托盘 { notifyIcon1.Visible = true; //显示托盘图标 this.ShowInTaskbar = false; this.Hide(); //隐藏窗口 } } private void FrmServiceSetup_FormClosing(object sender, FormClosingEventArgs e) { DialogResult result = MessageBox.Show("是缩小到托盘?", "确认", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); if (result== DialogResult.Yes) { // 取消关闭窗体 e.Cancel = true; // 将窗体变为最小化 this.WindowState = FormWindowState.Minimized; } else if (result == DialogResult.No) { System.Environment.Exit(0); } else { e.Cancel = true; } } private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left&&this.WindowState == FormWindowState.Minimized) { this.Show(); this.WindowState = FormWindowState.Normal; this.ShowInTaskbar = true; //显示在系统任务栏 //notifyIcon1.Visible = false; //托盘图标不可见 this.Activate(); } } private void 打开主界面ToolStripMenuItem_Click(object sender, EventArgs e) { this.Show(); this.WindowState = FormWindowState.Normal; this.ShowInTaskbar = true; //显示在系统任务栏 notifyIcon1.Visible = false; //托盘图标不可见 this.Activate(); } private void 退出ToolStripMenuItem_Click(object sender, EventArgs e) { System.Environment.Exit(0); ExitProcess(); } //结束进程 private void ExitProcess() { System.Environment.Exit(0); Process[] ps = Process.GetProcesses(); foreach (Process item in ps) { if (item.ProcessName == "ServiceSetup") { item.Kill(); } } } } }
新建一个类,专门用于日志操作LogAPI.cs,这里的日志路径和名称建议从配置文件中读取
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ServiceSetup { public class LogAPI { private static string myPath = ""; private static string myName = ""; /// <summary> /// 初始化日志文件 /// </summary> /// <param name="logPath"></param> /// <param name="logName"></param> public static void InitLogAPI(string logPath, string logName) { myPath = logPath; myName = logName; } /// <summary> /// 写入日志 /// </summary> /// <param name="ex">日志信息</param> public static void WriteLog(string ex) { if (myPath == "" || myName == "") return; string Year = DateTime.Now.Year.ToString(); string Month = DateTime.Now.Month.ToString().PadLeft(2, '0'); string Day = DateTime.Now.Day.ToString().PadLeft(2, '0'); //年月日文件夹是否存在,不存在则建立 if (!Directory.Exists(myPath + "\\LogFiles\\" + Year + "_" + Month + "\\" + Year + "_" + Month + "_" + Day)) { Directory.CreateDirectory(myPath + "\\LogFiles\\" + Year + "_" + Month + "\\" + Year + "_" + Month + "_" + Day); } //写入日志UNDO,Exception has not been handle string LogFile = myPath + "\\LogFiles\\" + Year + "_" + Month + "\\" + Year + "_" + Month + "_" + Day + "\\" + myName; if (!File.Exists(LogFile)) { System.IO.StreamWriter myFile; myFile = System.IO.File.AppendText(LogFile); myFile.Close(); } while (true) { try { StreamWriter sr = File.AppendText(LogFile); sr.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " " + ex); sr.Close(); break; } catch (Exception e) { System.Threading.Thread.Sleep(50); continue; } } } } }
Windows服务的操作类ServiceAPI.cs
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System; using System.Collections; using System.Collections.Generic; using System.Configuration.Install; using System.IO; using System.Linq; using System.Reflection; using System.ServiceProcess; using System.Text; using System.Threading.Tasks; using Microsoft.Win32; namespace ServiceSetup { public class ServiceAPI { /// <summary> /// 检查服务存在的存在性 /// </summary> /// <param name=" NameService ">服务名</param> /// <returns>存在返回 true,否则返回 false;</returns> public static bool isServiceIsExisted(string NameService) { ServiceController[] services = ServiceController.GetServices(); foreach (ServiceController s in services) { if (s.ServiceName.ToLower() == NameService.ToLower()) { return true; } } return false; } /// <summary> /// 安装Windows服务 /// </summary> /// <param name="stateSaver">集合</param> /// <param name="filepath">程序文件路径</param> public static void InstallmyService(IDictionary stateSaver, string filepath) { AssemblyInstaller AssemblyInstaller1 = new AssemblyInstaller(); AssemblyInstaller1.UseNewContext = true; AssemblyInstaller1.Path = filepath; AssemblyInstaller1.Install(stateSaver); AssemblyInstaller1.Commit(stateSaver); AssemblyInstaller1.Dispose(); } /// <summary> /// 卸载Windows服务 /// </summary> /// <param name="filepath">程序文件路径</param> public static void UnInstallmyService(string filepath) { AssemblyInstaller AssemblyInstaller1 = new AssemblyInstaller(); AssemblyInstaller1.UseNewContext = true; AssemblyInstaller1.Path = filepath; AssemblyInstaller1.Uninstall(null); AssemblyInstaller1.Dispose(); } /// <summary> /// 启动服务 /// </summary> /// <param name=" NameService ">服务名</param> /// <returns>存在返回 true,否则返回 false;</returns> public static bool RunService(string NameService) { bool bo = true; try { ServiceController sc = new ServiceController(NameService); if (sc.Status.Equals(ServiceControllerStatus.Stopped) || sc.Status.Equals(ServiceControllerStatus.StopPending)) { sc.Start(); } } catch (Exception ex) { bo = false; LogAPI.WriteLog(ex.Message); } return bo; } /// <summary> /// 停止服务 /// </summary> /// <param name=" NameService ">服务名</param> /// <returns>存在返回 true,否则返回 false;</returns> public static bool StopService(string NameService) { bool bo = true; try { ServiceController sc = new ServiceController(NameService); if (!sc.Status.Equals(ServiceControllerStatus.Stopped)) { sc.Stop(); } } catch (Exception ex) { bo = false; LogAPI.WriteLog(ex.Message); } return bo; } /// <summary> /// 获取服务状态 /// </summary> /// <param name=" NameService ">服务名</param> /// <returns>返回服务状态</returns> public static int GetServiceStatus(string NameService) { int ret = 0; try { ServiceController sc = new ServiceController(NameService); ret = Convert.ToInt16(sc.Status); } catch (Exception ex) { ret = 0; LogAPI.WriteLog(ex.Message); } return ret; } /// <summary> /// 获取服务安装路径 /// </summary> /// <param name="ServiceName"></param> /// <returns></returns> public static string GetWindowsServiceInstallPath(string ServiceName) { string path = ""; try { string key = @"SYSTEM\CurrentControlSet\Services\" + ServiceName; path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString(); path = path.Replace("\"", string.Empty);//替换掉双引号 FileInfo fi = new FileInfo(path); path = fi.Directory.ToString(); } catch (Exception ex) { path = ""; LogAPI.WriteLog(ex.Message); } return path; } /// <summary> /// 获取指定服务的版本号 /// </summary> /// <param name="serviceName">服务名称</param> /// <returns></returns> public static string GetServiceVersion(string serviceName) { if (string.IsNullOrEmpty(serviceName)) { return string.Empty; } try { string path = GetWindowsServiceInstallPath(serviceName) + "\\" + serviceName + ".exe"; Assembly assembly = Assembly.LoadFile(path); AssemblyName assemblyName = assembly.GetName(); Version version = assemblyName.Version; return version.ToString(); } catch (Exception ex) { LogAPI.WriteLog(ex.Message); return string.Empty; } } } }
注意:记得将服务程序的dll拷贝到可视化安装程序的bin目录下面。包括配置文件。如果运行报错,尝试以管理员身份运行安装程序。