Windows系統服務編程


1. 簡介

Windows系統服務是一個不需要用戶登入就可以一直在后台運行的服務程序,

通過服務管理控制器(Service Control Manager, SCM)可以操作系統服務啟動、停止、自動運行等。

 

服務管理控制器(Service Control Manager, SCM) 維護着操作系統所有已安裝的服務,

里面有關於服務是如何啟動等信息,具有以下功能。

(1)在服務數據庫中維護系統已安裝的所有服務

(2)以自啟動或手動的方式啟動系統服務

(3)枚舉所有已安裝的服務

(4)維護服務的狀態

(5)向運行的服務傳輸控制請求信息

(6)加鎖或解鎖服務數據庫

 

2. 服務管理控制器數據庫

在注冊表中點擊以下路徑查看所有服務

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

 

 

2.1 OpenSCManager 打開SCM數據庫

在操作服務管理數據庫時,必須使用函數 OpenSCManager 打開數據庫,獲得句柄。

SC_HANDLE WINAPI OpenSCManager(
  _In_opt_ LPCTSTR lpMachineName,  /* 目標機器名稱,NULL為本地機器 */
  _In_opt_ LPCTSTR lpDatabaseName, /* 值一般為 SERVICES_ACTIVE_DATABASE */
  _In_     DWORD   dwDesiredAccess /* 特定權限訪問服務數據庫 */
);

 

API 參考鏈接  https://msdn.microsoft.com/en-us/library/windows/desktop/ms684323(v=vs.85).aspx

 

2.2 CreateService 創建服務

系統服務的名字由 CreateService 函數定義,原型如下

此函數功能: 創建一個名為 lpServiceName 的服務對象,並且安裝到服務控制管理器數據庫中。

返回特定的已安裝的服務對象句柄。

/* 成功返回SC_HANDLE類型的句柄,失敗返回NULL */
SC_HANDLE WINAPI CreateService( _In_ SC_HANDLE hSCManager, /* SCM數據庫句柄對象,由 OpenSCManager函數返回 */ _In_ LPCTSTR lpServiceName, /* 安裝服務的名稱 */ _In_opt_ LPCTSTR lpDisplayName, /* 對用戶顯示的名稱 */ _In_ DWORD dwDesiredAccess, /* 訪問進程 */ _In_ DWORD dwServiceType, /* 服務類型 */ _In_ DWORD dwStartType, /* 服務啟動選項 */ _In_ DWORD dwErrorControl, /* 錯誤等級 */ _In_opt_ LPCTSTR lpBinaryPathName, /* exe文件路徑 */ _In_opt_ LPCTSTR lpLoadOrderGroup, /* 加載順序 */ _Out_opt_ LPDWORD lpdwTagId, /* */ _In_opt_ LPCTSTR lpDependencies, _In_opt_ LPCTSTR lpServiceStartName, /* 服務應該在哪個用戶下運行 DomainName/UserName */ _In_opt_ LPCTSTR lpPassword /* 用戶密碼 */ );

 

CreateService 接口示例代碼 參考鏈接

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682450(v=vs.85).aspx

 

 

2.3 StartService 啟動服務

服務配置管理器對服務的啟動步驟如下

(1) 在 ServiceGroupOrder 列表中的系統將先啟動。

(2) 在ServiceOrderList列表中的值也會啟動

(3) 啟動對於依賴的服務

 

當服務啟動后,SCM執行以下步驟

(1)在數據庫中獲取用戶賬戶信息

(2)登錄服務賬戶

(3)加載用戶信息

(4)創建一個掛起的服務

(5)分配登錄口令給進程

(6)允許進程運行

開啟服務由 StartService 函數定義

 

StartService 函數參考文檔

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686321(v=vs.85).aspx

 

每個服務項都會記錄相關信息 (ChangeServiceConfig 函數來修改記錄)

* 服務名稱

* 啟動類型

* 服務狀態 (SetServiceStatus 函數更新狀態)

* 指向依賴服務的列表

 

CloseServiceHandle 函數關閉服務對象句柄

 

3. 服務程序

服務程是運行一個或多個系統服務的可執行代碼。

 

3.1 服務程序入口

主函數的服務程序會調用 StartServiceDispatcher 函數連接SCM數據庫並且啟動dispatcher純程。

dispacher線程循環等待 dispach 表中的請求控制。

當所有服務都結束時,SCM會發送一個控制請求通知dispacher線程退出。

然后 StartServiceDispacher 函數會退出

 

StartServiceCtrlDispatcher 使用 SERVICE_TABLE_ENTRY 結構來作為參數。

每個結構都指明了服務名稱與服務入口函數

 

3.2 服務入口函數

服務入口函數會做以下事情

1. 初始化全局變量

2. 調用 RegisterServiceCtrlHandler 函數注冊一個句柄來控制服務。

3. 執行初始化。

 

3.3 服務主函數

 

3.3 服務控制接收函數

每一個服務都有控制接收函數,一個服務調用 RegisterServiceCrtlHandler 函數注冊服務控制器接收函數。

當服務控制器接收函數調用后,服務必須調用 SetServiceStatus 函數通知 SCM 服務狀態是否改變。

服務器控制函數必須在30s內返回,否則SCM返回Error錯誤信息。

如果一個服務收到 SERVICE_CONTROL_STOP 控制代碼,必須停止接收控制請求,進入 SERVICE_STOP_PENDING 或 SERVICE_STOPPED 狀態。

如果用戶關閉系統,則狀態碼會是 SERVICE_ACCEPT_PRESHUTDOWN, 則調用 SetServiceStatus進入 SERVICE_CONTROL_PRESHUTDOWN 狀態。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM