Windows Service的安裝卸載 和 Service控制


作者:Peter
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.


本文內容包括如何通過C#代碼安裝Windows Service(exe文件,並非打包後的安裝文件)、判斷Service是否存在、獲得Service狀態及啓動停止Service。

  創建Windows Service項目並Build得到exe文件,如何創建 Service 可參考 創建windows service 並打包成安裝文件

一、 Windows服務的安裝和卸載

  安裝和卸載服務可以使用 .NET 工具installutil.exe (eg:安裝-> installutil xxx.exe 卸載-> installutil /u xxx.exe),使用ManagedInstallerClass可以實現安裝卸載Windows 服務,ManagedInstallerClass 在System.Configuration.Install命名空間下。

  實現如下:

複製代碼
 1         /// <summary>
 2         /// 使用Windows Service對應的exe文件 安裝Service
 3         /// 和 installutil xxx.exe 效果相同
 4         /// </summary>
 5         /// <param name="installFile">exe文件(包含路徑)</param>
 6         /// <returns>是否安裝成功</returns>
 7         public static bool InstallServie(string installFile)
 8         {
 9             string[] args = { installFile };
10             try
11             {
12                 ManagedInstallerClass.InstallHelper(args);
13                 return true;
14             }
15             catch
16             {
17                 return false;
18             }
19         }
20 
21         /// <summary>
22         /// 使用Windows Service對應的exe文件 卸載Service
23         /// 和 installutil /u xxx.exe 效果相同
24         /// </summary>
25         /// <param name="installFile">exe文件(包含路徑)</param>
26         /// <returns>是否卸載成功</returns>
27         public static bool UninstallService(string installFile)
28         {
29             string[] args = { "/u", installFile };
30             try
31             {
32                 // 根據文件獲得服務名,假設exe文件名和服務名相同
33                 string tmp = installFile;
34                 if (tmp.IndexOf('\\') != -1)
35                 {
36                     tmp = tmp.Substring(tmp.LastIndexOf('\\') + 1);
37                 }
38                 string svcName = tmp.Substring(0, tmp.LastIndexOf('.'));
39                 // 在卸載服務之前 要先停止windows服務
40                 StopService(svcName);
41 
42                 ManagedInstallerClass.InstallHelper(args);
43                 return true;
44             }
45             catch
46             {
47                 return false;
48             }
49         }
複製代碼

  注意: 服務刪除前需要先停止服務,否則服務被標記爲禁用,並無法刪除。原因:系統刪除服務時,首先是標記服務爲“刪除”,等待服務的所有引用完全斷開後,服務才被完全刪除。當服務引用未完全斷開時,就刪除服務,系統將服務鎖死爲“禁用”狀態,並禁止其他操作,注意此時服務尚未完全刪除。所以對已刪除後立即重裝的服務,需要完全釋放與服務相關的所有引用,此時系統才真正完全刪除服務,之後才能再次安裝服務。如果出現服務禁用問題,檢查代碼,哪些地方有服務引用,同時檢查是否其他程序還在引用,也要終止這些引用程序。

二、Windows服務的狀態獲取和控制

  使用ServiceController來獲取服務狀態或對服務進行控制。

  ServiceController 表示 Windows 服務並允許連接到正在運行或者已停止的服務、對其進行操作或獲取有關它的信息。使用 ServiceController 類連接到現有服務並控制其行爲。當創建 ServiceController 類的實例時,設置其屬性,以便它與特定的 Windows 服務交互作用。然後可以使用此類來啓動、停止和以其他方式操作該服務創建實例後,必須爲其設置兩個屬性來標識與其交互的服務:計算機名稱和要控制的服務的名稱。默認情況下,MachineName 設置爲本地計算機,因此不需要更改它,除非想將該實例設置爲指向另一臺計算機。

  服務可以處理的命令集取決於該服務的屬性;例如,可以將服務的 CanStop 屬性設置爲 false。該設置使 Stop 命令在那個特定的服務上不可用;它禁用了必要的按鈕,使您無法從 SCM 中停止服務。如果試圖通過代碼停止服務,系統將引發錯誤,並顯示錯誤信息“未能停止 servicename”。

常用操作如下:

  1.  獲得Service對應的ServiceController實例

