Windows服務是獨立於登錄用戶而工作的Windows應用程序
它通常在計算機啟動時開始執行
且常常連續執行
直到計算機關閉為止
像Exchange Server
IIS和殺毒軟件等都使用這種方式
這樣就可以獨立於某一用戶而且可以在任何用戶登錄前來運行
同時也可以服務於所有的進程
從而以一種服務的形式存在
正因為Windows服務有著這麼多的特性
因此
當需要一些特殊功能的時候就可以考慮使用Windows服務來解決問題
比如下面我們要做的這個例子
對於我們這些程序設計人員
計算機是在一起工作時間最長的伙伴
每天都會對著它的屏幕八個小時以上
還不包括下班後在家打游戲的時間
因此
保護眼睛是最重要的了
問題的起因來源於本人周六去眼科對激光手術的復查
大夫一再向我強調眼睛的自我調節能力
就是說只要你能保證你每隔一個小時左右就閉眼休息或向遠處眺望
離開電腦屏幕
那麼已經治好的近視就不會反彈
本人雖是自律性比較強的人
但在計算機屏幕面前就不再如此了
往往幾個小時也不抬頭一次
為了眼睛的健康
我決定把這個艱巨的任務交由計算機來完成
讓它在一小時左右自動提醒我休息五分鐘
如此一來
豈不是再也不用顧慮這件事了
功能雖然簡單
但要寫個程序放在啟動組裡每天自動運行也不是一個好的辦法
正巧以前也沒做過Windows服務
不如索性來試一試
同進也看看
NET為我們提供了多麼先進的功能吧
於是決定
就用C#來做一個提醒我保護眼睛的Windows服務
取名就叫CareEye吧
運行Visual Studio
NET
建立一個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(
);
if (DateTime
Now
Hour
==LastHour)
{
MessageBox
Show(
為了愛護您的眼睛
請您暫時休息
分鐘並向遠處眺望!
警告
MessageBoxButtons
OK
MessageBoxIcon
Warning
MessageBoxDefaultButton
Button
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即可
以下是careeye
cs的源程序:
using System;
using System
Collections;
using System
ComponentModel;
using System
Data;
using System
Diagnostics;
using System
ServiceProcess;
using System
Threading;
using System
Windows
Forms;
namespace CareEye
{
public class CareEye : System
ServiceProcess
ServiceBase
{
private Thread MainThread;
/// <summary>
/// 必需的設計器變量
/// </summary>
private System
ComponentModel
Container components = null;
public CareEye()
{
// 該調用是 Windows
Forms 組件設計器所必需的
InitializeComponent();
// TODO: 在 InitComponent 調用後添加任何初始化
MainThread=new Thread(new ThreadStart(ThreadFunc));
MainThread
Priority=ThreadPriority
Lowest;
}
// 進程的主入口點
static void Main()
{
//System
ServiceProcess
ServiceBase[] ServicesToRun;
// 同一進程中可以運行多個用戶服務
若要將
//另一個服務添加到此進程
請更改下行
// 以創建另一個服務對象
例如
//
// ServicesToRun = New System
ServiceProcess
ServiceBase[] {new CareEye()
new MySecondUserService()};
//
//ServicesToRun = new System
ServiceProcess
ServiceBase[] { new CareEye() };
System
ServiceProcess
ServiceBase
Run(new CareEye());
}
/// <summary>
/// 設計器支持所需的方法
不要使用代碼編輯器
/// 修改此方法的內容
/// </summary>
private void InitializeComponent()
{
//
// CareEye
//
this
ServiceName =
CareEye
;
}
/// <summary>
/// 清理所有正在使用的資源
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components
Dispose();
}
}
base
Dispose( disposing );
}
/// <summary>
/// 設置具體的操作
以便服務可以執行它的工作
/// </summary>
protected override void OnStart(string[] args)
{
// TODO: 在此處添加代碼以啟動服務
MainThread
Start();
}
/// <summary>
/// 停止此服務
/// </summary>
protected override void OnStop()
{
// TODO: 在此處添加代碼以執行停止服務所需的關閉操作
MainThread
Abort();
}
public static void ThreadFunc()
{
int LastHour=DateTime
Now
Hour;
while (true)
{
System
Threading
Thread
Sleep(
);
if (DateTime
Now
Hour
==LastHour)
{
MessageBox
Show(
為了愛護您的眼睛
請您暫時休息
分鐘並向遠處眺望!
警告
MessageBoxButtons
OK
MessageBoxIcon
Warning
MessageBoxDefaultButton
Button
MessageBoxOptions
DefaultDesktopOnly);
LastHour=DateTime
Now
Hour;
}
}
}
}
}
From:http://tw.wingwit.com/Article/program/net/201311/12658.html