Windows 服务程序(一)
Windows 服务程序简介:

int main(void)
{
SERVICE_TABLE_ENTRYA ServTable[]; // 创建服务分派表。
ServTable[].lpServiceName = "Test"; // 服务名称。类似于 Win32 应用程序的窗口名称。每个服务代表一项功能。
ServTable[].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; //服务入口函数。
ServTable[].lpServiceName = NULL; // 每一个服务分派表代表一个服务,分派表的最后一项必须是服务名和服务主函数域的 NULL 指针。
ServTable[].lpServiceProc = NULL; // 我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。
StartServiceCtrlDispatcher(ServTable); // 启动控制分派机制。
return 0;
}
SERVICE_TABLE_ENTRYA 结构体:
typedef struct _SERVICE_TABLE_ENTRYA {
LPSTR lpServiceName; // 服务名称。
LPSERVICE_MAIN_FUNCTIONA lpServiceProc; // 服务入口函数。
} SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
StartServiceCtrlDispatcher() 介绍 :
功能:连接程序主线程到服务控制管理程序。
BOOL StartServiceCtrlDispatcher(
CONST SERVICE_TABLE_ENTRYA *lpServiceStartTable // SERVICE_TABLE_ENTRYA 结构体变量。
);
返回值:非零表示成功,零表示失败。
服务控制管理器 (SCM:Services Control Manager) 是一个管理系统所有服务的进程。
当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数,
将分派表传递给 StartServiceCtrlDispatcher。
这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,
该线程运行分派表中每个服务的 ServiceMain 函数分派器还监视程序中所有服务的执行情况。
然后分派器将控制请求从 SCM 传给服务。
分派表中所有的服务执行完之后,或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。
SCM 开始启动一个服务程序时,总是等待这个服务程序去调用 StartServiceCtrlDispatcher()。
而当服务开始运行时,main() 将会调用 ServiceMain(), 直到 ServiceMain() 执行完毕或发生错误而退出,
StartServiceCtrlDispatcher() 返回,主线程将会终止。
ServiceMain() 服务入口函数,它的作用就是:将你需要执行的任务放到该函数中循环执行即可。这就是服务程序的工作函数。
在ServiceMain执行你的任务前,需要给SERVICE_TABLE_ENTRY 分派表结构体进行赋值。
典型代码如下:
// SERVICE_STATUS ServiceStatus; //这段代码应声明为全局变量,因多处使用。
// SERVICE_STATUS_HANDLE hStatus; //这段代码应声明为全局变量,因多处使用。
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
{
// 初始化状态设置。
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING; // 即服务目前状态为 正在初始化。
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
// 这个通知 SCM 服务接收哪个域。本例包含 停止,暂停和继续,关机等命令。
ServiceStatus.dwWin32ExitCode = ; // 这个域在终止服务并报告细节时很有用。下面这四个值一般不用关心,通常设置为 0。
ServiceStatus.dwCheckPoint = ; // 用来报告它当前的事件进展情况的。
ServiceStatus.dwServiceSpecificExitCode = ; // 这个域在终止服务并报告细节时也很有用。
ServiceStatus.dwWaitHint = ; // 根据初始化过程的长短而定。
// 注册控制函数。
hStatus = RegisterServiceCtrlHandler("ServiceName", // 注册服务控制程序,注册成功后将会返回一个服务状态句柄。
(LPHANDLER_FUNCTION)ServiceHandler); // ServiceHandle 是服务控制程序。类似与 Windows 应用程序的窗口过程。
if (!hStatus)
{
printf("Register Service Error!\n");
system("pause");
return;
}
SetServiceStatus(hStatus, &ServiceStatus); // 设置服务状态。通过调用 SetServiceStatus 函数,向 SCM 报告服务的状态。
if (GetLastError != NO_ERROR) // 返回调用线程最近的错误代码值,检查是否出错。
{
// 如果出错,将其重设为停止状态。
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
printf("Start Error!\n");
system("pause");
return;
}
// 没有错误就继续运行。
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
// 创建线程执行特定功能
HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL); // MyWOrk 是特定功能的函数,如后门程序。
if(hThread = NULL)
return;
}
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_USER_OWN_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 | 系统在关闭前,能够收到系统的 SERVICE_CONTROL_PRESHUTDOWN 通知,用来处理一些关闭前的清理,xp之前不支持此控制码 |
| SERVICE_ACCEPT_SHUTDOWN | 能够接收系统退出时的 SERVICE_CONTROL_SHUTDOWN 的通知,以便处理一些回收 |
| SERVICE_ACCEPT_STOP | 能够接收 SERVICE_CONTROL_STOP 的通知来处理一些回收任务 |
SetServiceStatus() 介绍:
功能:更新服务控制管理器调用服务的状态信息。
函数原型:BOOL SetServiceStatus(
SERVICE_STATUS_HANDLE hServiceStatus, //服务状态信息结构的句柄, 由 RegisterServiceCtrlHandler() 返回。
LPSERVICE_STATUS lpServiceStatus // 指向 SERVICE_STATUS 结构的指针包含呼叫服务的最新状态信息。
);
返回值:非零表示成功,零表示失败。
RegisterServiceCtrlHandler() 介绍:
功能:注册一个函数以处理服务控制请求。
函数原型:SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(
LPCSTR lpServiceName, //调用线程运行的服务的名称, 即在 CreateService() 中指定的服务控制程序的服务名称。
LPHANDLER_FUNCTION lpHandlerProc // 指向要注册的处理程序的函数。
);
返回值:如果函数成功, 则返回值为服务状态句柄。如果函数失败, 返回值为零。
CreateThread() 介绍:
功能:该函数在 主线程的基础上创建一个新线程。线程终止运行后,
线程对象仍然在系统中,必须通过 CloseHandle() 来关闭该线程对象。
函数原型:HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
参数:
lpThreadAttributes
指向 SECURITY_ATTRIBUTES 结构的指针, 它确定返回的句柄是否可以由子进程继承。
如果 lpThreadAttributes 为 NULL, 则无法继承句柄。
dwStackSize
堆栈的初始大小 (以字节为单位)。系统将此值舍入到最近的页面。
如果此参数为零, 则新线程将使用可执行文件的默认大小。
lpStartAddress
指向要由线程执行的应用程序定义的函数。此指针表示线程的起始地址。
lpParameter
指向要传递给线程的变量的指针。
dwCreationFlags
控制线程创建的标志。通常情况下为 0。
lpThreadId
指向接收线程标识符的变量的指针。如果此参数为 NULL, 则不返回线程标识符。
返回值:如果函数成功, 则返回值是新线程的句柄。如果函数失败, 返回值为 NULL。
ServiceHandle() 服务控制函数,典型代码如下:
void WINAPI ServiceHandler(DWORD fdwControl)
{
switch (fdwControl)
{
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwWaitHint = ;
SetServiceStatus(hStatus, &ServiceStatus);
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus); // 重设服务状态。
return;
}
入门代码如下:(目前的代码仍然不能当做服务来运行,还需要 SCM 进行安装)
#include<stdio.h>
#include<Windows.h>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
void WINAPI ServiceHandler(DWORD fdwControl);
DWORD WINAPI MyWork(LPVOID lpParam);
int main(void)
{
SERVICE_TABLE_ENTRY ServTable[];
ServTable[].lpServiceName = (LPSTR)"Test";
ServTable[].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServTable[].lpServiceName = NULL;
ServTable[].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServTable);
return ;
} void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = ;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwServiceSpecificExitCode = ;
ServiceStatus.dwWaitHint = ;
hStatus = RegisterServiceCtrlHandler("ServiceName",
(LPHANDLER_FUNCTION)ServiceHandler);
if (!hStatus)
{
printf("Register Service Error!\n");
system("pause");
return;
}
SetServiceStatus(hStatus, &ServiceStatus);
if (GetLastError() != NO_ERROR)
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
printf("Start Service Error!\n");
system("pause");
return;
}
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
// 从这里开始可以放入你想服务为你所做的事情。
HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL);
if(hThread = NULL)
return;
} void WINAPI ServiceHandler(DWORD fdwControl)
{
switch (fdwControl)
{
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = ;
ServiceStatus.dwWaitHint = ;
SetServiceStatus(hStatus, &ServiceStatus);
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);
return;
} DWORD WINAPI MyWork(LPVOID lpParam)
{
return 0;
}
Windows 服务程序(一)的更多相关文章
- WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...
- C#写Windows Service(windows服务程序)
背景: 要学习使用一个新东西,我们必须知道他是个什么东西.对于我们此次研究的windows服务来说,他又是个什么东西,其实也没有什么高深的了. windows service概述: 一个 ...
- 关于开发Windows服务程序容易搞混的地方!
在开发Windows服务程序时,我们一般需要添加安装程序,即:serviceInstaller,里面有几个关于名称属性,你都搞明白了吗? 1.Description:表示服务说明(描述服务是干什么的) ...
- Windows服务程序和安装程序制作
转:http://www.cr173.com/html/15350_1.html 本文介绍了如何用C#创建.安装.启动.监控.卸载简单的Windows Service 的内容步骤和注意事项. 一.创建 ...
- .net Windows服务程序和安装程序制作图解 及 VS 2010创建、安装、调试 windows服务(windows service)
.net Windows服务程序和安装程序制作 最近项目中用到window服务程序,以前没接触过,比较陌生,花了两天的时间学习了下,写了个简单的服务,但在制作安装程序的时候,参照网上很多资料,却都制作 ...
- C# 编写Windows Service(windows服务程序)【转载】
[转]http://www.cnblogs.com/bluestorm/p/3510398.html Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成 ...
- C# 创建、安装和卸载Windows服务程序
1.新建一个windows服务程序. 2.点击这个服务类,从工具箱中加入一个Timer控件,右键这个Timer控件 命名为 timerOrderDeductionDetailJob,Enable设为T ...
- windows服务程序
首先创建一个myService的窗体程序作为服务安装卸载控制器(管理员身份运行vs,windows服务的安装卸载需要管理员权限) 在同一个解决方案里面添加一个windows服务程序,取名myWin ...
- C语言编写Windows服务程序
原文:C语言编写Windows服务程序 #include <Windows.h> #include <stdio.h> #define SLEEP_TIME 5000 // 间 ...
- 创建一个Windows服务程序与实现定时器效果
1.创建一个Windows服务程序 一. 新建Window服务项目 二. 添加安装程序 三. 配置服务属性 四. 编写定时器代码 publicpartialclassService1 ...
随机推荐
- 【第十篇】easyui-datagrid排序 (转)
本文体验datagrid的排序. □ 思路 当点击datagrid的标题,视图传递给Controller的Form Data类似这样:page=1&rows=10&sort=Custo ...
- CSS——字体
1.字体样式font-family.颜色color <!DOCTYPE html> <html> <head> <meta charset="UTF ...
- SpringBoot整合redis缓存(一)
准备工作 1.Linux系统 2.安装redis(也可以安装docker,然后再docker中装redis,本文章就直接用Linux安装redis做演示) redis下载地址: 修改redis,开启远 ...
- Linux 笔记 - 第十四章 LAMP 之(二) 环境配置
博客地址:http://www.moonxy.com 一.前言 LAMP 环境搭建好之后,其实仅仅是安装上了软件,我们还需要掌握 httpd 和 PHP 的配置. 二.httpd 配置 2.1 创建虚 ...
- Python3 爬虫之 Scrapy 框架安装配置(一)
博客地址:http://www.moonxy.com 基于 Python 3.6.2 的 Scrapy 爬虫框架使用,Scrapy 的爬虫实现过程请参照本人的另一篇博客:Python3 爬虫之 Scr ...
- Disruptor原理探讨
之前谈到了在我的项目里用到了Disruptor,因为对它了解不足的原因,才会引发之前的问题,因此,今天特意来探讨其原理. 为什么采用Disruptor 先介绍一下我的这个服务.这个服务主要是作为游戏服 ...
- linux安装couchbase
一.卸载 查看已安装的版本 rpm -qa|grep couchbase 卸载已安装的版本 rpm -e xxxx 二.安装 安装couchbase rpm -i xxxx.rpm 浏览器中访问809 ...
- [Linux] Vmware 15安装CentOs后显示网络不可用
转载自:https://blog.csdn.net/chenjin_chenjin/article/details/83617186 在虚拟机上安装好centos7后,ping www.baidu.c ...
- Cocos Creator 中 _worldMatrix 到底是什么(上)
Cocos Creator 中 _worldMatrix 到底是什么(上) 1. (矩阵)Matrix是什么,有什么用 (矩阵)Matrix一个神奇的存在?在开发过程中对里边各项值的含义是不是抓耳挠腮 ...
- 了解一下Java SPI的原理
了解一下Java SPI的原理 1 为什么写这篇文章? 近期,本人在学习dubbo相关的知识,但是在dubbo官网中有提到Java的 SPI,这个名词之前未接触过,所以就去看了看,感觉还是有很多地方有 ...