[Win32] 服务程序开发(1)基本概念和服务程序的框架

来源:互联网 发布:阿里云os电视软件下载 编辑:程序博客网 时间:2024/05/24 06:49

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/47604179

一。服务程序基本概念

在Windows中,有一个特殊的群体,他们天生拥有极高的权限,在一些特殊用户,比如“SYSTEM”的用户中工作。他们享受很高的优待。很多系统功能(更新服务,触摸屏服务。。。)都是以服务运行的。应用程序也可以安装控制自己的服务(使用服务管理器API,以后会讲)。下面,让我们看看如何编写一个Win32服务。

图:系统中安装的服务

二。服务程序的编写框架

1。StartServiceCtrlDispatcher函数

BOOL WINAPI StartServiceCtrlDispatcher(  _In_ const SERVICE_TABLE_ENTRY *lpServiceTable);

函数功能:连接服务控制管理器

参数:一个SERVICE_TABLE_ENTRY结构的指针,成员最后一必须具有NULL指定末尾

如果函数成功返回为零如果函数失败返回

2。SERVICE_TABLE_ENTRY结构:

typedef struct _SERVICE_TABLE_ENTRY {  LPTSTR                  lpServiceName;  LPSERVICE_MAIN_FUNCTION lpServiceProc;} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;


lpServiceName:要服务进程运行服务名称,不能和其他程序的重了。我一般把这个名称设为注册到系统的服务名称一致。

如果服务安装的是SERVICE_WIN32_OWN_PROCESS服务类型成员忽略为 NULL,可以字符串("")。

lpServiceProc指针指向ServiceMain函数

3。ServiceMain函数:(服务启动回调函数)

VOID WINAPI ServiceMain(  _In_ DWORD  dwArgc,  _In_ LPTSTR *lpszArgv);

dwArgc:lpszArgv数组中字符串个数

lpszArgv:启动参数

服务控制管理器收到请求启动服务便启动服务进程(如果尚未运行)。服务进程线程调用StartServiceCtrlDispatcher函数SERVICE_TABLE_ENTRY结构数组指针然后服务控制管理器启动请求发送服务控制调度程序服务进程服务控制调度程序将创建一个线程执行服务正在启动ServiceMain函数

ServiceMain函数立即调用RegisterServiceCtrlHandlerEx函数指定一个HandlerEx函数处理控制请求接下来应该调用SetServiceStatus函数状态信息发送服务控制管理器这些调用完成之后函数完成初始化服务

不应服务初始化期间调用任何系统功能只有报告SERVICE_RUNNING状态服务代码才可以调用系统函数

4。RegisterServiceCtrlHandlerEx函数

SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerEx(  _In_     LPCTSTR               lpServiceName,  _In_     LPHANDLER_FUNCTION_EX lpHandlerProc,  _In_opt_ LPVOID                lpContext);

函数功能:注册一个函数处理扩展服务控制请求

lpServiceName通过调用线程运行服务名称服务控制程序创建服务CreateService函数指定服务名称。(和上面说的SERVICE_TABLE_ENTRY中的lpServiceName一致即可)

