Windows服务开发
1.新建Windows服务项目
(1)
(2)默认服务名称“Service1”。双击服务,在"设计"视图中,右击"属性",在属性窗口可以重命名服务
业务代码中,默认重写OnStart和OnStop两个方法,用于启动和停止服务对组件的处理:
/// <summary>
/// 启动
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
Log4netHelper.Info("Demo Service启动");
// TODO 业务处理
}
/// <summary>
/// 停止
/// </summary>
protected override void OnStop()
{
Log4netHelper.Info("Demo Service停止");
}
(3)添加安装程序
(4)配置安装程序
注意:
- Account设置为LocalService。
- ServiceName设置为DemoService,和服务类名称保持一致。
- StartType设置为Automatic,自启动。
- Description设置服务描述,此描述在"服务"窗口描述列显示。
- DisplayName可以不同于ServiceName属性,它是系统使用的名称,此名称在"服务"窗口名称列显示。
2.调试服务-将 Windows 服务作为控制台应用运行
(1)向你运行 OnStart 和 OnStop 方法的类添加一个方法:
internal void TestStartupAndStop(string[] args)
{
this.OnStart(args);
Console.ReadLine();
this.OnStop();
}
(2)按如下所示重写 Main
方法:
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
MyNewService service1 = new MyNewService(args);
service1.TestStartupAndStop(args);
}
else
{
// Put the body of your old Main method here.
}
}
(3)在项目属性的“应用程序” 选项卡中,将“输出类型” 设置为“控制台应用程序” 。
(4)选择“启动调试” (F5)。
(5)若要将该程序再次作为 Windows 服务运行,请安装它并像通常启动 Windows 服务一样启动它。 不必恢复这些更改。
在某些情况下,你必须使用 Windows 调试器,比如当你想要调试仅在系统启动时发生的问题时。
3.新建窗体项目,创建可视化服务管理界面
查看代码
#region
const string serviceName = "HzService";
string serviceFilePath = Application.StartupPath + "\\Hz_WindowsService.exe";
//事件:安装服务
private void button1_Click(object sender, EventArgs e)
{
try
{
if (this.IsServiceExisted(serviceName))
{
this.UninstallService(serviceName);
}
this.InstallService(serviceFilePath);
Thread.Sleep(200);
MessageBox.Show("服务安装成功。", "提示");
}
catch (Exception e1)
{
MessageBox.Show("出错!" + e1.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//事件:启动服务
private void button2_Click(object sender, EventArgs e)
{
try
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStart(serviceName);
MessageBox.Show("服务启动成功。", "提示");
btnStart.Enabled = false;
btnStop.Enabled = true;
}
else
{
MessageBox.Show("服务不存在。", "提示");
}
}
catch (Exception e1)
{
MessageBox.Show("出错!" + e1.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//事件:停止服务
private void button4_Click(object sender, EventArgs e)
{
try
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStop(serviceName);
MessageBox.Show("服务停止成功。", "提示");
btnStart.Enabled = true;
btnStop.Enabled = false;
}
else
{
MessageBox.Show("服务不存在。", "提示");
}
}
catch (Exception e1)
{
MessageBox.Show("出错!" + e1.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//事件:卸载服务
private void button3_Click(object sender, EventArgs e)
{
try
{
if (this.IsServiceExisted(serviceName))
{
this.ServiceStop(serviceName);
this.UninstallService(serviceFilePath);
MessageBox.Show("服务卸载成功。", "提示");
}
else
{
MessageBox.Show("服务不存在。", "提示");
}
}
catch (Exception e1)
{
MessageBox.Show("出错!" + e1.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//判断服务是否存在
private bool IsServiceExisted(string serviceName)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController sc in services)
{
if (sc.ServiceName.ToLower() == serviceName.ToLower())
{
return true;
}
}
return false;
}
//安装服务
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);
}
}
//卸载服务
private void UninstallService(string serviceFilePath)
{
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = serviceFilePath;
installer.Uninstall(null);
}
}
//启动服务
private void ServiceStart(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Stopped)
{
control.Start();
}
}
}
//停止服务
private void ServiceStop(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Running)
{
control.Stop();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
btnFlush_Click(null, null);
}
private void btnFlush_Click(object sender, EventArgs e)
{
try
{
this.btnStart.Enabled = false;
this.btnStop.Enabled = false;
ServiceController sc = new ServiceController(serviceName);
switch (sc.Status)
{
case ServiceControllerStatus.Running:
this.btnStop.Enabled = true;
break;
case ServiceControllerStatus.Stopped:
this.btnStart.Enabled = true;
break;
}
}
catch (Exception e1)
{
MessageBox.Show("出错!" + e1.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
补充:如未进行以下步骤,则运行“服务管理程序”进行相关操作时,需要右键管理员权限打开。
由于需要安装服务,故需要使用UAC中Administrator的权限,鼠标右击项目,添加新项“应用程序清单文件,如下图所示:
打开该文件,并将<requestedExecutionLevel level="asInvoker" uiAccess="false" />改为<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />,如下图所示:
4.遇到的问题
问题:当服务无法停止时。
解决方案:
管理员打开命令行窗口,运行 sc queryex 命令来获取服务的 PID(也可以右键任务管理器,在服务页找到该服务对应PID),接着使用 taskkill 命令来停止它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
C:\>sc queryex PlatformMessageService SERVICE_NAME: PlatformMessageService TYPE : 10 WIN32_OWN_PROCESS STATE : 2 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x1 WAIT_HINT : 0xbb8 PID : 524 FLAGS : C:\>taskkill /PID 524 /F SUCCESS: The process with PID 3756 has been terminated.<br><br><br> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现