用Visual C#建立Windows服务程序

Visual C# 建立Windows 服务程序
一.Windows服务介绍:

  Windows服务之前被称做NT服务,是一些运行在Windows NT、Windows 2000和Windows XP等操做系统下用户环境之外的程序。在之前,编写Windows服务程序须要程序员很强的C或C++功底。然而如今在Visual Studio.Net下,你能够运用C++或Visual C#或Visual Basic.Net很轻松的建立一个Windows服务程序。一样,你还能够运用其余任何与CLR相容的语言来建立Windows服务程序。本文就向你们介绍如何运用Visual C#来一步一步建立一个文件监视的Windows服务程序,而后介绍如何安装、测试和调试该Windows服务程序。

  在介绍如何建立Windows服务程序之前,我先向你们介绍一些有关Windows服务的背景知识。一个Windows服务程序是在Windows操做系统下能完成特定功能的可执行的应用程序。Windows服务程序虽然是可执行的,可是它不像通常的可执行文件经过双击就能开始运行了,它必须有特定的启动方式。这些启动方式包括了自动启动和手动启动两种。对于自动启动的Windows服务程序,它们在Windows启动或是重启以后用户登陆以前就开始执行了。只要你将相应的Windows服务程序注册到服务控制管理器(Service Control Manager)中,并将其启动类别设为自动启动就好了。而对于手动启动的Windows服务程序,你能够经过命令行工具的NET START 命令来启动它,或是经过控制面板中管理工具下的服务一项来启动相应的Windows服务程序(见图1)。一样,一个Windows服务程序也不能像通常的应用程序那样被终止。由于Windows服务程序通常是没有用户界面的,因此你也要经过命令行工具或是下面图中的工具来中止它,或是在系统关闭时使得Windows服务程序自动中止。由于Windows服务程序没有用户界面,因此基于用户界面的API函数对其是没有多大的意义。为了能使一个Windows服务程序可以正常并有效的在系统环境下工做,程序员必须实现一系列的方法来完成其服务功能。Windows服务程序的应用范围很广,典型的Windows服务程序包含了硬件控制、应用程序监视、系统级应用、诊断、报告、Web和文件系统服务等功能。

  图1



  二.建立Windows服务程序:

在介绍如何建立Windows服务程序之前,我先向你们介绍一下.Net框架下与Windows服务相关的命名空间和其中的类库。.Net框架大大地简化了Windows服务程序的建立和控制过程,这要归功于其命名空间中的功能强大的类库。和Windows服务程序相关的命名空间涉及到如下两个:System.ServiceProcess和System.Diagnostics。

要建立一个最基本的Windows服务程序,咱们只须要运用.Net框架下的System.ServiceProcess命名空间以及其中的四个类:ServiceBase、ServiceInstaller、ServiceProcessInstaller以及ServiceController,其体系结构可见图2。

  图2



  其中ServiceBase类定义了一些可被其子类重载的函数,经过这些重载的函数,服务控制管理器就能够控制该Windows服务程序了。这些函数包括:OnStart()、OnStop()、OnPause()以及OnContinue()等四个。并且ServiceBase类的子类还能够重载OnCustomCommand()函数来完成一些特定的操做。经过重载以上的一些函数,咱们就完成了一个Windows服务程序的基本框架,这些函数的重载方法以下:


protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
protected override void OnPause()
{
}
protected override void OnContinue()
{
}


  ServiceBase类还为咱们提供了一些属性,而这些属性是任何Widnows服务程序所必须的。其中的ServiceName属性指定了Windows服务的名称,经过该名称系统就能够调用Windows服务了,同时其它应用程序也能够经过该名称来调用它的服务。而CanPauseAndContinue和CanStop属性顾名思义就是容许暂停并恢复和容许中止的意思。

  要使得一个Windows服务程序可以正常运行,咱们须要像建立通常应用程序那样为它建立一个程序的入口点。在Windows服务程序中,咱们也是在Main()函数中完成这个操做的。首先咱们在Main()函数中建立一个Windows服务的实例,该实例应该是ServiceBase类的某个子类的对象,而后咱们调用由基类ServiceBase类定义的一个Run()方法。然而Run()方法并不就开始了Windows服务程序,咱们必须经过前面提到的服务控制管理器调用特定的控制功能来完成Windows服务程序的启动,也就是要等到该对象的OnStart()方法被调用时服务才真正开始运行。若是你想在一个Windows服务程序中同时启动多个服务,那么只要在Main()函数中定义多个ServiceBae类的子类的实例对象就能够了,方法就是建立一个ServiceBase类的数组对象,使得其中的每一个对象对应于某个咱们已预先定义好的服务。


{
System.ServiceProcess.ServiceBase[] MyServices;
MyServices = new System.ServiceProcess.ServiceBase[] { new Service1(), new Service2() };
System.ServiceProcess.ServiceBase.Run(MyServices);
}


