Windows 服务应用程序介绍
Microsoft Windows 服务(过去称为 NT 服务)允许用户创建可在其自身的 Windows 会话中长时间运行的可执行应用程序。 这些服务可在计算机启动时自动启动,可以暂停和重启,并且不显示任何用户界面。 这些功能使服务非常适合在服务器上使用,或者需要长时间运行的功能(不会影响在同一台计算机上工作的其他用户)的情况。还可以在与登录用户或默认计算机帐户不同的特定用户帐户的安全性上下文中运行服务。
可以通过创建作为服务安装的应用程序来轻松创建服务。 例如,假设你想监视性能计数器数据并对阈值作出响应。 可以编写一个侦听性能计数器数据的 Windows 服务应用程序,部署该应用程序并开始收集和分析数据。
可以将服务创建为 Microsoft Visual Studio 项目,并在其中定义代码,以控制可以将哪些命令发送到服务以及在收到这些命令时应采取的操作。 可以发送到服务的命令包括启动、暂停、恢复和停止服务,还可以执行自定义命令。
在创建和生成应用程序之后,可以通过运行命令行实用程序 InstallUtil.exe 并将该路径传递给服务的可执行文件来安装它。 然后,可以使用服务控制管理器来启动、停止、暂停、恢复和配置服务。 还可以在“服务器资源管理器”的“服务”节点中或使用 ServiceController 类完成许多相同的任务。
创建一个简单的 windows 服务程序 Dome ,VS2019 ,win10 环境。
代码:
Service1
using System;
using System.Configuration;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace WindowsServiceTest
{
public partial class Service1 : ServiceBase
{
private string path = string.Empty;
private string debug = string.Empty;
/// <summary>
/// 定时器
/// </summary>
private static System.Timers.Timer aTimer;
private const string strat = "服务启动";
private const string stop = "服务停止";
private const string run = "服务运行中";
private const string pause = "服务暂停中";
private const string conti = "服务已恢复";
private const string shutdown = "服务即将停止运行";
/// <summary>
/// 读写锁,当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入
/// </summary>
static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
public Service1()
{
InitializeComponent();
path = ConfigurationManager.AppSettings["PATH"];
debug = ConfigurationManager.AppSettings["Debug"];
}
/// <summary>
/// 定时任务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
work(run);
}
private void work(string str)
{
try
{
// //设置读写锁为写入模式独占资源,其他写入请求需要等待本次写入结束之后才能继续写.
LogWriteLock.EnterWriteLock();
WriteTxt(path, str);
}
catch(Exception ex)
{
WriteTxt(debug, DateTime.Now.ToString()+" : "+ ex.Message);
}
finally
{
退出写入模式,释放资源占用 一次请求对应一次释放. 若释放次数大于请求次数将会触发异常[写入锁定未经保持即被释放] 若请求处理完成后未释放将会触发异常[此模式不下允许以递归方式获取写入锁定]
LogWriteLock.ExitWriteLock();
}
}
/// <summary>
/// 向文件写入文本
/// </summary>
/// <param name="path">路径</param>
/// <param name="txt">文本</param>
private void WriteTxt(string path,string txt)
{
if (!File.Exists(path))
{
File.Create(path).Close();
}
using (FileStream stream = new FileStream(path, FileMode.Append))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.WriteLine($"{DateTime.Now},{txt}");
}
}
#region 服务启停
/// <summary>
/// 服务启动执行代码
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
aTimer = new System.Timers.Timer
{
Interval = 5000
};
aTimer.Elapsed += ATimer_Elapsed;
aTimer.Enabled = true;
aTimer.Start();
}
/// <summary>
/// 服务结束执行代码
/// </summary>
protected override void OnStop()
{
work(stop);
aTimer.Enabled = false;
}
/// <summary>
/// 服务暂停执行代码
/// </summary>
protected override void OnPause()
{
work(pause);
aTimer.Enabled = false;
aTimer.Stop();
}
/// <summary>
/// 服务恢复执行代码
/// </summary>
protected override void OnContinue()
{
work(conti);
aTimer.Enabled = true;
aTimer.Start();
}
/// <summary>
/// 服务即将关闭执行代码
/// </summary>
protected override void OnShutdown()
{
work(shutdown);
}
#endregion
#region 调试代码
/// <summary>
/// 服务启动执行代码
/// </summary>
/// <param name="args"></param>
internal void DebugOnStart()
{
aTimer = new System.Timers.Timer
{
Interval = 5000
};
aTimer.Elapsed += ATimer_Elapsed;
aTimer.Enabled = true;
aTimer.Start();
}
/// <summary>
/// 服务结束执行代码
/// </summary>
internal void DebugOnStop()
{
work(stop);
aTimer.Enabled = false;
}
/// <summary>
/// 服务暂停执行代码
/// </summary>
internal void DebugOnPause()
{
work(pause);
aTimer.Enabled = false;
aTimer.Stop();
}
/// <summary>
/// 服务恢复执行代码
/// </summary>
internal void DebugOnContinue()
{
work(conti);
aTimer.Enabled = true;
aTimer.Start();
}
/// <summary>
/// 服务即将关闭执行代码
/// </summary>
internal void DebugOnShutdown()
{
work(shutdown);
}
#endregion
}
}
Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace WindowsServiceTest
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
static void Main()
{
Service1 service = new Service1();
if (Environment.UserInteractive)//调试模式
{
service.DebugOnStart();
Console.ReadKey();
service.DebugOnPause();
Console.ReadKey();
service.DebugOnContinue();
Console.ReadKey();
service.DebugOnShutdown();
Console.ReadKey();
service.DebugOnStop();
Console.ReadKey();
}
else//正常
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
service
};
ServiceBase.Run(ServicesToRun);
}
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="PATH" value="D:\\MyServiceLog.txt"/>
<add key="Debug" value="D:\\Service\\Debug.txt"/>
</appSettings>
</configuration>
给服务添加安装,在 Service1.cs[设计] 界面,鼠标点击右键-》添加安装程序
添加成功后:此时软件会生成两个组件,分别为“serviceInstaller1”及“serviceProcessInstaller1”
可以对其属性进行修改。F4 查看属性并修改
ServiceProcessInstaller 类 和 ServiceInstaller 类 详细信息。
修改属性字段值:
一个简单的调试方法,把项目输出类型改为 控制台应用程序类型。就可以像控制台程序一样调试了。
安装方法:
1:使用VS 开发人员命令行
打开 VS 开发命令行,使用管理员权限运行
installutil.exe 命令:+ 程序路径(生成成功的可执行文件路径)
我的是在:E:\C#Notes\WindowsService\WindowsServiceTest\bin\Debug\WindowsServiceTest.exe
查看服务:
卸载服务:
installutil.exe/u E:\C#Notes\WindowsService\WindowsServiceTest\bin\Debug\WindowsServiceTest.exe
如果服务终止不掉,使用 CMD 命令强制杀死。打开命令行窗口,运行 sc queryex 命令来获取服务的 PID,接着使用 taskkill 命令来停止它
强制删除服务:
sc delete 服务名(如果服务名中间有空格,就需要前后加引号);然后重启电脑 services.msc 打开服务列表应该就不见了。
使用程序界面安装服务:
新建一个 winform 程序,引用 server 服务。
代码:
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;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Configuration;
using System.Collections;
namespace ServiceSetup
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
serviceFilePath = ConfigurationManager.AppSettings["PATH"];
}
string serviceFilePath = string.Empty;
string serviceName = "MyService";
/// <summary>
/// 安装服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butSetup_Click(object sender, EventArgs e)
{
if (this.IsServiceExisted(serviceName))
{
this.UninstallService(serviceName);
}
this.InstallService(serviceFilePath);
}
/// <summary>
/// 启动服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butStrat_Click(object sender, EventArgs e)
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStart(serviceName);
}
else
{
MessageBox.Show("服务不存在!");
}
}
/// <summary>
/// 停止服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butStop_Click(object sender, EventArgs e)
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStop(serviceName);
}
}
/// <summary>
/// 卸载服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butUninstall_Click(object sender, EventArgs e)
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStop(serviceName);
this.UninstallService(serviceFilePath);
}
}
/// <summary>
/// 判断服务是否存在
/// </summary>
/// <param name="serviceName">服务名称</param>
/// <returns></returns>
private bool IsServiceExisted(string serviceName)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController sc in services)
{
if (sc.ServiceName.ToLower() == serviceName.ToLower())
{
return true;
}
}
return false;
}
/// <summary>
/// 安装服务
/// </summary>
/// <param name="serviceFilePath"></param>
private void InstallService(string serviceFilePath)
{
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = serviceFilePath;
IDictionary savedState = new Hashtable();
installer.Install(savedState);
installer.Commit(savedState);
}
}
/// <summary>
/// 卸载服务
/// </summary>
/// <param name="serviceFilePath"></param>
private void UninstallService(string serviceFilePath)
{
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = serviceFilePath;
installer.Uninstall(null);
}
}
/// <summary>
/// 启动服务
/// </summary>
/// <param name="serviceName"></param>
private void ServiceStart(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Stopped)
{
control.Start();
}
}
}
/// <summary>
/// 停止服务
/// </summary>
/// <param name="serviceName"></param>
private void ServiceStop(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Running)
{
control.Stop();
}
}
}
}
}
但是启动安装必须要以管理员 权限运行,才能安装服务
Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ServiceSetup
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//获得当前登录的Windows用户标示
System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
//判断当前用户是否是管理员权限
if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
{
Application.Run(new MainForm()); //是管理员。直接运行
}
else
{
//创建启动对象
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = Application.ExecutablePath;
//设置启动动作,确保以管理员身份运行
startInfo.Verb = "runas";
try
{
System.Diagnostics.Process.Start(startInfo);
}
catch
{
return;
}
Application.Exit();
}
}
}
}
参考博文:https://blog.csdn.net/Andrewniu/article/details/97300245