Windows 服务应用程序介绍
Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这使服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。
创建 Windows 服务
当创建服务时,可以使用称作 Windows 服务的 Visual Studio .NET 项目模板。此模板引用适当的类和命名空间、设置从服务基类的继承并重写您可能要重写的几种方法,从而自动为您完成大部分工作。
若要创建功能性服务,必须至少:
- 设置 ServiceName 属性。
- 为服务应用程序创建必需的安装程序。
- 重写 OnStart 和 OnStop 方法并为其指定代码以自定义服务的行为方式。
在将安装程序添加到应用程序之后,下一步是创建安装项目,该项目将安装已编译的项目文件并运行安装服务所需的安装程序。若要创建完整的安装项目,您必须将服务项目的输出添加到该安装项目,然后添加自定义操作以安装您的服务。
- 创建一个 Windows 服务项目。
- 在“属性”窗口中,设置服务的 ServiceName 属性。 (注意 ServiceName 属性的值必须始终与安装程序类中记录的名称匹配。如果更改此属性,还必须更新安装程序类中的 ServiceName 属性。)
- 设置下列所有属性以确定服务的工作机制。
属性 设置 CanStop True 表示服务将接受停止运行的请求;false 表示禁止服务停止。 CanShutDown True 表示服务希望在运行它的计算机关闭时收到通知,以便能够调用 OnShutDown 过程。 CanPauseAndContinue True 表示服务将接受暂停或继续运行的请求;false 表示禁止服务暂停和继续。 CanHandlePowerEvent True 表示该服务可以处理有关计算机电源状态更改的通知;false 表示禁止服务得到有关这些更改的通知。 AutoLog True 表示在服务执行操作时将信息项写入应用程序的事件日志;false 表示禁用此功能。(注意 默认为 true。)
注意 当 CanStop 或 CanPauseandContinue 设置为 false 时,服务控制管理器将禁用停止、暂停或继续服务的相应菜单选项。
- 访问代码编辑器,并为 OnStart 和 OnStop 过程填写所需的处理。
- 重写其他所有要为其定义功能的方法。
- 添加服务应用程序所必需的安装程序。
- 通过从“生成”菜单中选择“生成解决方案”来生成项目。 (注意 不要通过按 F5 键来运行项目,不能以这种方式运行服务项目。)
实例:
新建一个名为MyService的Windows服务项目,将Service1.cs及代码里的类名改为你想要的名字,我这里统一用MyService;
using System.Threading;
一个后台服务线程,private Thread backThread=null;
在构造函数里实例化线程,this.backThread=new Thread(new ThreadStart(this.Running));
在类里添加private void Running(){}方法,一般要让线程一直处于运行状态来处理你给它安排的工作,例如根据消息队列里的消息,执行下载任务下载文件。
private void Running()
{
while(true)
{
//你的处理
Thread.Sleep(5*1000);//例如让线程休眠5秒
}
}
重写线程的控制函数
protected override void OnStart(string[] args)
{
this.backThread.Start();
}
protected override void OnStop()
{
this.backThread.Abort();
}
protected override void OnPause()
{
this.backThread.Suspend();
}
protected override void OnContinue()
{
this.backThread.Resume();
}
同时你也可以根据需要按照上面表格所列的属性进行设置。
在该项目上点右键选择添加-添加类-安装程序类,取名Install.cs
在Install.cs的视图设计器里为它添加ServiceInstall和ServiceProcessInstall控件,可以为这2个控件设置属性,例如可以在ServiceInstall的ServiceDependedOn属性里设置服务依赖。
生成解决方案,下面介绍如何安装服务
安装和卸载服务
手动安装服务
- 访问项目中的已编译可执行文件所在的目录。
- 用项目的输出作为参数,从命令行运行 InstallUtil.exe。在命令行中输入下列代码:
installutil yourproject.exe
手动卸载服务
- 用项目的输出作为参数,从命令行运行 InstallUtil.exe。在命令行中输入下列代码:
installutil /u yourproject.exe
调试 Windows 服务应用程序
由于服务必须从服务控制管理器的上下文中运行,而不是从 Visual Studio .NET 中运行,因此调试服务不像调试其他 Visual Studio 应用程序类型那样简单。若要调试服务,必须首先启动服务,然后将一个调试器附加到正在运行服务的进程中。然后可以使用 Visual Studio 的所有标准调试功能来调试应用程序。
警告 除非知道进程是什么,并且知道附加到进程或可能会取消进程所带来的后果,否则不要附加到进程。例如,如果附加到 WinLogon 进程,然后停止调试,系统就会暂停,因为没有 WinLogon,系统无法运行。
只能将调试器附加到正在运行的服务。附加进程会中断服务的当前运行;它并不真正终止或暂停服务的处理。也就是说,如果开始调试时服务正在运行,则在进行调试时,该服务从技术上说仍处于“已启动”状态,但它的处理已挂起。
附加到服务的进程使您能够调试大多数服务代码,但并非全部;例如,由于服务已经启动,因此不能用这种方法调试服务的 OnStart 方法中的代码,或调试用于加载服务的 Main 方法中的代码。解决此问题的一个方法是:在唯一作用是帮助调试的服务应用程序中创建一个临时服务。可以将两个服务都安装上,然后启动此“虚拟”服务加载服务进程。临时服务启动了进程后,就可以使用 Visual Studio .NET 中的“调试”菜单来附加到服务进程。
当附加该进程之后,可以设置断点并使用这些断点来调试代码。当退出用于附加到该进程的对话框时,实际上已处于调试模式。您可以使用服务控制管理器开始、停止、暂停和继续您的服务,因此命中已设置的断点。调试成功后,移除此“虚拟”服务。
注意 调试 OnStart 方法可能比较困难,因为 Windows 服务管理器将所有尝试启动服务的时间限制在 30 秒内。当调试 Windows 服务应用程序时,服务与“Windows 服务管理器”进行交互。“服务管理器”通过调用 OnStart 方法启动服务,然后花 30 秒时间等待 OnStart 方法返回。如果在这段时间内方法没有返回,管理器将显示一个服务无法启动的错误。如果在 OnStart 方法中放置一个断点并且在 30 秒内不通过该断点,则管理器不会启动服务。
调试服务
- 安装您的服务。
- 可从服务控制管理器、“服务器资源管理器”或代码启动服务。
- 在 Visual Studio 中,从“调试”菜单中选择“进程”。 出现“进程”对话框。
- 单击“显示系统进程”。
- 在“可用进程”区域内单击服务的进程,然后单击“附加”。 (提示 此进程将与服务的可执行文件同名。)出现“附加到进程”对话框。
- 选择任意适当选项,然后单击“确定”关闭对话框。 (注意 您现在已处于调试模式。)
- 设置要在代码中使用的任意断点。
- 访问服务控制管理器并操纵您的服务,并发送停止、暂停和继续命令以命中您的断点。
本人对Windows Service的理解还不是很透彻,欢迎和我讨论,共同学习。
用.NET创建Windows服务
用.NET创建Windows服务
译者说明:我是通过翻译来学习C#的,文中涉及到的有Visual Studio.NET有关操作,我都根据中文版的VS.NET显示信息来处理的,可以让大家不致有误解。
作者:Mark Strawmyer
我们将研究如何创建一个作为Windows服务的应用程序。内容包含什么是Windows服务,如何创建、安装和调试它们。会用到System.ServiceProcess.ServiceBase命名空间的类。
什么是Windows服务?
Windows服务应用程序是一种需要长期运行的应用程序,它对于服务器环境特别适合。它没有用户界面,并且也不会产生任何可视输出。任何用户消息都会被写进Windows事件日志。计算机启动时,服务会自动开始运行。它们不要用户一定登录才运行,它们能在包括这个系统内的任何用户环境下运行。通过服务控制管理器,Windows服务是可控的,可以终止、暂停及当需要时启动。
Windows 服务,以前的NT服务,都是被作为Windows NT操作系统的一部分引进来的。它们在Windows 9x及Windows Me下没有。你需要使用NT级别的操作系统来运行Windows服务,诸如:Windows NT、Windows 2000 Professional或Windows 2000 Server。举例而言,以Windows服务形式的产品有:Microsoft Exchange、SQL Server,还有别的如设置计算机时钟的Windows Time服务。
创建一个Windows服务
我们即将创建的这个服务除了演示什么也不做。服务被启动时会把一个条目信息登记到一个数据库当中来指明这个服务已经启动了。在服务运行期间,它会在指定的时间间隔内定期创建一个数据库项目记录。服务停止时会创建最后一条数据库记录。这个服务会自动向Windows应用程序日志当中登记下它成功启动或停止时的记录。
Visual Studio .NET能够使创建一个Windows服务变成相当简单的一件事情。启动我们的演示服务程序的说明概述如下。
1. 新建一个项目
2. 从一个可用的项目模板列表当中选择Windows服务
3. 设计器会以设计模式打开
4. 从工具箱的组件表当中拖动一个Timer对象到这个设计表面上 (注意: 要确保是从组件列表而不是从Windows窗体列表当中使用Timer)
5. 设置Timer属性,Enabled属性为False,Interval属性30000毫秒
6. 切换到代码视图页(按F7或在视图菜单当中选择代码),然后为这个服务填加功能
Windows服务的构成
在你类后面所包含的代码里,你会注意到你所创建的Windows服务扩充了System.ServiceProcess.Service类。所有以.NET方式建立的Windows服务必须扩充这个类。它会要求你的服务重载下面的方法,Visual Studio默认时包括了这些方法。
• Dispose – 清除任何受控和不受控资源(managed and unmanaged resources)
• OnStart – 控制服务启动
• OnStop – 控制服务停止
数据库表脚本样例
在这个例子中使用的数据库表是使用下面的T-SQL脚本创建的。我选择SQL Server数据库。你可以很容易修改这个例子让它在Access或任何你所选择的别的数据库下运行。
CREATE TABLE [dbo].[MyServiceLog] (
[in_LogId] [int] IDENTITY (1, 1) NOT NULL,
[vc_Status] [nvarchar] (40)
COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[dt_Created] [datetime] NOT NULL
) ON [PRIMARY]
Windows服务样例
下面就是我命名为MyService的Windows服务的所有源代码。大多数源代码是由Visual Studio自动生成的。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
namespace CodeGuru.MyWindowsService
{
public class MyService : System.ServiceProcess.ServiceBase
{
private System.Timers.Timer timer1;
/// <remarks>
/// Required designer variable.
/// </remarks>
private System.ComponentModel.Container components = null;
public MyService()
{
// This call is required by the Windows.Forms
// Component Designer.
InitializeComponent();
}
// The main entry point for the process
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[]
{ new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.timer1 = new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)
(this.timer1)).BeginInit();
//
// timer1
//
this.timer1.Interval = 30000;
this.timer1.Elapsed +=
new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// MyService
//
this.ServiceName = "My Sample Service";
((System.ComponentModel.ISupportInitialize)
(this.timer1)).EndInit();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
/// <summary>
/// Set things in motion so your service can do its work.
/// </summary>
protected override void OnStart(string[] args)
{
this.timer1.Enabled = true;
this.LogMessage("Service Started");
}
/// <summary>
/// Stop this service.
/// </summary>
protected override void OnStop()
{
this.timer1.Enabled = false;
this.LogMessage("Service Stopped");
}
/*
* Respond to the Elapsed event of the timer control
*/
private void timer1_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
this.LogMessage("Service Running");
}
/*
* Log specified message to database
*/
private void LogMessage(string Message)
{
SqlConnection connection = null;
SqlCommand command = null;
try
{
connection = new SqlConnection(
"Server=localhost;Database=SampleDatabase;Integrated
Security=false;User Id=sa;Password=;");
command = new SqlCommand(
"INSERT INTO MyServiceLog (vc_Status, dt_Created)
VALUES ('" + Message + "',getdate())", connection);
connection.Open();
int numrows = command.ExecuteNonQuery();
}
catch( Exception ex )
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
command.Dispose();
connection.Dispose();
}
}
}
}
安装Windows服务
Windows服务不同于普通Windows应用程序。不可能简简单单地通过运行一个EXE就启动Windows服务了。安装一个Windows服务应该通过使用.NET Framework提供的InstallUtil.exe来完成,或者通过诸如一个Microsoft Installer (MSI)这样的文件部署项目完成。
添加服务安装程序
创建一个Windows服务,仅用InstallUtil程序去安装这个服务是不够的。你必须还要把一个服务安装程序添加到你的Windows服务当中,这样便于InstallUtil或是任何别的安装程序知道应用你服务的是怎样的配置设置。
1. 将这个服务程序切换到设计视图
2. 右击设计视图选择“添加安装程序”
3. 切换到刚被添加的ProjectInstaller的设计视图
4. 设置serviceInstaller1组件的属性:
1) ServiceName = My Sample Service
2) StartType = Automatic
5. 设置serviceProcessInstaller1组件的属性
1) Account = LocalSystem
6. 生成解决方案
在完成上面的几个步骤之后,会自动由Visual Studio产生下面的源代码,它包含于ProjectInstaller.cs这个源文件内。
using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
namespace CodeGuru.MyWindowsService
{
/// <summary>
/// Summary description for ProjectInstaller.
/// </summary>
[RunInstaller(true)]
public class ProjectInstaller :
System.Configuration.Install.Installer
{
private System.ServiceProcess.ServiceProcessInstaller
serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public ProjectInstaller()
{
// This call is required by the Designer.
InitializeComponent();
// TODO: Add any initialization after the InitComponent call
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new
System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new
System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Account =
System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// serviceInstaller1
//
this.serviceInstaller1.ServiceName = "My Sample Service";
this.serviceInstaller1.StartType =
System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new
System.Configuration.Install.Installer[]
{this.serviceProcessInstaller1, this.serviceInstaller1});
}
#endregion
}
}
用InstallUtil安装Windows服务
现在这个服务已经生成,你需要把它安装好才能使用。下面操作会指导你安装你的新服务。
1. 打开Visual Studio .NET命令提示
2. 改变路径到你项目所在的bin/Debug文件夹位置(如果你以Release模式编译则在bin/Release文件夹)
3. 执行命令“InstallUtil.exe MyWindowsService.exe”注册这个服务,使它建立一个合适的注册项。
4. 右击桌面上“我的电脑”,选择“管理”就可以打计算机管理控制台
5. 在“服务和应用程序”里面的“服务”部分里,你可以发现你的Windows服务已经包含在服务列表当中了
6. 右击你的服务选择启动就可以启动你的服务了
在每次需要修改Windows服务时,这就会要求你卸载和重新安装这个服务。不过要注意在卸载这个服务前,最好确保服务管理控制台已经关闭,这会是一个很好的习惯。如果没有这样操作的话,你可能在卸载和重安装Windows服务时会遇到麻烦。仅卸载服务的话,可以执行相的InstallUtil命令用于注销服务,不过要在后面加一个/u命令开关。
调试Windows服务
从另外的角度度看,调试Windows服务绝不同于一个普通的应用程序。调试Windows服务要求的步骤更多。服务不能象你对普通应用程序做的那样,只要简单地在开发环境下执行就可以调试了。服务必须首先被安装和启动,这一点在前面部分我们已经做到了。为了便于跟踪调试代码,一旦服务被启动,你就要用Visual Studio把运行的进程附加进来(attach)。记住,对你的Windows服务做的任何修改都要对这个服务进行卸载和重安装。
附加正在运行的Windows服务
为了调试程序,有些附加Windows服务的操作说明。这些操作假定你已经安装了这个Windows服务并且它正在运行。
1. 用Visual Studio装载这个项目
2. 点击“调试”菜单
3. 点击“进程”菜单
4. 确保 显示系统进程 被选
5. 在 可用进程 列表中,把进程定位于你的可执行文件名称上点击选中它
6. 点击 附加 按钮
7. 点击 确定
8. 点击 关闭
9. 在timer1_Elapsed方法里设置一个断点,然后等它执行
总结
现在你应该对Windows服务是什么,以及如何创建、安装和调试它们有一个粗略的认识了。Windows服务的额处的功能你可以自行研究。这些功能包括暂停(OnPause)和恢复(OnContinue)的能力。暂停和恢复的能力在默认情况下没有被启用,要通过Windows服务属性来设置。
About the Author
Mark Strawmyer, MCSD, MCSE (NT4/W2K), MCDBA is a Senior Architect of .NET applications for large and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design and development of Microsoft-based solutions. You can reach Mark at mstrawmyer@crowechizek.com.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=6159
创建Windows Service
打开VS 2005,点击File->New->Project….,在创建工程向导中选择Windows service模板,如下图所示:
在工程名输入框中,输入TestService然后点击OK。VS为我们生成了最基本的代码,我们将Service的名称改为我们期望的名称,在solution explorer中右键点击vs自动生成的service文件“Service1.cs”,在弹出的菜单中选择Rename,输入“MyFirstService”,然后切换到设计视图,也就是在solution explorer中双击MyfirstService.cs,在Property Explorer中将ServiceName属性改为MyFirstService,这时一个可运行的windows service已经创建成功。我们添加一些代码来测试一下这个service,最简单的测试方式就是向windows event log里来添加一些消息以显示我们的Service的状态。
我们需要一个EventLog组件向windows log中添加信息,在solution explorer中双击MyfirstSerice文件切换到设计视图,将工具箱中的EventLog组件拖到设计视图中,我们保留EventLog组件的默认名称eventLog1。选中eventLog1,在property explorer中将Log属性选为Application,在Source属性中输入“MyFirstService”。接下来,我们在设计视图的空白处,右键点击,并选择View Code切换到代码视图,在OnStart和OnStop方法里输入代码实现日志写入,代码如下:
要运行这个service我们还要做下边的几个步骤:
1.为我们的Service添加Installer,右键点击设计视图,选择Add Installer,VS将会为我们添加ProjectInstaller.cs,并在ProjectInstaller中添加组件serviceInstaller1和serviceProcessInstaller1,现在我们来修改他们的属性来控制Service的安装和启动选项。在ProjectInstaller得设计视图中选中serviceProcessInstaller1,将它得Account属性选为LocalSystem,这样以这个帐号服务启动。如果你希望系统启动时自动启动服务得话,将serviceInstaller1的StartType的属性选为Automatic,如果手动启动的话,选为manaul。
2.安装service,我们要用到IntallUtil.exe这个程序,这个程序位于C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727。点击开始菜单,选择“运行”,在运行对话框中输入cmd,进入到命令行窗口,输入cd :/WINDOWS/Microsoft.NET/Framework/v2.0.50727,进入到这个目录,然后输入installutil F:/Programs/C#/TestService/TestService/bin/Debug/testserveice.exe, installutil后边的内容就是我们的工程生成的可执行程序的路径,情根据需要修改。
如果你给ServiceInstaller1的StartType设为Automatic的话,安装完服务,服务已经运行起来了,如果StartType是Manual的话,你需要手动启动。现在我们进入“服务”,要打开“服务”,请单击“开始”,指向“设置”,然后单击“控制面板”。依次单击“性能和维护”、“管理工具”,然后双击“服务”。在里边你应该能够看到我们制作的Service MyFirstService。在这里边,我们可以启动,关闭服务,还可以设置服务的启动类型。然后,我们看看服务有没有正确的写入日志,我们需要进入到事件查看器,要打开“事件查看器”,请单击“开始”,指向“设置”,然后单击“控制面板”。单击“性能和维护”,单击“管理工具”,然后双击“事件查看器”。如下图所示,我们的消息已经成功的写到了系统日志里了。
如果你不需要这个Service了,仍然使用InstallUtil这个程序来卸载,不过在InstallUtil后跟参数 –u,比如installutil –u F:/Programs/C#/TestService/TestService/bin/Debug/testserveice.exe。
Service的调试方法与普通的程序调试方法是不一样的。我来介绍一下。
1. Build你的项目
2. 设置断点,因为我们的Service非常的简单,没有什么执行逻辑,所以设置断点没有任何意义,大家可以自己写一些代码来实践。一般来说,我们服务里需要用到一个另外的线程来执行任务,你需要在线程的执行代码中来设置断点。
3. 安装service,我们前边有介绍如何安装。
4. 如果你的Service启动类型是手动(Manual),你需要到“服务”里启动你的Service。一般来说,如果你的service在开发阶段,我推荐你将Service的启动类型设置为Manual,这样便于调试,因为如果service在运行过程中,你将无法build工程。
5. 在VS中,从菜单中选择Debug->Attach Process….,将会出现下图:
里边列出了正在运行的进程,如果你找不到自己的service,请选中Show processes from all users。在Available processes列表中选中我们的service所在的进程TestService,然后点击Attach按钮,如果你设置的断点合理的话,那么,程序就会停在断点处,接下来你就可以进行调试了。
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
namespace TestService
{
public partial class MyFirstService : ServiceBase
{
public MyFirstService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
eventLog1.WriteEntry("Service start");
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
eventLog1.WriteEntry("Service stop");
}
}
}
原文链接:http://www.cnblogs.com/guanjinke/archive/2006/12/01/578399.html
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1497563
Visual C#中调用Windows服务初探
Windows服务是独立于登录用户而工作的Windows应用程序,它通常在计算机启动时开始执行,且常常连续执行,直到计算机关闭为止。像Exchange Server,IIS和杀毒软件等都使用这种方式,这样就可以独立于某一用户而且可以在任何用户登录前来运行,同时也可以服务于所有的进程,从而以一种服务的形式存在。
正因为Windows服务有着这么多的特性,因此,当需要一些特殊功能的时候就可以考虑使用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;同时在构造函数中对其进行初始化:
MainThread=new Thread(new ThreadStart(ThreadFunc)); MainThread.Priority=ThreadPriority.Lowest; |
这里把线程的优先级设到最低,这样不会耗用过多的系统性能。这个线程对象使用ThreadFunc作为线程函数,因此将这个线程函数补充完整:
public static void ThreadFunc() { int LastHour=DateTime.Now.Hour; while (true) { System.Threading.Thread.Sleep(60000); if (DateTime.Now.Hour-1==LastHour) { MessageBox.Show("为了爱护您的眼睛,请您暂时休息5分钟并向远处眺望!","警告",MessageBoxButtons.OK,MessageBoxIcon.Warning,MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); LastHour=DateTime.Now.Hour; } } } |
余下的代码就简单了,只要在OnStart中启动线程,在OnStop中停止线程就行了。
以上的服务程序虽然很简单,线程的处理上也不很恰当,也违背了很多服务程序的原则比如界面显示等,但对于本人的需求而言是足够了,因此就如此制作了。如果你有需要,当然可以把对话框改为其他的提醒方式如响铃等,线程也可以使用内核对象同时使用更好的处理方法。
Windows服务就做完了,余下的就是要测试了,但发现这个EXE无法运行,它会提示你该EXE需要使用安装程序来安装服务,看来不可能写一个程序就算是Windows服务了,还要把它注册到Windows才行。
接下来,右击CareEye.cs的设计视图,添加安装程序,(VS.NET想得就是挺周到的),这下又出来一批代码,不过好在不用改代码了,只要把Account的账户类型设成LocalSystem,把StartType设成手动启动就行了,这里用手动是为了方便调试,以后可以改成自动类型。
编译完后,还是无法运行,此处还需要一步,就是运行installutil来安装这个服务,其安装和卸载的用法为:
installutil CareEye.exe installutil /u CareEye.exe |
安装完后能过系统的服务管理器你就可以看到你的服务了,只要点击启动就可以把它启动,把时间向前改一个小时它就会提醒你需要休息了,呵呵,够简单了吧。
如果你想制作成安装包分发给自己的朋友,只需要再添加个部署项目就行了,不过为了完成自注册,要在自定义操作编辑器中的安装阶段添加一个自定义的安装操作,把InstallerClass属性设成TRUE即可。
余下的事情,就是自己动手试试吧,这回不用担心用眼超时了!