概述C#调用Windows服务

开发 后端
本文介绍C#调用Windows服务,Windows服务是独立于登录用户而工作的Windows应用程序,它通常在计算机启动时开始执行,且常常连续执行,直到计算机关闭为止。

Windows服务是独立于登录用户而工作的Windows应用程序,它通常在计算机启动时开始执行,且常常连续执行,直到计算机关闭为止。像Exchange Server,IIS和杀毒软件等都使用这种方式,这样就可以独立于某一用户而且可以在任何用户登录前来运行,同时也可以服务于所有的进程,从而以一种服务的形式存在。

正因为Windows服务有着这么多的特性,因此,当需要一些特殊功能的时候就可以考虑C#调用Windows服务来解决问题。比如下面我们要做的这个例子。对于我们这些程序设计人员,计算机是在一起工作时间最长的伙伴,每天都会对着它的屏幕八个小时以上,还不包括下班后在家打游戏的时间,因此,保护眼睛是最重要的了。问题的起因来源于本人周六去眼科对激光手术的复查,大夫一再向我强调眼睛的自我调节能力,就是说只要你能保证你每隔一个小时左右就闭眼休息或向远处眺望,离开电脑屏幕,那么已经治好的近视就不会反弹。本人虽是自律性比较强的人,但在计算机屏幕面前就不再如此了,往往几个小时也不抬头一次,为了眼睛的健康,我决定把这个艰巨的任务交由计算机来完成,让它在一小时左右自动提醒我休息五分钟。如此一来,岂不是再也不用顾虑这件事了。

功能虽然简单,但要写个程序放在启动组里每天自动运行也不是一个好的办法,正巧以前也没做过Windows服务,不如索性来试一试,同进也看看.NET为我们提供了多么先进的功能吧,于是决定,就用C#来做一个提醒我保护眼睛的Windows服务,取名就叫CareEye吧。

运行Visual Studio.NET 2003,建立一个C#调用Windows服务项目,在CareEye.cs的设计视图提示可以把需要的控件和组件拖动到这上面,假如想要做系统日志的话当然就可以把EventLog组件拖过来了,不过这个程序好像不需要这些东西,还是算了吧。那么计时要不要采用计时器控件呢?想了一下,这个控件虽然好用,但太常用了,本着学习新知识的原则,最恰当的恐怕就是线程了,而且在以后做其他Windows服务的时候线程肯定是必需的,所以还是用线程好,这样我只要在线程中完成对时间的监测,把线程的启动和停止交给服务的启动和停止,呵,很方便啊。

再来看CareEye.cs的源程序,一大堆没见过的东西,不过仔细分析一下也就没什么了。CareEye类派生于ServiceBase类,因此继承了基本服务类的特性,显然Main()方法会由SCM(服务控制管理程序)调用,在这个方法中Run一个新的CareEye实例,这样就运行了一个Windows服务,OnStart()和OnStop()明显是用于启动和停止服务的响应函数了。

注意在Main()方法中有一个ServiceBase[]的数组,它是为那些一个服务进程包含多个服务准备的,对于这个程序来说,它只有一个 CareEye服务,因此完全可以把这个数组删除,而只是使用System.ServiceProcess.ServiceBase.Run(new CareEye());一句就够了。

接下来为了使用线程,需要引入System.Threading命名空间,为了使用对话框,还需要引入System.Windows.Forms命名空间,这是为了将来提示用户时显示对话框而准备的。

下面为类CareEye添加一个成员字段private Thread MainThread;同时在构造函数中对其进行初始化:

  1. MainThread=new Thread(new ThreadStart(ThreadFunc));  
  2. MainThread.Priority=ThreadPriority.Lowest; 

这里把线程的优先级设到最低,这样不会耗用过多的系统性能。这个线程对象使用ThreadFunc作为线程函数,因此将这个线程函数补充完整:

  1. public static void ThreadFunc()  
  2. {  
  3. int LastHour=DateTime.Now.Hour;  
  4. while (true)  
  5. {  
  6. System.Threading.Thread.Sleep(60000);  
  7. if (DateTime.Now.Hour-1==LastHour)  
  8. {  
  9. MessageBox.Show,MessageBoxButtons.OK,MessageBoxIcon.Warning,
    MessageBoxDefaultButton.Button1,  
  10. MessageBoxOptions.DefaultDesktopOnly);  
  11. LastHour=DateTime.Now.Hour;  
  12. }  
  13. }  

余下的代码就简单了,只要在OnStart中启动线程,在OnStop中停止线程就行了。

以上的服务程序虽然很简单,线程的处理上也不很恰当,也违背了很多服务程序的原则比如界面显示等,但对于本人的需求而言是足够了,因此就如此制作了。如果你有需要,当然可以把对话框改为其他的提醒方式如响铃等,线程也可以使用内核对象同时使用更好的处理方法。

Windows服务就做完了,余下的就是要测试了,但发现这个EXE无法运行,它会提示你该EXE需要使用安装程序来安装服务,看来不可能写一个程序就算是Windows服务了,还要把它注册到Windows才行。

接下来,右击CareEye.cs的设计视图,添加安装程序,(VS.NET想得就是挺周到的),这下又出来一批代码,不过好在不用改代码了,只要把 Account的账户类型设成LocalSystem,把StartType设成手动启动就行了,这里用手动是为了方便调试,以后可以改成自动类型。

编译完后,还是无法运行,此处还需要一步,就是运行installutil来安装这个服务,其安装和卸载的用法为:

