最近在研究Windows Service
網路資料有些片段,寫個文章整理一下
主要目標很簡單,就是寫一個排程器
每隔幾秒做事情
放在伺服器上
—–
以下用visual studio 2012做示範
建立專案
一樣老樣子從開新專案開始
File -> New -> Project…
選Visual C# -> Windows -> Windows Service (中文叫做Windows服務)
然後打上專案名稱 (這裡用MyService1)
按下OK後建立
然後就建立專案
這裡可以發現這個Service的專案跟一般視窗專案有些不同
除了一樣有Program.cs
多了Service1.cs
點選Service1.cs在Design模式時,什麼都沒有(因為只有元件沒有畫面)
點選Click here to switch to code view直接看程式碼
這裡就有原始碼
只有很簡單的OnStart跟OnStop
因為它是服務,所以無法直接執行
直接按Start按鈕執行的話會看到這個視窗
意思是說,這服務需要被安裝才可以執行
需要用到 installutil.exe 這程式來安裝(等下再介紹)
然後還要用NET START指令啟動服務(這可以不用理會沒關係,我們可以用圖形介面)
———
到這裡還沒有開始寫排程器,還要爲這個服務做一些設定
回到Service1.cs的Design模式(就是剛剛什麼都沒有地方)
按右鍵 -> Add Installer (加入安裝程式)
這時會多一個ProjectInstaller.cs檔案,在設計模式底下會有這二個東西
點選 serviceInstaller1
這裡需要做一些設定
DisplayName 就是服務要顯示的名稱
Description 服務描述
ServiceName 服務的唯一名稱
StartType 啓動方式,初始值爲Manual (手動)
當然要設定Automatic (自動) 呀
DelayedAutoStart 爲開機之後是否延遲啓動
點選 serviceProcessInstaller1
設定只要改一個
Account 這裡決定服務的帳號與權限
我們可以設定爲LocalSystem (就是最大權限)
———
撰寫相關程式碼
先撰寫定時器
這裡用到 System.Timers 所以要先引用
using System.Timers;
然後寫一個定時器
private Timer MyTimer;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
MyTimer = new Timer();
MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
MyTimer.Interval = 10 * 1000;
MyTimer.Start();
}
private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
// Do SomeThing…
}
這裡設定 定時器為每10秒 執行一次
日誌輸出
在設計模式拉一個EventLog
然後增加一些程式碼變成如下
private Timer MyTimer;
public Service1()
{
InitializeComponent();
this.AutoLog = false;
if (!System.Diagnostics.EventLog.SourceExists(“MySource”))
{
System.Diagnostics.EventLog.CreateEventSource(
“MySource”, “MyLog”);
}
eventLog1.Source = “MySource”;
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry(“Start Timer.”);
MyTimer = new Timer();
MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
MyTimer.Interval = 10 * 1000;
MyTimer.Start();
}
private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
eventLog1.WriteEntry(“Timer Ticked.”);
}
protected override void OnStop()
{
eventLog1.WriteEntry(“Stop Timer.”);
MyTimer.Stop();
MyTimer = null;
}
剩下就讓大家自由發揮了
——————————
安裝 / 解除安裝 服務
剛剛不是有提到 installutil.exe 嗎?
官方文件是寫
安裝服務的時候執行指令
InstallUtil MyService1.exe
解除安裝的時候執行指令
InstallUtil /u MyService1.exe
但事情沒有這麼簡單
installutil.exe 它其實是在
C:WindowsMicrosoft.NETFramework<版本號> 底下
版本號會有很多個
因為我這個專案是用.Net Framework 4.5
所以就用v4.0.30319
有安裝.Net Framework 4.5都會有這個資料夾,也會有這個程式
但還有一個問題
因為我執行時是用LocalSystem
這個需要額外的管理員權限
——-
在這裡我寫了二個Bat檔案,做安裝服務與解除安裝的服務
這裡只列安裝服務,反正把指令加上 /u 就是 解除安裝就不列出了
Install-MyService1.bat
內容為
@ECHO OFF
net session >nul 2>&1
IF NOT %ERRORLEVEL% EQU 0 (
ECHO ERROR: Please run Bat as Administrator.
PAUSE
EXIT /B 1
)
@SETLOCAL enableextensions
@CD /d “%~dp0”
REM The following directory is for .NET 4
SET DOTNETFX4=%SystemRoot%Microsoft.NETFrameworkv4.0.30319
SET PATH=%PATH%;%DOTNETFX4%
ECHO Installing MyService1…
ECHO —————————————————
InstallUtil /i .MyService1.exe
ECHO —————————————————
ECHO Done.
PAUSE
藍色字自行修改所需要的.Net版本號
還有服務程式的exe名稱
橘色字是檢查管理員權限用的
若Account不是選LocalSystem的話
可以刪掉它
——————————
執行測試
完成之後可以做安裝,然後做測試
在Install-MyService1.bat按右鍵 -> Run as administrator
打開控制台 -> 系統管理工具 -> 服務
這個列表裡面就會多了一個你的服務
裡面的名稱都跟剛剛打的一樣
那我們剛剛寫的日誌呢?
控制台 -> 系統管理工具 -> 事件檢視器
找到Applications and Services (應用程式及服務記錄檔)
就會多出一個MyLog
裡面就是我們寫的日誌檔
除錯
之前在重複若干次的 安裝服務/解除安裝服務 的時候
有遇到EventLog的問題
可以嘗試去登錄編輯器(regedit)刪除以下機碼
HKEY_LOCAL_MACHINESYSTEMControlSet001serviceseventlogMySource
HKEY_LOCAL_MACHINESYSTEMControlSet001servicesMySource
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetserviceseventlogMySource
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesMySource
在執行 解除安裝服務 的程式
參考資料:
http://blog.wahahajk.com/2008/06/cservice.html
http://msdn.microsoft.com/en-us/library/y817hyb6(v=vs.110).aspx
http://gogo1119.pixnet.net/blog/post/27575780-%5Bc%23%5D-windows-service%E5%BB%BA%E7%AB%8B%E7%AF%84%E4%BE%8B
http://www.cnblogs.com/xianspace/archive/2009/04/05/1429835.html
http://stackoverflow.com/questions/3307151/receiving-has-already-been-registered-from-eventlog-createeventsource-ev
http://stackoverflow.com/questions/4824051/problem-installing-windows-service