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 状态。

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号