昨天一个朋友想用做个短信网关,与移动TCP/IP通迅来完成短信的发送。并且想是用一个Windows服务来完成这个工作,但是又想让管理员能在客户端(浏览器端)对服务进行装载,卸载,启动,停止。我初步听了以后,觉得这个需求是可以完成的,服务这个项目的建立没有问题,控制服务这个项目也是没有问题的。于是就研究了一下,并去网上搜集了一些资料,整理了一个从技术角度相对完整的文档,拿出来给大家分享一下。
为了简化业务,这里就把与短信网关通信的需求改成每间隔一秒钟向一个txt文档写一个当前时间的需求。
我们先来看服务部分:
打开VS2008,“文件→新建→项目”,选择“Windows”项中的“Windows服务”,根据自己的情况修跑径和名称,这里的名称修为“WriteTextService”,确定后,出现一个“若要在类中添加组件,请从工具箱中拖出它们,然后例用”属性”窗口来设置它们的属性。若要为类创建方法和事件,请单击此处切换到代码视图。”的一个界面,我们如果处理业务逻辑,单击“单击此处切换到代码视图”,来转换到代码页。
代码
WriteTextService.cs
1
using System;
2
using System.ServiceProcess;
3
using System.IO;
4
using System.Threading;
5
6
namespace WriteTextServiceNS
7

{
8
public partial class WriteTextService : ServiceBase
9
{
10
public WriteTextService()
11
{
12
InitializeComponent();
13
}
14
protected override void OnStart(string[] args)
15
{
16
Thread t = new Thread(new ThreadStart(DY));
17
t.Start();
18
}
19
private void DY()
20
{
21
while (true)
22
{
23
File.WriteAllText(@"F:/gsw.txt",DateTime.Now.ToString());
24
Thread.Sleep(2000);
25
}
26
}
27
protected override void OnStop()
28
{
29
}
30
}
31
}
32
现在,我们还需要在服务中创建一个服务安装类,来完成服务初始化安装工作。
我们创建一个类ServiceInstall
ServiceInstall.cs
1
using System.Collections;
2
using System.Configuration.Install;
3
using System.ServiceProcess;
4
using System.ComponentModel;
5
using Microsoft.Win32;
6
7
namespace WriteTextServiceNS
8

{
9
[RunInstaller(true)]
10
public class ServiceInstall : Installer
11
{
12
private ServiceInstaller WTSerInst; //它由安装实用工具用来将与服务关联的注册表值写入 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services 注册表项内的子项。
13
private ServiceProcessInstaller WTProInst; //安装实用工具使用它来写与要安装服务关联的注册表值。
14
public ServiceInstall()
15
{
16
WTProInst = new ServiceProcessInstaller();
17
WTProInst.Account = ServiceAccount.LocalSystem; //安装服务时使用的账户
18
19
WTSerInst = new ServiceInstaller();
20
WTSerInst.StartType = ServiceStartMode.Automatic ; //启动服务的后模式(Automatic 自动,Manual 手动,Disabled 禁用)
21
WTSerInst.ServiceName = "WriteTextService"; //要安装服务的名称 与服务类名相同
22
23
Installers.Add(WTSerInst); //把服务安装类放入安装集合中
24
Installers.Add(WTProInst);
25
}
26
/**//// <summary>
27
/// 重写父类的安装,并在安装服务后写入服务的描述
28
/// </summary>
29
/// <param name="stateSaver"></param>
30
public override void Install(IDictionary stateSaver)
31
{
32
RegistryKey system,service,config;
33
try
34
{
35
base.Install(stateSaver);
36
system = Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services");
37
service = system.OpenSubKey(this.WTSerInst.ServiceName, true);
38
service.SetValue("Description", "……这是一个每秒写入Text一次时间的服务……");
39
config = service.CreateSubKey("AdditionalInformation");
40
}
41
catch
42
{ }
43
}
44
/**//// <summary>
45
/// 重写父类的卸载,并在卸载服务后删除描述
46
/// </summary>
47
/// <param name="stateServer"></param>
48
public override void Uninstall(IDictionary stateServer)
49
{
50
RegistryKey system,currentControlSet,services,service;
51
try
52
{
53
system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System");
54
currentControlSet = system.OpenSubKey("CurrentControlSet");
55
services = currentControlSet.OpenSubKey("Services");
56
service = services.OpenSubKey(this.WTSerInst.ServiceName, true);
57
service.DeleteSubKeyTree("AdditionalInformation");
58
}
59
catch
60
{}
61
finally
62
{
63
base.Uninstall(stateServer);
64
}
65
}
66
}
67
}
68
这样就完成了一个服务,关且有服务的描述,最要是通过重写父类Install和Uninstall来完成对服务描述的添加。因为服务都是在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/WriteTextService下有个项Description,给这个项添加数据就对应该服务的描述,所以Install和Uninstall两个方法本质上就是注册表英的添加与删除。
接下来我们看一下服务的操作,即装载,卸载,启动,停止。
我们新建一个web网站,只有一个Default.aspx页面,代码如下:
Default.aspx
1
<%
@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
2
3
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
5
<html xmlns="http://www.w3.org/1999/xhtml">
6
<head runat="server">
7
<title>无标题页</title>
8
</head>
9
<body>
10
<form id="form1" runat="server">
11
<div>
12
13
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="装载服务" />
14
<asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="卸载服务" />
15
<asp:Button ID="Button3" runat="server" onclick="Button3_Click" Text="启动服务" />
16
<asp:Button ID="Button4" runat="server" onclick="Button4_Click" Text="停止服务" />
17
18
</div>
19
</form>
20
</body>
21
</html>
22
Default.aspx.cs
1
using System;
2
using System.Configuration;
3
using System.Web;
4
using System.Web.Security;
5
using System.Web.UI;
6
using System.Web.UI.HtmlControls;
7
using System.Web.UI.WebControls;
8
using System.Web.UI.WebControls.WebParts;
9
using System.Xml.Linq;
10
using System.Configuration.Install;
11
using System.Collections;
12
using System.ServiceProcess;
13
14
15
public partial class _Default : System.Web.UI.Page
16

