Windows服务是独立于登录用户而工作的Windows应用程序它通常在计算机启动时开始执行且常常连续执行直到计算机关闭为止像Exchange ServerIIS和杀毒软件等都使用这种方式这样就可以独立于某一用户而且可以在任何用户登录前来运行同时也可以服务于所有的进程从而以一种服务的形式存在
正因为Windows服务有着这么多的特性因此当需要一些特殊功能的时候就可以考虑使用Windows服务来解决问题比如下面我们要做的这个例子对于我们这些程序设计人员计算机是在一起工作时间最长的伙伴每天都会对着它的屏幕八个小时以上还不包括下班后在家打游戏的时间因此保护眼睛是最重要的了问题的起因来源于本人周六去眼科对激光手术的复查大夫一再向我强调眼睛的自我调节能力就是说只要你能保证你每隔一个小时左右就闭眼休息或向远处眺望离开电脑屏幕那么已经治好的近视就不会反弹本人虽是自律性比较强的人但在计算机屏幕面前就不再如此了往往几个小时也不抬头一次为了眼睛的健康我决定把这个艰巨的任务交由计算机来完成让它在一小时左右自动提醒我休息五分钟如此一来岂不是再也不用顾虑这件事了
功能虽然简单但要写个程序放在启动组里每天自动运行也不是一个好的办法正巧以前也没做过Windows服务不如索性来试一试同进也看看NET为我们提供了多么先进的功能吧于是决定就用C#来做一个提醒我保护眼睛的Windows服务取名就叫CareEye吧
运行Visual StudioNET 建立一个C#的Windows服务项目在CareEyecs的设计视图提示可以把需要的控件和组件拖动到这上面假如想要做系统日志的话当然就可以把EventLog组件拖过来了不过这个程序好像不需要这些东西还是算了吧那么计时要不要采用计时器控件呢?想了一下这个控件虽然好用但太常用了本着学习新知识的原则最恰当的恐怕就是线程了而且在以后做其他Windows服务的时候线程肯定是必需的所以还是用线程好这样我只要在线程中完成对时间的监测把线程的启动和停止交给服务的启动和停止呵很方便啊
再来看CareEyecs的源程序一大堆没见过的东西不过仔细分析一下也就没什么了CareEye类派生于ServiceBase类因此继承了基本服务类的特性显然Main()方法会由SCM(服务控制管理程序)调用在这个方法中Run一个新的CareEye实例这样就运行了一个Windows服务OnStart()和OnStop()明显是用于启动和停止服务的响应函数了
注意在Main()方法中有一个ServiceBase[]的数组它是为那些一个服务进程包含多个服务准备的对于这个程序来说它只有一个CareEye服务因此完全可以把这个数组删除而只是使用SystemServiceProcessServiceBaseRun(new CareEye());一句就够了
接下来为了使用线程需要引入SystemThreading命名空间为了使用对话框还需要引入SystemWindowsForms命名空间这是为了将来提示用户时显示对话框而准备的
下面为类CareEye添加一个成员字段private Thread MainThread;同时在构造函数中对其进行初始化
MainThread=new Thread(new ThreadStart(ThreadFunc));
MainThreadPriority=ThreadPriorityLowest;
这里把线程的优先级设到最低这样不会耗用过多的系统性能这个线程对象使用ThreadFunc作为线程函数因此将这个线程函数补充完整
public static void ThreadFunc()
{
int LastHour=DateTimeNowHour;
while (true)
{
SystemThreadingThreadSleep();
if (DateTimeNowHour==LastHour)
{
MessageBoxShow(为了爱护您的眼睛请您暂时休息分钟并向远处眺望!警告MessageBoxButtonsOKMessageBoxIconWarningMessageBoxDefaultButtonButton
MessageBoxOptionsDefaultDesktopOnly);
LastHour=DateTimeNowHour;
}
}
}
余下的代码就简单了只要在OnStart中启动线程在OnStop中停止线程就行了
以上的服务程序虽然很简单线程的处理上也不很恰当也违背了很多服务程序的原则比如界面显示等但对于本人的需求而言是足够了因此就如此制作了如果你有需要当然可以把对话框改为其他的提醒方式如响铃等线程也可以使用内核对象同时使用更好的处理方法
Windows服务就做完了余下的就是要测试了但发现这个EXE无法运行它会提示你该EXE需要使用安装程序来安装服务看来不可能写一个程序就算是Windows服务了还要把它注册到Windows才行
接下来右击CareEyecs的设计视图添加安装程序(VSNET想得就是挺周到的)这下又出来一批代码不过好在不用改代码了只要把Account的账户类型设成LocalSystem把StartType设成手动启动就行了这里用手动是为了方便调试以后可以改成自动类型
编译完后还是无法运行此处还需要一步就是运行installutil来安装这个服务其安装和卸载的用法为
installutil CareEyeexe
installutil /u CareEyeexe
安装完后能过系统的服务管理器你就可以看到你的服务了只要点击启动就可以把它启动把时间向前改一个小时它就会提醒你需要休息了呵呵够简单了吧
如果你想制作成安装包分发给自己的朋友只需要再添加个部署项目就行了不过为了完成自注册要在自定义操作编辑器中的安装阶段添加一个自定义的安装操作把InstallerClass属性设成TRUE即可
以下是careeyecs的源程序:
using System;
using SystemCollections;
using SystemComponentModel;
using SystemData;
using SystemDiagnostics;
using SystemServiceProcess;
using SystemThreading;
using SystemWindowsForms;
namespace CareEye
{
public class CareEye : SystemServiceProcessServiceBase
{
private Thread MainThread;
/// <summary>
/// 必需的设计器变量
/// </summary>
private SystemComponentModelContainer components = null;
public CareEye()
{
// 该调用是 WindowsForms 组件设计器所必需的
InitializeComponent();
// TODO: 在 InitComponent 调用后添加任何初始化
MainThread=new Thread(new ThreadStart(ThreadFunc));
MainThreadPriority=ThreadPriorityLowest;
}
// 进程的主入口点
static void Main()
{
//SystemServiceProcessServiceBase[] ServicesToRun;
// 同一进程中可以运行多个用户服务若要将
//另一个服务添加到此进程请更改下行
// 以创建另一个服务对象例如
//
// ServicesToRun = New SystemServiceProcessServiceBase[] {new CareEye() new MySecondUserService()};
//
//ServicesToRun = new SystemServiceProcessServiceBase[] { new CareEye() };
SystemServiceProcessServiceBaseRun(new CareEye());
}
/// <summary>
/// 设计器支持所需的方法 不要使用代码编辑器
/// 修改此方法的内容
/// </summary>
private void InitializeComponent()
{
//
// CareEye
//
thisServiceName = CareEye;
}
/// <summary>
/// 清理所有正在使用的资源
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
componentsDispose();
}
}
baseDispose( disposing );
}
/// <summary>
/// 设置具体的操作以便服务可以执行它的工作
/// </summary>
protected override void OnStart(string[] args)
{
// TODO: 在此处添加代码以启动服务
MainThreadStart();
}
/// <summary>
/// 停止此服务
/// </summary>
protected override void OnStop()
{
// TODO: 在此处添加代码以执行停止服务所需的关闭操作
MainThreadAbort();
}
public static void ThreadFunc()
{
int LastHour=DateTimeNowHour;
while (true)
{
SystemThreadingThreadSleep();
if (DateTimeNowHour==LastHour)
{
MessageBoxShow(为了爱护您的眼睛请您暂时休息分钟并向远处眺望!警告MessageBoxButtonsOKMessageBoxIconWarningMessageBoxDefaultButtonButtonMessageBoxOptionsDefaultDesktopOnly);
LastHour=DateTimeNowHour;
}
}
}
}
}