複製代碼
 1         /// <summary>
 2         /// 獲得service對應的ServiceController對象
 3         /// </summary>
 4         /// <param name="serviceName">服務名</param>
 5         /// <returns>ServiceController對象,若沒有該服務,則返回null</returns>
 6         public static ServiceController GetService(string serviceName)
 7         {
 8             ServiceController[] services = ServiceController.GetServices();
 9             foreach (ServiceController s in services)
10             {
11                 if (s.ServiceName == serviceName)
12                 {
13                     return s;
14                 }
15             }
16             return null;
17         }
複製代碼

  2.  檢查指定的服務是否存在

複製代碼
 1         /// <summary>  
 2         /// 檢查指定的服務是否存在。  
 3         /// </summary>  
 4         /// <param name="serviceName">要查找的服務名字</param>  
 5         /// <returns>是否存在</returns>  
 6         public static bool ServiceExisted(string serviceName)
 7         {
 8             if (GetService(serviceName) == null)
 9             {
10                 return false;
11             }
12             else
13             {
14                 return true;
15             }
16         }
複製代碼

  3. 獲得服務詳細信息

複製代碼
 1         /// <summary>
 2         /// 獲得Service的詳細信息
 3         /// </summary>
 4         /// <param name="serviceName">服務名</param>
 5         /// <returns>Service信息,保存在string中</returns>
 6         public static string GetServiceInfo(string serviceName)
 7         {
 8             StringBuilder details = new StringBuilder();
 9 
10             ServiceController sc = GetService(serviceName);
11 
12             if (sc == null)
13             {
14                 return string.Format("{0} 不存在!", serviceName);
15             }
16 
17             details.AppendLine(string.Format("服務標識的名稱: {0}", sc.ServiceName));
18             details.AppendLine(string.Format("服務友好名稱:{0}", sc.DisplayName));
19             details.AppendLine(string.Format("服務在啓動後是否可以停止: {0}", sc.CanStop));
20             details.AppendLine(string.Format("服務所駐留的計算機的名稱: {0}", sc.MachineName)); // "." 表示本地計算機
21             details.AppendLine(string.Format("服務類型: {0}", sc.ServiceType.ToString()));
22             details.AppendLine(string.Format("服務狀態: {0}", sc.Status.ToString()));
23 
24             // DependentServices 獲取依賴於與此 ServiceController 實例關聯的服務的服務集。
25             StringBuilder dependentServices = new StringBuilder();
26             foreach (ServiceController s in sc.DependentServices)
27             {
28                 dependentServices.Append(s.ServiceName + ", ");
29             }
30             details.AppendLine(string.Format("依賴於與此 ServiceController 實例關聯的服務的服務: {0}", dependentServices.ToString()));
31             
32             // ServicesDependedOn 此服務所依賴的服務集。
33             StringBuilder serviceDependedOn = new StringBuilder();
34             foreach (ServiceController s in sc.ServicesDependedOn)
35             {
36                 serviceDependedOn.Append(s.ServiceName + ", ");
37             }
38             details.AppendLine(string.Format("此服務所依賴的服務: {0}", serviceDependedOn.ToString()));
39 
40             return details.ToString();
41         }
複製代碼

  4.  啓動服務

複製代碼
 1         /// <summary>
 2         /// 啓動服務
 3         /// </summary>
 4         /// <param name="serviceName">服務名</param>
 5         /// <returns>是否啓動成功</returns>
 6         public static bool StartService(string serviceName)
 7         {
 8             ServiceController sc = GetService(serviceName);
 9 
10             if (sc.Status != ServiceControllerStatus.Running)
11             {
12                 try
13                 {
14                     sc.Start();
15                     sc.WaitForStatus(ServiceControllerStatus.Running);  // 等待服務達到指定狀態
16                 }
17                 catch
18                 {
19                     return false;
20                 }
21             }
22 
23             return true;
24         }
複製代碼

  5.  停止服務

複製代碼
 1         /// <summary>
 2         /// 停止服務
 3         /// </summary>
 4         /// <param name="serviceName">服務名</param>
 5         /// <returns>是否停止服務成功,如果服務啓動後不可以停止,則拋異常</returns>
 6         public static bool StopService(string serviceName)
 7         {
 8             ServiceController sc = GetService(serviceName);
 9 
10             if (!sc.CanStop)
11             {
12                 throw new Exception(string.Format("服務{0}啓動後不可以停止.", serviceName));
13             }
14 
15             if (sc.Status != ServiceControllerStatus.Stopped)
16             {
17                 try
18                 {
19                     sc.Stop();
20                     sc.WaitForStatus(ServiceControllerStatus.Stopped);  // 等待服務達到指定狀態
21                 }
22                 catch
23                 {
24                     return false;
25                 }
26             }
27 
28             return true;
29         }
複製代碼


作者:Peter
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章