{
17
protected void Page_Load(object sender, EventArgs e)
18
{
19
20
}
21
protected void Button1_Click(object sender, EventArgs e)
22
{
23
AssemblyInstaller myassemblyinstaller = new AssemblyInstaller();//加载一个程序集,并运行其中的所有安装程序。
24
myassemblyinstaller.UseNewContext = true;
25
myassemblyinstaller.Path = @"f:/gsw.exe";//服务所在的路径
26
Hashtable mysavedstate = new Hashtable();
27
myassemblyinstaller.Install(mysavedstate);
28
myassemblyinstaller.Commit(mysavedstate);
29
myassemblyinstaller.Dispose();
30
Response.Write("安装服务成功");
31
32
}
33
protected void Button2_Click(object sender, EventArgs e)
34
{
35
AssemblyInstaller myassemblyinstaller = new AssemblyInstaller();
36
myassemblyinstaller.UseNewContext = true;
37
myassemblyinstaller.Path = @"f:/gsw.exe";//服务所在的路径
38
myassemblyinstaller.CommandLine = new string[1]
{ "/u" };// 利用/u命令来完成卸载
39
myassemblyinstaller.Uninstall(null);
40
myassemblyinstaller.Dispose();
41
Response.Write("卸载服务成功");
42
}
43
protected void Button3_Click(object sender, EventArgs e)
44
{
45
ServiceController sc = new ServiceController();//表示 Windows 服务并允许连接到正在运行或者已停止的服务、对其进行操作或获取有关它的信息。
46
sc.DisplayName = "桂素伟";
47
sc.ServiceName = "WriteTextService";
48
sc.Start();//启动这个名称的服务
49
System.Threading.Thread.Sleep(1000);
50
sc.Refresh();//刷新服务的状态
51
if (sc.Status == ServiceControllerStatus.Running)//判断服务是已经运行
52
{
53
Response .Write ("服务成功启动!");
54
}
55
}
56
protected void Button4_Click(object sender, EventArgs e)
57
{
58
ServiceController sc = new ServiceController();
59
sc.ServiceName = "WriteTextService";
60
sc.Stop();
61
62
System.Threading.Thread.Sleep(1000);
63
sc.Refresh();//刷新服务的状态
64
if (sc.Status == ServiceControllerStatus.Stopped)//判断服务是已经运行
65
{
66
Response .Write ("服务成功停止!");
67
}
68
}
69
}
70
我们是通过AssemblyInstaller类来完成对服务的装载和卸载,通过ServiceController类来完成对服务的启动和停止。
这样,我们就把服务和控制服务的代友做完整了。
(我的代码是在vista和vs2008下实现的。)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
2007-12-26 关于模式对话框和非模式对话框(Form.Show()&Form.ShowDialog())