static void Main()

  三.添加文件监视服务:

  了解了Windows服务的基本体系结构和建立方法后,咱们就能够试着往服务中添加一些实际的功能了。下面我将向你们介绍一个能监视本地文件系统的文件监视服务-FileMonitorService。该服务能根据预先设定的本地目录路径监视其中的文件包括子文件夹中的任何变化:文件建立、文件删除、文件更名、文件修改。同时,该服务还为每种变化建立了一个相对应的计数器,计数器的做用就是反映该种变化的频度。

  首先,咱们打开Visual Studio.Net,新建一个Visual C#的Windows服务的项目,如图3所示:

  图3



  在重载Windows服务的OnStart()函数以前,咱们先给其类添加一些计数器对象,这些计数器分别对应了文件的建立、删除、更名以及修改等变化。一旦指定目录中的文件发生以上的某种变化,与其相对应的计数器就会自动加1。全部的这些计数器都是定义为PerformanceCounter类型的变量的,该类是包含在System.Diagnostics命名空间中的。


private System.Diagnostics.PerformanceCounter fileCreateCounter;
private System.Diagnostics.PerformanceCounter fileDeleteCounter;
private System.Diagnostics.PerformanceCounter fileRenameCounter;
private System.Diagnostics.PerformanceCounter fileChangeCounter;


  以后咱们便在类的InitializeComponent()方法中建立以上定义的各个计数器对象并肯定其相关属性。同时咱们将该Windows服务的名称设置为“FileMonitorService”,设定其便是容许暂停并恢复的又是容许中止的。


private void InitializeComponent()
              {
                     this.components = new System.ComponentModel.Container();
                     this.fileChangeCounter = new System.Diagnostics.PerformanceCounter();
                     this.fileDeleteCounter = new System.Diagnostics.PerformanceCounter();
                     this.fileRenameCounter = new System.Diagnostics.PerformanceCounter();
                     this.fileCreateCounter = new System.Diagnostics.PerformanceCounter();
 
                     fileChangeCounter.CategoryName = "File Monitor Service";
                     fileDeleteCounter.CategoryName = "File Monitor Service";
                     fileRenameCounter.CategoryName = "File Monitor Service";
                     fileCreateCounter.CategoryName = "File Monitor Service";
 
                     fileChangeCounter.CounterName = "Files Changed";
                     fileDeleteCounter.CounterName = "Files Deleted";
                     fileRenameCounter.CounterName = "Files Renamed";
                     fileCreateCounter.CounterName = "Files Created";
 
                     this.ServiceName = "FileMonitorService";
                     this.CanPauseAndContinue = true;
                     this.CanStop = true;
                     servicePaused = false;
              }


  接着就是重载OnStart()函数和OnStop()函数,OnStart()函数完成了一些必要的初始化工做。在.Net框架下,文件的监视功能能够由FileSystemWatcher类来完成,该类是包含在System.IO命名空间下的。该Windows服务所要完成的功能包括了监视文件的建立、删除、更名和修改等变化,而FileSystemWatcher类包含全部了对应于这些变化的处理函数。


protected override void OnStart(string[] args)
              {    
                     FileSystemWatcher curWatcher = new FileSystemWatcher();
 
                     curWatcher.BeginInit();
                     curWatcher.IncludeSubdirectories = true;
                     curWatcher.Path =
             System.Configuration.ConfigurationSettings.AppSettings
               ["FileMonitorDirectory"];
                     curWatcher.Changed += new FileSystemEventHandler(OnFileChanged);
                     curWatcher.Created += new FileSystemEventHandler(OnFileCreated);
                     curWatcher.Deleted += new FileSystemEventHandler(OnFileDeleted);
                     curWatcher.Renamed += new RenamedEventHandler(OnFileRenamed);
                     curWatcher.EnableRaisingEvents = true;
                     curWatcher.EndInit();
              }


  注意其中被监视的目录是存放在一个应用程序配置文件中的,该文件是一个XML类型的文件。这种作法的好处就是咱们没必要从新编译并发布该Windows服务而只要直接修改其配置文件就能够达到更改所要监视的目录的功能了。

  当该Windows服务启动后,一旦被监视的目录中的文件发生某种变化,与其相对应的计数器的值便会相应的增长,方法很简单,只要调用计数器对象的IncrementBy()便可。


private void OnFileChanged(Object source, FileSystemEventArgs e)
              {
                     if( servicePaused == false )
                     {
                            fileChangeCounter.IncrementBy(1);
                     }
              }
 
              private void OnFileRenamed(Object source, RenamedEventArgs e)
              {
                     if( servicePaused == false )
                     {
                            fileRenameCounter.IncrementBy(1);
                     }
              }
 
              private void OnFileCreated(Object source, FileSystemEventArgs e)
              {
                     if( servicePaused == false )
                     {
                            fileCreateCounter.IncrementBy(1);
                     }
              }
 
              private void OnFileDeleted(Object source, FileSystemEventArgs e)
              {
                     if( servicePaused == false )
                     {
                            fileDeleteCounter.IncrementBy(1);
                     }
              }


  OnStop()函数便是中止Windows服务的,在该Windows服务中,服务一旦中止,全部的计数器的值都应归零,可是计数器并不提供一个Reset()方法,因此咱们只好将计数器中的值减去当前值来达到这个目的。