installutil CareEye.exe
installutil /u CareEye.exe

安装完后能过系统的服务管理器你就可以看到你的服务了,只要点击启动就可以把它启动,把时间向前改一个小时它就会提醒你需要休息了,呵呵,够简单了吧。

如果你想制作成安装包分发给自己的朋友,只需要再添加个部署项目就行了,不过为了完成自注册,要在自定义操作编辑器中的安装阶段添加一个自定义的安装操作,把InstallerClass属性设成TRUE即可。

以下是careeye.cs的源程序:

  1. using System;  
  2. using System.Collections;  
  3. using System.ComponentModel;  
  4. using System.Data;  
  5. using System.Diagnostics;  
  6. using System.ServiceProcess;  
  7. using System.Threading;  
  8. using System.Windows.Forms;  
  9. namespace CareEye  
  10. {  
  11. public class CareEye : System.ServiceProcess.ServiceBase  
  12. {  
  13. private Thread MainThread;  
  14. /// <summary> 
  15. /// 必需的设计器变量。  
  16. /// </summary> 
  17. private System.ComponentModel.Container components = null;  
  18.  
  19. public CareEye()  
  20. {  
  21. // 该调用是 Windows.Forms 组件设计器所必需的。  
  22. InitializeComponent();  
  23.  
  24. // TODO: 在 InitComponent 调用后添加任何初始化  
  25. MainThread=new Thread(new ThreadStart(ThreadFunc));  
  26. MainThread.Priority=ThreadPriority.Lowest;  
  27. }  
  28.  
  29. // 进程的主入口点  
  30. static void Main()  
  31. {  
  32. //System.ServiceProcess.ServiceBase[] ServicesToRun;  
  33.  
  34. // 同一进程中可以运行多个用户服务。若要将  
  35. //另一个服务添加到此进程,请更改下行  
  36. // 以创建另一个服务对象。例如,  
  37. //  
  38. // ServicesToRun = New System.ServiceProcess.ServiceBase[] {
    new CareEye(), new MySecondUserService()};  
  39. //  
  40. //ServicesToRun = new System.ServiceProcess.ServiceBase[] { 
    new CareEye() };  
  41.  
  42. System.ServiceProcess.ServiceBase.Run(new CareEye());  
  43. }  
  44.  
  45. /// <summary> 
  46. /// 设计器支持所需的方法 - 不要使用代码编辑器  
  47. /// 修改此方法的内容。  
  48. /// </summary> 
  49. private void InitializeComponent()  
  50. {  
  51. //  
  52. // CareEye  
  53. //  
  54. this.ServiceName = "CareEye";  
  55.  
  56. }  
  57.  
  58. /// <summary> 
  59. /// 清理所有正在使用的资源。  
  60. /// </summary> 
  61.  
  62. protected override void Dispose( bool disposing )  
  63. {  
  64. if( disposing )  
  65. {  
  66. if (components != null)  
  67. {  
  68. components.Dispose();  
  69. }  
  70. }  
  71. base.Dispose( disposing );  
  72. }  
  73.  
  74. /// <summary> 
  75. /// 设置具体的操作,以便服务可以执行它的工作。  
  76. /// </summary> 
  77. protected override void OnStart(string[] args)  
  78. {  
  79. // TODO: 在此处添加代码以启动服务。  
  80. MainThread.Start();  
  81. }  
  82.  
  83. /// <summary> 
  84. /// 停止此服务。  
  85. /// </summary> 
  86. protected override void OnStop()  
  87. {  
  88. // TODO: 在此处添加代码以执行停止服务所需的关闭操作。  
  89. MainThread.Abort();  
  90. }  
  91. public static void ThreadFunc()  
  92. {  
  93. int LastHour=DateTime.Now.Hour;  
  94. while (true)  
  95. {  
  96. System.Threading.Thread.Sleep(60000);  
  97. if (DateTime.Now.Hour-1==LastHour)  
  98. {  
  99. MessageBox.Show,MessageBoxButtons.OK,MessageBoxIcon.Warning,
    MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);  
  100. LastHour=DateTime.Now.Hour;  
  101. }  
  102. }  
  103. }  
  104. }  
  105. }  

以上介绍C#调用Windows服务

【编辑推荐】

  1. C#字符串进行分割
  2. 全面测试C#字符串
  3. C# out和ref传递数组
  4. 浅析C#定义整型数组
  5. C#数据库连接字符串
责任编辑:佚名 来源: MSDN
相关推荐

2009-08-17 09:57:00

C# Windows

2009-08-07 17:19:50

C#调用外部进程

2009-08-21 17:11:41

C#调用Active组

2009-08-24 14:19:27

C# Windows应

2009-09-03 16:20:14

C#调用Windows

2009-07-31 16:12:10

Windows APIC#

2009-08-03 13:34:57

C#调用Windows

2009-08-17 13:18:01

C#调用Windows

2009-08-25 15:38:12

C# Windows服

2009-08-31 09:44:23

C# Employee

2009-08-13 15:18:23

C#文件上传

2009-08-18 09:26:07

C#线程功能

2009-07-31 14:08:54

C# 匿名函数

2009-08-18 17:29:02

C#使用指针

2009-09-03 11:15:38

C#设置Coopera

2009-08-19 11:09:00

C# Cast<T>

2009-08-20 16:28:45

C#匿名方法

2009-08-25 10:08:39

C# MyData对象

2009-08-25 16:49:44

C#使用if语句

2009-08-24 18:09:13

C#构造函数
点赞
收藏

51CTO技术栈公众号