開發 Windows Service 專案並安裝後,發現「服務」管理工具 (services.msc) 中的「描述」欄位為空白,而系統內建服務皆有說明文字。ServiceBase 類別與 ProjectInstaller 均無直接提供「描述」屬性。
Windows 服務描述儲存於登錄機碼:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{ServiceName} 下的 Description 字串值。透過覆寫安裝程式類別的虛擬方法,在安裝時寫入、解除安裝時清理。
using System;
using System.Collections;
using System.Configuration.Install;
using System.ComponentModel;
using Microsoft.Win32;
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private ServiceInstaller serviceInstaller1;
private ServiceProcessInstaller serviceProcessInstaller1;
public ProjectInstaller()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
// 開啟服務登錄機碼
RegistryKey system = Registry.LocalMachine.OpenSubKey("SYSTEM");
RegistryKey currentControlSet = system.OpenSubKey("CurrentControlSet");
RegistryKey services = currentControlSet.OpenSubKey("Services");
RegistryKey service = services.OpenSubKey(serviceInstaller1.ServiceName, true); // 可寫入
// 寫入描述
service.SetValue("Description", "此服務負責處理訂單排程與通知發送");
// 可選:建立自訂子機碼
RegistryKey config = service.CreateSubKey("AdditionalInformation");
config.SetValue("Version", "1.0.0.0");
config.SetValue("Author", "Team Alpha");
config.Close();
service.Close();
}
catch (Exception ex)
{
// 記錄錯誤至事件日誌
System.Diagnostics.EventLog.WriteEntry("ServiceInstaller", ex.Message, System.Diagnostics.EventLogEntryType.Error);
}
}
public override void Uninstall(IDictionary savedState)
{
try
{
RegistryKey system = Registry.LocalMachine.OpenSubKey("SYSTEM");
RegistryKey currentControlSet = system.OpenSubKey("CurrentControlSet");
RegistryKey services = currentControlSet.OpenSubKey("Services");
RegistryKey service = services.OpenSubKey(serviceInstaller1.ServiceName, true);
// 移除自訂子機碼
service.DeleteSubKeyTree("AdditionalInformation");
service.Close();
}
catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry("ServiceInstaller", ex.Message, System.Diagnostics.EventLogEntryType.Error);
}
finally
{
base.Uninstall(savedState);
}
}
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new ServiceProcessInstaller();
this.serviceInstaller1 = new ServiceInstaller();
// 設定服務帳號、啟動類型、服務名稱等...
this.Installers.AddRange(new Installer[] { this.serviceProcessInstaller1, this.serviceInstaller1 });
}
}
| 步驟 | 說明 |
|---|---|
| 1. 繼承 Installer | 專案安裝類別需標記 [RunInstaller(true)] |
| 2. 覆寫 Install | 先呼叫 base.Install() 完成標準安裝,再操作登錄寫入 Description |
| 3. 覆寫 Uninstall | 清理自訂子機碼,最後呼叫 base.Uninstall() |
| 4. 登錄路徑 | HKLM\SYSTEM\CurrentControlSet\Services\{ServiceName} |
| 5. 權限需求 | 安裝程式需以系統管理員權限執行,才能寫入 HKLM |
ServiceInstaller.Description 屬性 (但僅限設計工具支援,程式碼仍需手動設定)。sc.exe description "ServiceName" "描述文字" 命令列工具在安裝後補充。雖然 .NET 基底類別庫未直接暴露服務描述屬性,但透過安裝程式覆寫登錄操作,即可輕鬆為 Windows 服務加上有意義的描述,提升維運可讀性。