lpHandlerProc指向注册处理程序函数(HandlerEx指针

lpContext:上下文。多个服务共享一个进程,表示任何用户定义数据参数传递处理程序函数可以帮助识别服务。(可空)

如果函数成功返回服务状态句柄如果函数失败返回零。

5。HandlerEx回调函数
DWORD WINAPI HandlerEx(  _In_ DWORD  dwControl,  _In_ DWORD  dwEventType,  _In_ LPVOID lpEventData,  _In_ LPVOID lpContext);
RegisterServiceCtrlHandlerEx函数应用程序定义回调函数服务程序可以使用作为控制处理程序功能特定服务
dwControl:控制代码
SERVICE_CONTROL_NETBINDDISABLE:通知网络服务及其绑定之一已被禁用。服务应该重读它的绑定信息和删除绑定。应用程序应改用插即用功能。SERVICE_CONTROL_NETBINDENABLE:通知网络服务已启用已禁用的绑定。服务应该重读它的绑定信息,并添加新的绑定。应用程序应改用插即用功能。SERVICE_CONTROL_NETBINDREMOVE:通知网络服务绑定的组件已被删除。服务应该重读它的绑定信息和取消绑定从已删除的组件。应用程序应改用插即用功能。SERVICE_CONTROL_PARAMCHANGE:通知服务特定于服务的启动参数已更改。服务应该重读其启动参数。SERVICE_CONTROL_PAUSE:通知它应该暂停服务。SERVICE_CONTROL_PRESHUTDOWN:通知服务,系统将关闭。在系统关机时需要额外的时间来执行清理任务等紧迫的时间的服务可以使用此通知。Windows Server 2003 和 Windows XP: 不支持此值。SERVICE_CONTROL_SHUTDOWN:通知系统正在关闭,所以这项服务可以执行清理任务的服务。请注意注册 SERVICE_CONTROL_PRESHUTDOWN 通知的服务无法接收此通知,因为他们已经停止了。如果服务接受此控制代码,它必须停止后它执行其清理任务并返回 NO_ERROR。SCM 发送此控制代码之后,它不会向服务发送其他控制代码。SERVICE_CONTROL_STOP:通知应停止服务。如果服务接受此控制代码,它必须在收到后停止并返回 NO_ERROR。SCM 发送此控制代码之后,它不会向服务发送其他控制代码。Windows XP: 如果服务返回 NO_ERROR,继续运行,它继续接收控制代码。这种行为与 Windows Server 2003 和 Windows XP sp2 开始改变了。此参数也可以是下面的扩展的控制代码之一。请注意,这些控制代码不支持由处理程序函数处理:。(该服务必须注册以接收这些通知,使用 RegisterDeviceNotification 函数。)SERVICE_CONTROL_DEVICEEVENT:通知服务设备事件。DwEventType 和 lpEventData 参数包含附加信息。SERVICE_CONTROL_HARDWAREPROFILECHANGE:通知已更改计算机的硬件配置文件服务。DwEventType 参数包含的其他信息。SERVICE_CONTROL_POWEREVENT:通知系统电源事件服务。DwEventType 参数包含的其他信息。如果 dwEventType 是 PBT_POWERSETTINGCHANGE,lpEventData 参数还包含其他信息。SERVICE_CONTROL_SESSIONCHANGE:通知服务的会话更改事件。请注意,只有在是否它是完全加载之前进行登录尝试只将用户登录的通知服务。DwEventType 和 lpEventData 参数包含附加信息。SERVICE_CONTROL_TIMECHANGE:通知服务的系统时间已更改。LpEventData 参数包含的其他信息。不使用 dwEventType 参数。Windows Server 2008、 Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。SERVICE_CONTROL_TRIGGEREVENT:通知服务注册为已发生事件的服务触发事件。Windows Server 2008、 Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。SERVICE_CONTROL_USERMODEREBOOT:通知服务的用户已开始重新启动。Windows Server 2008 R2、 Windows 7、 Windows Server 2008,Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。用户自定义的控制代码:从 128 到 255。
dwEventType发生事件类型。(一般不需要)如果dwControlSERVICE_CONTROL_DEVICEEVENTSERVICE_CONTROL_HARDWAREPROFILECHANGE、SERVICE_CONTROL_POWEREVENTSERVICE_CONTROL_SESSIONCHANGE使用参数否则
如果dwControlSERVICE_CONTROL_DEVICEEVENT参数可以下列之一:DBT_DEVICEARRIVAL
DBT_DEVICEREMOVECOMPLETE
DBT_DEVICEQUERYREMOVE
DBT_DEVICEQUERYREMOVEFAILED
DBT_DEVICEREMOVEPENDING
DBT_CUSTOMEVENT
如果dwControlSERVICE_CONTROL_HARDWAREPROFILECHANGE参数可以下列之一:
DBT_CONFIGCHANGED
DBT_QUERYCHANGECONFIG
DBT_CONFIGCHANGECANCELED
如果 dwControl 是 SERVICE_CONTROL_POWEREVENT,此参数可以指定 WM_POWERBROADCAST 消息的 wParam 参数中的值之一。如果 dwControl 是 SERVICE_CONTROL_SESSIONCHANGE,此参数可以指定 WM_WTSSESSION_CHANGE 消息的 wParam 参数中的值之一。
lpEventData其他设备信息(一般不需要)
如果 dwControl 是 SERVICE_CONTROL_DEVICEEVENT,此数据对应的 lParam 参数的应用程序接收作为 WM_DEVICECHANGE 消息的一部分。
如果 dwControl 是 SERVICE_CONTROL_POWEREVENT 和 dwEventType 是 PBT_POWERSETTINGCHANGE,这个数据是指向 POWERBROADCAST_SETTING 结构的指针。
如果 dwControl 是 SERVICE_CONTROL_SESSIONCHANGE,此参数是指向 WTSSESSION_NOTIFICATION 结构的指针。
如果 dwControl 是 SERVICE_CONTROL_TIMECHANGE,这个数据是指向 SERVICE_TIMECHANGE_INFO 结构的指针。
lpContext用户RegisterServiceCtrlHandlerEx传递数据。多个服务共享一个进程lpContext参数可以帮助标识服务
返回值:
如果服务处理控制返回ERROR_CALL_NOT_IMPLEMENTED然而服务返回SERVICE_CONTROL_INTERROGATE即使服务处理
如果服务处理SERVICE_CONTROL_STOPSERVICE_CONTROL_SHUTDOWN时返回NO_ERROR
如果您的服务处理 SERVICE_CONTROL_DEVICEEVENT,返回可授予请求和错误代码拒绝该请求。
如果您的服务处理 SERVICE_CONTROL_HARDWAREPROFILECHANGE,返回可授予请求和错误代码拒绝该请求。
如果您的服务处理 SERVICE_CONTROL_POWEREVENT,返回可授予请求和错误代码拒绝该请求。
对于所有其他控制代码你服务句柄,返回 NO_ERROR。
6。SetServiceStatus
BOOL WINAPI SetServiceStatus(  _In_ SERVICE_STATUS_HANDLE hServiceStatus,  _In_ LPSERVICE_STATUS      lpServiceStatus);
hServiceStatus当前服务状态信息结构句柄句柄RegisterServiceCtrlHandlerEx函数返回
lpServiceStatus指向SERVICE_STATUS结构指针,此结构包含调用服务最新状态信息
如果函数成功返回为零如果函数失败返回
7。SERVICE_STATUS结构
typedef struct _SERVICE_STATUS {  DWORD dwServiceType;  DWORD dwCurrentState;  DWORD dwControlsAccepted;  DWORD dwWin32ExitCode;  DWORD dwServiceSpecificExitCode;  DWORD dwCheckPoint;  DWORD dwWaitHint;} SERVICE_STATUS, *LPSERVICE_STATUS;
dwServiceType服务类型
SERVICE_FILE_SYSTEM_DRIVER:服务是文件系统驱动程序。SERVICE_KERNEL_DRIVER:服务是一个设备驱动程序。SERVICE_WIN32_OWN_PROCESS:服务运行在它自己的进程。SERVICE_WIN32_SHARE_PROCESS:服务与其他服务共享一个进程。如果服务类型是 SERVICE_WIN32_OWN_PROCESS 或 SERVICE_WIN32_SHARE_PROCESS,并且该服务运行在本地系统帐户的上下文中,也可以指定以下类型:SERVICE_INTERACTIVE_PROCESS:服务可以与桌面交互。
dwCurrentState:服务的当前状态。此成员可以是下列值之一。
SERVICE_CONTINUE_PENDING:服务继续处于挂起状态。SERVICE_PAUSE_PENDING:服务暂停被挂起。SERVICE_PAUSED:服务已暂停。SERVICE_RUNNING:该服务正在运行。SERVICE_START_PENDING:服务正在启动。SERVICE_STOP_PENDING:服务正在停止。SERVICE_STOPPED:服务已停止。
dwControlsAccepted
SERVICE_ACCEPT_NETBINDCHANGE:服务是网络组件,它可以接受更改其绑定中的没有被停止并重新启动。此控制代码允许接收 SERVICE_CONTROL_NETBINDADD、 SERVICE_CONTROL_NETBINDREMOVE、 SERVICE_CONTROL_NETBINDENABLE 和 SERVICE_CONTROL_NETBINDDISABLE 的通知服务。SERVICE_ACCEPT_PARAMCHANGE:该服务可以重读其启动参数没有被停止并重新启动。此控制代码允许接收 SERVICE_CONTROL_PARAMCHANGE 通知服务。SERVICE_ACCEPT_PAUSE_CONTINUE:可以暂停和继续服务。此控制代码允许接收 SERVICE_CONTROL_PAUSE 和 SERVICE_CONTROL_CONTINUE 通知服务。SERVICE_ACCEPT_PRESHUTDOWN:该服务可以执行 preshutdown 任务。此控制代码使服务能够接收 SERVICE_CONTROL_PRESHUTDOWN 通知。请注意,这个和 ControlServiceEx 不能发送此通知;只有系统可以发送它。Windows Server 2003 和 Windows XP: 不支持此值。SERVICE_ACCEPT_SHUTDOWN:系统关机时,将通知服务。此控制代码允许接收 SERVICE_CONTROL_SHUTDOWN 通知服务。请注意,这个和 ControlServiceEx 不能发送此通知;只有系统可以发送它。SERVICE_ACCEPT_STOP:可以停止该服务。此控制代码允许接收 SERVICE_CONTROL_STOP 通知服务。此成员还可以包含下面的扩展的控制代码,仅由 HandlerEx 支持。(请注意,这些控制代码无法通过ControlServiceEx发送)。SERVICE_ACCEPT_HARDWAREPROFILECHANGE:当计算机的硬件配置文件发生更改时,将通知服务。这使系统能够向服务发送 SERVICE_CONTROL_HARDWAREPROFILECHANGE 通知。SERVICE_ACCEPT_POWEREVENT:当计算机电源状态更改通知服务。这使系统能够向服务发送 SERVICE_CONTROL_POWEREVENT 通知。SERVICE_ACCEPT_SESSIONCHANGE:当计算机的会话状态发生更改时,将通知服务。这使系统能够向服务发送 SERVICE_CONTROL_SESSIONCHANGE 通知。SERVICE_ACCEPT_TIMECHANGE:当系统时间已更改通知服务。这使系统能够向服务发送 SERVICE_CONTROL_TIMECHANGE 通知。Windows Server 2008、 Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。SERVICE_ACCEPT_TRIGGEREVENT:服务注册为该事件发生时通知服务。这使系统能够向服务发送 SERVICE_CONTROL_TRIGGEREVENT 通知。Windows Server 2008、 Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。SERVICE_ACCEPT_USERMODEREBOOT:当用户启动重新启动时,将通知服务。Windows Server 2008 R2、 Windows 7、 Windows Server 2008,Windows Vista、 Windows Server 2003 和 Windows XP: 此控制代码不受支持。
dwWin32ExitCode错误代码服务使用报告启动停止时发生错误若要返回服务特定错误代码服务必须设置ERROR_SERVICE_SPECIFIC_ERROR指示dwServiceSpecificExitCode成员包含错误代码服务运行正常终止设置NO_ERROR
dwServiceSpecificExitCodedwWin32ExitCode成员设置ERROR_SERVICE_SPECIFIC_ERROR时,此参数表示服务返回发生错误服务正在启动停止服务特定错误代码。否则忽略
dwCheckPoint:置0即可
dwWaitHint挂起启动所需估计时间停止暂停继续操作毫秒为单位
完整源码实例(服务程序框架):
#include "stdafx.h"#include <windows.h>static TCHAR* name = TEXT("MyService");//服务名称SERVICE_STATUS_HANDLE hStatus;//服务状态句柄SERVICE_STATUS ServiceStatus;//当前服务的状态信息DWORD WINAPI HandlerEx(_In_ DWORD  dwControl, _In_ DWORD  dwEventType, _In_ LPVOID lpEventData, _In_ LPVOID lpContext){switch (dwControl){case SERVICE_CONTROL_STOP://控制代码:要求停止停止ServiceStatus.dwWin32ExitCode = 0;ServiceStatus.dwCurrentState = SERVICE_STOPPED;SetServiceStatus(hStatus, &ServiceStatus);//报告服务运行状态return 0;case SERVICE_CONTROL_SHUTDOWN://控制代码:关机ServiceStatus.dwWin32ExitCode = 0;ServiceStatus.dwCurrentState = SERVICE_STOPPED;SetServiceStatus(hStatus, &ServiceStatus);//报告服务运行状态return 0;default:break;}ServiceStatus.dwCurrentState = SERVICE_RUNNING;SetServiceStatus(hStatus, &ServiceStatus);//报告服务运行状态return 0;}VOID WINAPI ServiceMain(_In_ DWORD  dwArgc, _In_ LPTSTR *lpszArgv){hStatus = RegisterServiceCtrlHandlerEx(name, &HandlerEx, NULL);if (hStatus == (SERVICE_STATUS_HANDLE)0){//这里是对RegisterServiceCtrlHandler失败的处理return;}RtlZeroMemory(&ServiceStatus, sizeof(SERVICE_STATUS));//结构体清空ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;ServiceStatus.dwCurrentState = SERVICE_RUNNING;ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;//接受关机和停止控制SetServiceStatus(hStatus, &ServiceStatus);//报告服务运行状态if (ServiceStatus.dwCurrentState == SERVICE_RUNNING){//把服务要做的工作放到这里}}int _tmain(int argc, _TCHAR* argv[]){SERVICE_TABLE_ENTRY ServiceTable[2];ServiceTable[0].lpServiceName = name;ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)&ServiceMain;ServiceTable[1].lpServiceName = NULL;ServiceTable[1].lpServiceProc = NULL;StartServiceCtrlDispatcher(ServiceTable);return 0;}

服务程序如何关闭自己?正确的做法是
ServiceStatus.dwWin32ExitCode = 0;ServiceStatus.dwCurrentState = SERVICE_STOPPED;SetServiceStatus(hStatus, &ServiceStatus);return;
如何把自己的服务安装进系统?使用服务管理器API,我们就可以让我们的程序安装服务,管理服务了,以后会讲。现在我们可以使用一些工具来安装(比如srvinstw),其实这些工具也是调用的服务管理器API

4 0
原创粉丝点击