使用C#開發自定義windows服務是一件十分簡單的事。那麼何時,咱們須要本身開發windows服務呢,就是當咱們須要計算機按期或者一直執行咱們開發的某些程序的時候。這裏我以一個WCF的監聽服務爲例,由於我是作一個局域聊天室,須要服務器端監聽終端,因此我就開發了一個服務,以便控制此監聽服務。然而,咱們開發的windows服務,默認狀況下是沒法可視化的操做的,這裏我就額外的開發一個工具來對此服務進行操做,效果圖以下:
windows
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(); }
將會出現一個Installer爲後綴的新界面,默認好像是Project Installer.cs,我這裏將其重命名爲ServiceInstaller.cs
ide
分別對界面上這兩個組件進行屬性配置,具體的屬性簽名能夠查看屬性面板的最下面(右下角處)工具
好了,咱們的windows服務已經開發好了,接下來就開發一個可視化的控制器,來控制服務的安裝、卸載、啓動和中止。this
一、 新建一個windows程序,名稱ServiceSetup,Form1重命名爲FrmServiceSetup,
spa
界面控件以下:.net
Program.cs代碼以下:日誌
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()); } } } }
主界面代碼:code
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.csorm
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
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目錄下面。