protected override void OnStop()
              {
                     if( fileChangeCounter.RawValue != 0 )
                     {
                            fileChangeCounter.IncrementBy(-fileChangeCounter.RawValue);
                     }
                     if( fileDeleteCounter.RawValue != 0 )
                     {
                            fileDeleteCounter.IncrementBy(-fileDeleteCounter.RawValue);
                     }
                     if( fileRenameCounter.RawValue != 0 )
                     {
                            fileRenameCounter.IncrementBy(-fileRenameCounter.RawValue);     
                     }
                     if( fileCreateCounter.RawValue != 0 )
                     {
                            fileCreateCounter.IncrementBy(-fileCreateCounter.RawValue);
                     }
              }


  同时,由于咱们的Windows服务是容许暂停并恢复的,因此咱们还得重载OnPause()函数和OnContinue()函数,方法很简单,只要设定前面定义的布尔值servicePaused便可。


protected override void OnPause()
              {
                     servicePaused = true;
              }
 
             protected override void OnContinue()
              {
                     servicePaused = false;
             }


  这样,该Windows服务的主体部分已经完成了,不过它并不有用,咱们还必须为其添加安装文件。安装文件为Windows服务的正确安装作好了工做,它包括了一个Windows服务的安装类,该类是重System.Configuration.Install.Installer继承过来的。安装类中包括了Windows服务运行所需的账号信息,用户名、密码信息以及Windows服务的名称,启动方式等信息。


[RunInstaller(true)]
       public class Installer1 : System.Configuration.Install.Installer
       {
              /// <summary>
              /// 必需的设计器变量。
              /// </summary>
              private System.ComponentModel.Container components = null;
              private System.ServiceProcess.ServiceProcessInstaller spInstaller;
              private System.ServiceProcess.ServiceInstaller sInstaller;
 
              public Installer1()
              {
                     // 该调用是设计器所必需的。
                     InitializeComponent();
 
                    // TODO: 在 InitComponent 调用后添加任何初始化
              }
 
              #region Component Designer generated code
              /// <summary>
              /// 设计器支持所需的方法 - 不要使用代码编辑器修改
              /// 此方法的内容。
              /// </summary>
             private void InitializeComponent()
              {
                     components = new System.ComponentModel.Container();
 
                     // 建立ServiceProcessInstaller对象和ServiceInstaller对象
                     this.spInstaller =
              new System.ServiceProcess.ServiceProcessInstaller();
                     this.sInstaller = new System.ServiceProcess.ServiceInstaller();
 
                     // 设定ServiceProcessInstaller对象的账号、用户名和密码等信息
                     this.spInstaller.Account =
              System.ServiceProcess.ServiceAccount.LocalSystem;
                     this.spInstaller.Username = null;
                     this.spInstaller.Password = null;
 
                    // 设定服务名称
                     this.sInstaller.ServiceName = "FileMonitorService";
 
                    // 设定服务的启动方式
                     this.sInstaller.StartType =
              System.ServiceProcess.ServiceStartMode.Automatic;
 
                     this.Installers.AddRange(
              new System.Configuration.Install.Installer[]
                {this.spInstaller, this.sInstaller });
              }
              #endregion
       }


  一样,由于该Windows服务中运用到了计数器对象,咱们也要为其添加相应的安装文件,安装文件的内容和做用与前面的相似。限于篇幅,这里就不给出相应的代码了,有兴趣的读者能够参考文后附带的源代码文件。

  到此为止,整个Windows服务已经构建完毕,不过Windows服务程序和通常的应用程序不一样,它不能直接调试运行。若是你直接在IDE下试图调试运行之,就会报出如图4所示提示。

  图4



  根据其中提示,咱们知道安装Windows服务须要用到一个名为InstallUtil.exe的命令行工具。而运用该工具安装Windows服务的方法是很是简单的,安装该Windows服务的命令以下:


installutil FileMonitorService.exe


  而要卸载该Windows服务,你只要输入以下的命令便可:


installutil /u FileMonitorService.exe


  Windows服务安装成功后,它便会出如今服务控制管理器中,如图5所示。

  图5



  这样,该文件监视的Windows服务就完成了,一旦咱们对被监视的目录中的文件进行操做,相应的计数器就会运做,起到监视文件变化的做用。不过这个功能对于通常的用户而言没多大意义,然而你能够在此基础上添加新的功能,好比构建一个后台的文件处理系统,一旦被监视的目录中的文件发生某种变化,Windows服务便对其进行特定的操做,而最终用户就没必要去关心后台处理程序是如何实现的了。

  四.总结:

  本文向你们介绍了Windows服务的一些基本概念和构建通常的Windows服务所需的方法,同时还向你们展现了一个具备文件监视功能的Windows服务程序。经过本文,读者应该能体会到构建Windows服务并非想象中的那么复杂,这主要还得归功于.Net框架为咱们所做的大量努力。同时,但愿你们能在本文给出的实例的基础上构建更加完善和更增强大的Windows服务程序。最后但愿本文对你们能有很多帮助。
(注:源代码文件为 Source.rar
相关文章
相关标签/搜索