做成一件小事,收获一份知识。(续)

现在,回顾我编程的过程,其实主要解决的问题有两个:

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两个属性,为对象的这另个属性赋值即可确定此对象控制哪个服务。下面先展示一下代码,然后再做说明(窗体见本文章的上一期)。代码如下:

 1using System;
 2using System.Windows.Forms;
 3using System.ServiceProcess;
 4
 5namespace ServiceControl
 6{
 7    public partial class Form1 : Form
 8    {
 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            else
41            {
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)。

 

今天为了解决一个小问题,编写了一个小程序,收获了几点小知识,很开心。

 

 

posted on 2008-08-26 20:18  iPeterRex  阅读(1857)  评论(4)    收藏  举报

导航

转载本博客文章请注明转载地址、作者姓名