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