From: 011netservice@gmail.com
Date: 2022-04-24

本文示範以 Visual Studio 2015, .Net 4.6, C# 建立 Windows Service 服務程式, 其他版本可參考引用.
範例程式可自 VS2015Pratice 取得.
舊版vs2008可自 文件 程式 取得.

目錄:
  1. 建立步驟
  2. 安裝服務
  3. 測試
  4. 常見問題

建立步驟

依照以下步驟, 建立一個 Windows 服務程式 WinService1.exe:

1. 建立新專案

在 Visual Studio 2015 中開新專案: Name=WinService1, Templates=Windows Service, .NET Framework 4.6.
注意專案名稱不可與 .NET 既有的 NameSpace 衝突. 例如, 若專案名稱為"ServiceBase", 則會與 System.ServiceProcess.ServiceBase 衝突, 導致專案無法載入.
img

新增的專案會自動建立 Program.cs, 程式碼如下. 主要是將專案中, 自動建立的 Service1 物件, 傳入 System.ServiceProcess.ServiceBase.Run() 所需的 ServiceBase[] 陣列執行.
img

專案中會自動建立 Serice1.cs 屬性如下.注意屬性 ServiceName 就是在 Windows 服務中顯示的名稱, 最好是跟專案的 namespace 一致, 比較不會混淆.
img

Service1.cs 預設程式碼如下, 只有框架, 沒有內容. 預設只有 OnStart() 跟 OnStop() 兩個事件處理. OnStart() 是在服務啟動時呼叫, OnStop() 是在服務停止時呼叫.
其他的事件介面, 例如 OnPause(暫停時) 及 OnContinue(繼續執行時) 兩個事件介面, 可以 override 的方式增加, 並且要把 Service1 物件中, 屬性 CanPauseAndContinue 改為 True 才能執行.
img

3. 修改 Service1.cs

在 Service1.cs 中撰寫服務要執行的工作內容, 例如以下的測試程式碼: (寫入 EventLog, File 以及 錯誤處理)
img

4. 新增安裝元件 (Add Installer)

Windows Service 的程式無法直接執行, 必須安裝在 Windows 服務中才能啟動執行.
因此程式必須增加安裝元件, 才能被安裝在 Windows 服務中, 方法如下:
在 Service1.cs 元件上按滑鼠右鍵選單, 選擇"Add Installer":
img

執行後會新增 ProjectInstaller.cs 內含2個元件:
serviceProcessInstaller1
serviceInstaller1
img

元件 serviceProcessInstaller1 預設屬性如下:
img

元件 serviceInstaller1 預設屬性如下:
img

5. 調整元件 serviceProcessInstaller1

serviceProcessInstaller1:
Account 屬性, 在服務執行的時候, 注意必須要擁有處理資源的權限.
Name: serviceProcessInstaller1
Accout: LocalSystem (必須擁有存取資源的權限, 才可正確執行!)
GenerateMember: True
HelpText: 空白
Modifiers: Internal
Parent: ProjectInstaller
img

6. 調整元件 serviceInstaller1

Name: serviceInstaller1
DelayedAutoStart: False
Description: 空白. (顯示在Windows 服務中的 描述欄位)
DisplayName: 空白. (顯示在Windows 服務中的 名稱欄位. 若為空白, 則以屬性 ServiceName 顯示)
GenerateMember: True
HelpText: 空白
Modifiers: Internal
Parent: ProjectInstaller
注意應與 Service1.cs 的 ServiceName 名稱一致. NameSpace就是在 Windows 服務中顯示的名稱, 最好是跟專案的 namespace 一致, 比較不會混淆.
ServiceName: WinService1. 注意應與 Service1.cs 的 ServiceName 名稱一致. 這欄位是 EventLog() 的來源欄位依據.
ServicesDependedOn: String[] Array
StartType: Manual. (啟動類型為手動或自動).
img

7. 增加自我安裝服務功能

若程式提供自我安裝的功能, 就不需要透過工具程式安裝服務, 可由程式本身自我安裝服務.
方法是將 Program.cs 改寫成可接收參數 "/i"安裝 或是 "/u"解除安裝, 交由 SelfInstall() 處理如下:
img

8. 編譯程式

