Windows Service服务程序的原理及实现(0)服务主函数 & 控制处理函数
来源:互联网 发布:数据挖掘工具主要有 编辑:程序博客网 时间:2024/06/05 19:57
摘要: 何为服务?Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。一个服务首先是一个Win32可执行程序,如果要写一个功能完备且强大的服务,需要熟悉动态连接库(DLL)、结构异常处理、内存映射文件、虚拟内存、设备I/O、线程及其同步、Unicode以及其他的由WinAPI函数提供的应用接口。
Windows Service概要
实现一个服务程序,主要需要完成两个部分:
- 服务运行函数(相当于
Thread
中的run
):服务运行函数,一般被呼为ServiceMain
。但是它的名称与ThreadProc
一样,其命名没有特殊要求,只是参数接口和调用类型必须与要求一致:
void WINAPI serviceImpl(DWORD argc, LPCWSTR* argv);
- 服务控制函数:Windows中提供了强大的命令行工具
sc.exe
,用于对服务进行管理。可以实现对服务的所有控制,包括安装、删除、配置、启动、停止等。为此,我们需要在自己的服务程序中对这些命令做出响应。也就是需要实现一个服务控制函数,当接收到不同命令的时候,执行不同的操作,具体操作自行定义。
一个服务包括若干属性,包括服务名称、显示名称、服务类型、描述、可执行文件路径、启动类型、服务状态、启动参数、依存关系等。
- 服务名称:唯一标识一个服务;
- 显示名称:在系统服务管理界面和sc.exe中显示名称;
- 服务类型:包括SERVICE_FILE_SYSTEM_DRIVER(文件系统驱动服务)、SERVICE_KERNEL_DRIVER(驱动服务)——(2种)运行于内核态。
SERVICE_WIN32_OWN_PROCESS(独立进程服务)、SERVICE_WIN32_SHARE_PROCESS(共享进程服务)——(2种)运行于用户态。
本文主要讲解Windows服务运行函数开发。Windows服务与多线程极为类似,服务运行函数一般称为ServiceMain
,与线程中的ThreadProc
(线程执行体)一样,其函数名并没有特殊的要求,只要求其参数接口和返回值调用类型与要求一致即可,这里所说的ServiceMain(服务运行函数)也可以理解为Thread中的run
,虽然不是很恰当。服务程序通过调用StartServiceCtrlDispatcher
API函数设置服务主函数。
其中,StartServiceCtrlDispatcher 函数原型如下:
StartServiceCtrlDispatcherW( _In_ CONST SERVICE_TABLE_ENTRYW *lpServiceStartTable );
以上函数中只有一个结构体,SERVICE_TABLE_ENTRYW
的原型也给出如下:
typedef struct _SERVICE_TABLE_ENTRYW { LPWSTR lpServiceName; LPSERVICE_MAIN_FUNCTIONW lpServiceProc;}SERVICE_TABLE_ENTRYW, *LPSERVICE_TABLE_ENTRYW;
lpServiceName
为服务名称;lpServiceProc
为指向ServiceMain的函数指针。只要将函数的指针复制给lpServiceProc,再调用StartServiceCtrlDispatcher ,这个函数就称为了服务主函数。
没有服务控制函数,光有服务执行体——服务是跑不起来的。
服务控制函数可以用Windows提供的sc.exe
程序,在命令提示符的环境下,让服务运行体(ServiceMain)跑起来。这里使用另外一种方式,使用Windows API来控制服务执行体。所谓服务——其实也就是一个EXE可执行程序。
Service一般开发流程
一般服务开发流程:
- 先将服务运行体(ServiceMain)生成,得到一个
XXX.exe
。(本文讲解内容) - 接着,将该exe放在电脑的某一个位置,再运行服务控制函数,服务就跑起来了。
- 这里需要注意一点,开发服务程序,需要以管理员方式运行Visual Studio 2013等版本。(或者在DOS下操作时,就是不编写服务控制程序,而采用Windows提供的
sc.exe
管理服务,也同样需要管理员权限。)
在服务程序开发过程中,有一个很重要的结构体SERVICE_STATUS
其具体定义如下:
typedef struct _SERVICE_STATUS { DWORD dwServiceType; //可执行文件类型 DWORD dwCurrentState; //服务当前状态 DWORD dwControlsAccepted; //指明服务接受何种控制 DWORD dwWin32ExitCode; //错误报告码(Win32已义错误) DWORD dwServiceSpecificExitCode; //自定义错误码 DWORD dwCheckPoint; //处于进程的哪一步 DWORD dwWaitHint; //超时时间} SERVICE_STATUS, *LPSERVICE_STATUS;
dwServiceType
指明服务可执行文件的类型。如果你的可执行文件中只有一个单独的服务,就把这个成员设置成SERVICE_WIN32_OWN_PROCESS;如果拥有多个服务的话,就设置成SERVICE_WIN32_SHARE_PROCESS。除了这两个标志之外,如果你的服务需要和桌面发生交互(当然不推荐这样做),就要用“OR”运算符附加上SERVICE_INTERACTIVE_PROCESS。这个成员的值在你的服务的生存期内绝对不应该改变。dwCurrentState
是这个结构中最重要的成员,它将告诉SCM你的服务的现行状态。为了报告服务仍在初始化,应该把这个成员设置成SERVICE_START_PENDING。在以后具体讲述CtrlHandler函数的时候具体解释其它可能的值。dwControlsAccepted
指明服务愿意接受什么样的控制通知。如果你允许一个SCP去暂停/继续服务,就把它设成SERVICE_ACCEPT_PAUSE_CONTINUE。很多服务不支持暂停或继续,就必须自己决定在服务中它是否可用。如果你允许一个SCP去停止服务,就要设置它为SERVICE_ACCEPT_STOP。如果服务要在操作系统关闭的时候得到通知,设置它为SERVICE_ACCEPT_SHUTDOWN可以收到预期的结果。这些标志可以用“OR”运算符组合。dwWin32ExitCode
和dwServiceSpecificExitCode
是允许服务报告错误的关键,如果希望服务去报告一个Win32错误代码(预定义在WinError.h中),它就设置dwWin32ExitCode为需要的代码。一个服务也可以报告它本身特有的、没有映射到一个预定义的Win32错误代码中的错误。为了这一点,要把dwWin32ExitCode设置为ERROR_SERVICE_SPECIFIC_ERROR,然后还要设置成员dwServiceSpecificExitCode为服务特有的错误代码。当服务运行正常,没有错误可以报告的时候,就设置成员dwWin32ExitCode为NO_ERROR。- 最后的两个成员
dwCheckPoint
和dwWaitHint
是一个服务用来报告它当前的事件进展情况的。当成员dwCurrentState被设置成SERVICE_START_PENDING的时候,应该把dwCheckPoint设成0,dwWaitHint设成一个经过多次尝试后确定比较合适的数,这样服务才能高效运行。一旦服务被完全初始化,就应该重新初始化SERVICE_STATUS结构的成员,更改dwCurrentState为SERVICE_RUNNING,然后把dwCheckPoint和dwWaitHint都改为0。- dwCheckPoint成员的存在对用户是有益的,它允许一个服务报告它处于进程的哪一步。每一次调用SetServiceStatus时,可以增加它到一个能指明服务已经执行到哪一步的数字,它可以帮助用户决定多长时间报告一次服务的进展情况。
- 如果决定要报告服务的初始化进程的每一步,就应该设置dwWaitHint为你认为到达下一步所需的毫秒数,而不是服务完成它的进程所需的毫秒数。
Service 实战
对于Windows服务开发想了解更多可以阅读《Windows服务编写原理及探讨》一文,想实战开发可以参阅《Windows API—函数、接口、编程实例》一书。以下是一个完整的服务运行体(ServiceMain
)实战。如果想直接讨论《Q群号:233688836》。在阅读本文的基础上,推荐阅读《Windows Service服务程序(1)实现对服务的控制和管理》,将对Windows服务编程有个更加深入的了解。
win32service.h
#ifndef _WIN32_SERVICE_H#define _WIN32_SERVICE_H#include <Windows.h>extern SERVICE_STATUS g_ServiceStatus;extern SERVICE_STATUS_HANDLE g_ServiceStatusHandle;void WINAPI serviceImpl(DWORD argc, LPCWSTR* argv);void WINAPI serviceCtrlHandlerProc(DWORD opcode);#endif
win32service.cpp
#include "win32service.h"SERVICE_STATUS g_ServiceStatus;SERVICE_STATUS_HANDLE g_ServiceStatusHandle;/*功能:服务控制函数*/void WINAPI serviceCtrlHandlerProc(DWORD opcode){ switch (opcode){ case SERVICE_CONTROL_PAUSE: g_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; break; case SERVICE_CONTROL_INTERROGATE:/*[ɪn'terə.ɡeɪt] v.审问;询问*/ MessageBeep(MB_OK); default: break; } if (!SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus)){ //set service status error. }}/*功能:服务运行函数*/void WINAPI serviceImpl(DWORD argc, LPCWSTR* argv){ g_ServiceStatus.dwServiceType = SERVICE_WIN32; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 0; g_ServiceStatus.dwWaitHint = 0; g_ServiceStatusHandle = RegisterServiceCtrlHandlerA("demo_srv", serviceCtrlHandlerProc); if (g_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0){ //register service ctrl handle error. return; } g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; if (!SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus)){ //set service status error. return; }#if 0 while (flag){ //run service }#endif}
main.cpp
#include "win32service.h"int main(void){ SERVICE_TABLE_ENTRYA DispatchTable[] = { { "demo_srv", (LPSERVICE_MAIN_FUNCTIONA)serviceImpl }, { NULL, NULL } }; if (!StartServiceCtrlDispatcherA(DispatchTable)){ //start service ctrl dispather error. } return 0;}
- Windows Service服务程序的原理及实现(0)服务主函数 & 控制处理函数
- Windows Service服务程序的原理及实现(1)实现对服务的控制和管理
- Windows服务程序的原理及实现
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- 关于服务程序(service)的命令(windows\linux)
- 制作可控制界面的windows服务(windows service)
- 如何控制Windows服务程序
- Windows服务之实现对服务的控制管理
- Windows服务之实现对服务的控制管理
- Windows Service开发日志四(用程序设置服务的运行状态及启动方式)
- C#制作Windows service服务系列三--制作可控制界面的Windows服务
- C# 编写Windows Service(windows服务程序)
- C# 编写Windows Service(windows服务程序)
- C# 编写Windows Service(windows服务程序)
- C# 编写Windows Service(windows服务程序)
- C# 编写Windows Service(windows服务程序)
- 设计模式---原型模式
- ADO.NET 快速入门(五):从 DataSet 更新数据库
- 用uid分库,uname上的查询怎么办?(58沈剑)
- Android学习二 布局和按钮点击事件
- 今天在刷题的过程看到一位大神写的代码
- Windows Service服务程序的原理及实现(0)服务主函数 & 控制处理函数
- Android Https相关完全解析 当OkHttp遇到Https
- 函数模板深探
- 深入理解JavaScript执行上下文、函数堆栈、提升的概念
- Kotlin(一)语法基础
- 阿里实习编程题1
- Uva725—除法
- LeetCode100 Same Tree
- Makefile介绍及Makefile是如何工作的