做成一件小事,收获一份知识。(续)
现在,回顾我编程的过程,其实主要解决的问题有两个:
1.如何使用基于.net框架的C#调用Windows中的服务,控制服务的启动、停止和启动方式;
2.Vista下的编程
最后一个问题其实很简单,但我到现在仍然没有给出一个完美的解决。我编好的程序成功运行,但当我试图去控制一个Windows服务的时候,系统会报错。原因是我没有获得权限,因此无法控制Windows服务。这样的原因在Vista之前是不存在的,Vista使用了用户帐户控制(UAC),因此在访问系统文件和程序的时候需要获得权限才可以正常访问,而用户管理员也必须在访问的时候确认访问才可以。这多多少少和Ubuntu中的sudo有些相似,都是为了系统安全考虑。但是这样如何在编程的时候写入代码呢?我不会。我只是修改了编译好的程序属性。
这样程序只有在作为程序可以运行了,但在IDE中无法编译正常运行。因此我只有选择编译完后,到Debug文件夹中双击ServiceControl程序。感叹自己不懂的东西实在是太多了。
对于第一个问题,到google上和msdn上检索一下相关的技术文章就会发现其实“想要控制Windows服务”其实不是一件难事。对于这个问题,要使用到System.ServiceProcess命名空间极其中的主要使的两个类,一个是ServiceController,另一个是ServiceInstaller。前者实现了Windows服务的控制,后者实现了服务启动类型的控制。
如何控制一个Windows服务?
对于一个Windows服务而言,要想控制它的启动、停止、暂停,要使用ServiceController类。控制一个服务,首先要确定这个服务。一个服务的属性有很多,包括服务所在的服务器,服务名称,服务显示名词,服务描述,服务状态等。通过服务所在服务器和服务显示名称,或者服务所在服务器和服务名称即可确定服务。我用到了前者。在.net中即.MachineName和.DisplayName两个属性,为对象的这另个属性赋值即可确定此对象控制哪个服务。下面先展示一下代码,然后再做说明(窗体见本文章的上一期)。代码如下:
using System;2
using System.Windows.Forms;3
using System.ServiceProcess;4

5
namespace ServiceControl6
{7
public partial class Form1 : Form8
{9
//用于控制服务的两个类10
ServiceController sc = new ServiceController();11
ServiceInstaller si = new ServiceInstaller();12

13
//构造窗体时加载的代码14
public Form1()15
{16
InitializeComponent();17
listBox1.SelectedIndex = 0;18
sc.MachineName = "WULEI-PC";19
si.DisplayName = sc.DisplayName = listBox1.SelectedItem.ToString();20
lableText();21
buttonEnable();22
}23

24
//三个lable用于显示服务的显示名称、服务名称和服务状态25
private void lableText()26
{27
label1.Text = sc.DisplayName;28
label2.Text = sc.ServiceName;29
label3.Text = sc.Status.ToString();30
}31

32
//当服务状态为启动时,只有停止按钮有效;亦则相反。33
private void buttonEnable()34
{35
if (sc.Status == ServiceControllerStatus.Running)36
{37
btnStart.Enabled = false;38
btnStop.Enabled = true;39
}40
else41
{42
btnStop.Enabled = false;43
btnStart.Enabled = true;44
}45
}46

47
//启动按钮,启动选定的服务48
private void btnStart_Click(object sender, EventArgs e)49
{50
si.StartType = ServiceStartMode.Manual;51
sc.Start();52
sc.WaitForStatus(ServiceControllerStatus.Running);53
buttonEnable();54
lableText();55
}56
//停止按钮,停止选定的服务57
private void btnStop_Click(object sender, EventArgs e)58
{59
sc.Stop();60
sc.WaitForStatus(ServiceControllerStatus.Stopped);61
buttonEnable();62
lableText();63
}64

65
//列表。选中服务,显示相关服务状态66
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)67
{68
si.DisplayName=sc.DisplayName = listBox1.SelectedItem.ToString();69
lableText();70
buttonEnable();71
}72
}73
}代码18、19行为对象的MachineName和DisplayName赋值,从而确定服务。这之后才可以启动、暂停或者停止服务(代码51、59行),但是要注意一点的是,如果服务的启动类型为“禁用”,那么此服务将无法直接被启动,首先要将启动类型改为“手动”或者“自动”(代码50行将服务的启动类型改为“手动”)。代码52和60行是一个非常关键的内容,这段两行代码执行结果是等待当前服务状态的更改。如第60行,等待服务停止。这之后才会运行后面的buttonEnable()自定义方法,否则可能服务还没有停止就运行后面的方法了;如果后面的方法需要当前的服务状态作为运行的基础,那么程序会出现错误。
总结:
1.调用一个Windows服务首先要确定服务
编程时使用System.ServiceProcess命名空间,通过ServiceController类的MachineName和ServiceName / DisplayName)确定服务,ServiceInstaller使用DisplayName确定服务;
2.控制一个服务之前要确定启动类型不为“禁用”
通过ServiceController对象的.start()和.stop()方法启动和停止服务,启动服务之前要确定服务的启动类型不是“禁用”;如果为禁用,要将其修改为“自动”或者“手动”,通过ServiceInstaller对象的StartType属性修改启动类型(赋值要用到枚举ServiceStartMode)。
3.如果修改启动类型的状态后要执行与服务状态相关的代码,须要使用WaitForStatus(参数)(括号中的参数使用枚举ServiceControllerStatus)。
今天为了解决一个小问题,编写了一个小程序,收获了几点小知识,很开心。


浙公网安备 33010602011771号