編譯成功後, 可產生.exe的服務程式. 例如本文之 WinService1.exe.

安裝服務

Windows Service 的程式無法直接執行, 必須安裝在 Windows 服務中才能啟動執行. 安裝步驟如下:

1. 確認執行服務程式的目錄

將編譯完成的服務程式, 複製到預定執行服務的目錄中.
例如: 本文將編譯成功的 WinService1.exe 複製到 C:\work\ 中.

2. 安裝與解除服務

注意安裝時, 必須擁有系統管理員權限. 在服務啟動執行時, 必須擁有存取資源的權限, 才可正確執行!

若是透過工具程式安裝服務, 工具程式 InstallUtil.exe 檔案位置在
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\ 或
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ 中.
指令格式為:
安裝: InstallUtil [program.exe]
解除安裝: InstallUtil /u [program.exe]
例如:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe c:\work\WinService1.exe
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /u c:\work\WinService1.exe

若是由程式自我安裝, 以本文為例, 指令為
安裝: c:\work\WinService1 /i
解除安裝: c:\work\WinService1 /u

如果服務程式已經不存在, 但是在 Windows 服務清單還存在的話, 則無法以上述的方法解除服務, 必須以 sc.exe 工具程式, 刪除在註冊機碼中的服務名稱.
例如:
sc delete WinService1.
sc.exe 工具程式可執行較多的服務管理功能, 詳Windows Commands.

安裝成功後, 可用 services.msc 指令在 Windows 服務清單中, 看到安裝成功的 WinService1 項目:
img

WinService1 的可執行檔位置為: "C:\work\WinService1.exe"
img

安裝記錄參考如下.
使用工具程式 InstallUtil.exe 安裝服務:
img

使用工具程式 InstallUtil.exe 解除服務:
img

使用程式自我安裝服務:
img

使用程式自我解除服務:
img

測試

1. 啟動服務

在 Windows Service 中選擇 WinService1 服務後, 按滑鼠右鍵, 選擇啟動:
img

啟動服務後, 檢查 c:\temp\myProjectID-OnStart.txt 檔案中, 應寫入一列字串, 格式為"專案代號-OnStart, 啟動時間".

2. 停止服務

在 Windows Service 中選擇 WinService1 服務後, 按滑鼠右鍵, 選擇停止:
img

啟動服務後, 檢查 c:\temp\myProjectID-OnStop.txt 檔案中, 應寫入一列字串, 格式為"專案代號-OnStop, 啟動時間".

3. 以指令方式啟動或停止服務

也可以指令的方式啟動或停止服務. 例如:
net start WinService1 | 啟動服務.
net stop WinService1 | 停止服務.

或是使用工具程式 sc.exe (Service Control), 啟動、停止或刪除服務:
sc delete "ServiceName"| 刪除服務 Deletes a service from the registry.
sc start "ServiceName"| 啟動服務
sc stop "ServiceName"| 停止服務
sc.exe 工具程式可執行更多的服務管理功能, 詳Windows Commands.

把指令存檔為 .bat 或 .cmd 檔案, 再搭配 Task Scheduler 設定為定期執行, 就是一個簡單的排程服務功能了.

以 net 指令啟動及停止服務:
img

以 sc.exe 工具程式啟動及停止服務:
img

4. 測試結果

若測試成功, 則會在啟動服務時, 將(專案代號=myProjectID, 執行時間)寫入檔案 myProjectID-OnStart.txt; 在服務停止時, 寫入檔案 myProjectID-OnStop.txt 中.
img

常見問題

1. 如何排程服務?

除了將啟動服務指令檔, 利用 Task Scheduler 定期執行以外, 也可以將 OnStart 事件改寫成如下, 利用 timer 定期執行服務:
img

由於 OnStart 事件改寫後, 不會結束, 因此在工作管理員的背景處理程序清單中, 可以找到持續執行中服務項目: WinServiceTimer, 每分鐘會寫入一列字串到 c:\temp\TimerService-OnStart.txt 檔案中.
img

2. 如何除錯?

除錯方式同先前介紹的方法, 只是使用不同的 Visual Studio 版本. 請參考舊版文件之 如何Debug Windows service程式? 章節說明.

Code In Fun