Windows服务程序有固定的模式,一般由4个部分构成:main()、Servicemain()、ServerHandle()、自定义函数。
main函数的作用与其他程序的主函数其实从主要作用上讲是一致的,主要作用就是创建服务分派表并且启动服务控制分派机制。简单讲就是初始化服务程序,开始干活。
典型的服务main函数的代码如下:
int main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName =(LPSTR)"Test";//设置服务名称
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;//设置服务对应的函数
ServiceTable[1].lpServiceName = NULL;//服务表的最后一项必须设置为空,表示当前服务表结束
ServiceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServiceTable);//启动控制分派器
return 0;
}
其中包含一个结构体SERVICE_TABLE_ENTRY(服务分派表),这个表的结构如下:
typedef struct _SERVICE_TABLE_ENTRYA {
LPSTR lpServiceName;//服务的名称
LPSERVICE_MAIN_FUNCTIONA lpServiceProc;//指向服务的函数
}SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
一个程序中可能包含多个服务以及服务处理函数,每个服务都要填入朱门的服务分派表中,服务分派表的第一个成员是该服务的名称,第二个成员则是服务的处理函数也就是服务入口函数。有一点需要注意,服务分派表的最后一项必须是服务名以及服务函数域为NULL的指针,以此来表示服务分派表结束。
StartServiceCtrlDispatcher函数的原型如下:函数作用(连接程序主线程到服务控制管理程序SCM)
BOOL
WINAPI
StartServiceCtrlDispatcherA(
_In_ CONST SERVICE_TABLE_ENTRYA *lpServiceStartTable
);
服务控制管理器(ServiceControlManager)是一个管理系统所有服务的进程,当SCM启动某个服务的时候,就会等待某个进程的主线程调用StartServiceCtrlDispatcher函数,接收到StartServiceCtrlDispatcher函数的运行之后,会把填充好的分派表项发送给StartServiceCtrlDispatcher函数。这个操作会把当前调用进程的主线程转换为控制分派器(在这里是main函数)控制分派器回信启动一个线程来执行所有的分派表中的Servermain函数。
ServiceMain函数除了用来向服务控制u案例其汇报服务状态之外,害需要完成自己特定的操作,也就是服务存在的意义:
不过ServiceMain函数的主要任务在微软官网上也能查找到:
https://docs.microsoft.com/en-us/windows/win32/services/service-servicemain-function
ServiceMain应该执行以下任务:
1:初始化所有的全局变量
2:注册Handler函数来处理对该服务的控制请求
3:执行初始化
4:初始化结束之后,调用SetServiceStatus将服务状态设置为SERVICE_RUNNING并指定服务准备接受的状态码
5:执行具体的任务,如果没有要执行的具体事务,将控制权返回给调用方
(注意:服务状态的任何更改都需要调用SetServiceStatus函数报告新的状态信息)
状态码
详见:SERVICE_STATUS
典型代码段如下:
SERVICE_STATUS ServiceStatus; //服务状态码
SERVICE_STATUS_HANDLE hStatus;//服务句柄
void WINAPI ServiceMain(DWORD Args,LPSTR *lpSzArgv)
{
//初始化服务状态
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;//服务类型
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;//设置目前服务的状态:正在初始化
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;//设置当前服务接收的请求
ServiceStatus.dwWin32ExitCode = 0;//服务用于报告启动或停止时发生错误的错误代码
ServiceStatus.dwCheckPoint = 0;//服务在长时间启动、停止、暂停或继续操作期间定期递增以报告其进度的检查点值
ServiceStatus.dwServiceType = 0;//服务类型
ServiceStatus.dwWaitHint = 0;//将要进行 开始、停止、暂停或继续服务 操作所需的估计时间 (以毫秒为单位)
//初始化结束之后,开始第二步操作,开始注册Handler函数(注册服务控制请求函数)
hStatus = RegisterServiceCtrlHandler("Demo",(LPHANDLER_FUNCTION)ServiceHandler);//注册服务控制请求函数
if (!hStatus)
{
printf("注册服务控制请求函数失败");
system("Pause");
return ;
}
SetServiceStatus(hStatus,&ServiceStatus);//向SCM报告服务状态
//是否设置成功
if (GetLastError != NO_ERROR)
{
//如果失败,重新设置状态为停止
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
printf("设置服务状态失败");
system("pause");
return;
}
//设置成功之后继续运行,这个时候需要通知SCM将服务状态设置为Running状态
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);//服务状态变更之后要重新设置 以通知SCM
//在开实质性服务主要函数之前还需要将服务启动
StartDestService();
//接下来开始执行服务程序的主要操作
WorkThing();
}
完成ServerMain之后,还有一个重要部分需要注意:服务请求控制函数的实现,该函数的主要功能在于通过服务的状态码来对服务进行相关操作,例如:暂停、继续运行、卸载、安装之类的操作。
典型代码:
VOID WINAPI ServiceHandler(DWORD dwControl)
{
//实现服务控制请求函数,通过各类请求控制码决定服务做什么操作
switch (dwControl)
{
//服务暂停
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
//服务继续运行
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
//关闭服务(和停止服务走相同的额逻辑)
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);//设置服务状态
//关闭服务和停止服务的时候需要先将服务停止
StopService();
//关闭和停止服务的时候需要同时将服务卸载
UninstallService();
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);//设置服务状态
return;
}
以上即为一个服务程序的简单组成部分,接下来就需要完成对服务的各个功能的补充:
1:服务的主要功能函数,这个服务的主要功能
2:服务的各个功能函数:安装、卸载、开始、停止等基本功能
服务安装函数:主要功能,创建服务
服务卸载函数:主要功能,删除服务
服务开始函数:主要功能,启动进程
服务停止函数:主要功能,停止进程
需要注意的函数有一个StartService,该函数在定义的时候存在3个参数,参数一是对应二点服务的句柄,参数二是对应的要传递给服务的参数个数,参数三是要传递给服务的参数(ServiceMain)
#include<stdio.h>
#include<Windows.h>
SERVICE_STATUS ServiceStatus; //服务状态码
SERVICE_STATUS_HANDLE hStatus;//服务句柄
SC_HANDLE SC_Manager;
SC_HANDLE SC_Service;
void WorkThing();//服务主要工作的事情
void UninstallService();//定义卸载服务的函数
void StopService();//定义停止服务的函数
void InstallService();//定义安装服务的函数
void StartDestService();//启动服务
VOID WINAPI ServiceHandler(DWORD dwControl);
void WINAPI ServiceMain(DWORD Args, LPSTR *lpSzArgv);
int main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName =(LPSTR)"Test";//设置服务名称
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;//设置服务对应的函数
ServiceTable[1].lpServiceName = NULL;//服务表的最后一项必须设置为空,表示当前服务表结束
ServiceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServiceTable);//启动控制分派机制
return 0;
}
void WINAPI ServiceMain(DWORD Args,LPSTR *lpSzArgv)
{
//初始化服务状态
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;//服务类型
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;//设置目前服务的状态:正在初始化
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;//设置当前服务接收的请求
ServiceStatus.dwWin32ExitCode = 0;//服务用于报告启动或停止时发生错误的错误代码
ServiceStatus.dwCheckPoint = 0;//服务在长时间启动、停止、暂停或继续操作期间定期递增以报告其进度的检查点值
ServiceStatus.dwServiceType = 0;//服务类型
ServiceStatus.dwWaitHint = 0;//将要进行 开始、停止、暂停或继续服务 操作所需的估计时间 (以毫秒为单位)
//初始化结束之后,开始第二步操作,开始注册Handler函数(注册服务控制请求函数)
hStatus = RegisterServiceCtrlHandler("Demo",(LPHANDLER_FUNCTION)ServiceHandler);//注册服务控制请求函数
if (!hStatus)
{
printf("注册服务控制请求函数失败");
system("Pause");
return ;
}
SetServiceStatus(hStatus,&ServiceStatus);//向SCM报告服务状态
//是否设置成功
if (GetLastError != NO_ERROR)
{
//如果失败,重新设置状态为停止
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
printf("设置服务状态失败");
system("pause");
return;
}
//设置成功之后继续运行,这个时候需要通知SCM将服务状态设置为Running状态
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);//服务状态变更之后要重新设置 以通知SCM
//启动服务
StartDestService();
//接下来开始执行服务程序的主要操作
WorkThing();
}
//定义服务控制请求函数
VOID WINAPI ServiceHandler(DWORD dwControl)
{
//实现服务控制请求函数,通过各类请求控制码决定服务做什么操作
switch (dwControl)
{
//服务暂停
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
//服务继续运行
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
//关闭服务(和停止服务走相同的额逻辑)
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);//设置服务状态
//关闭服务和停止服务的时候需要先将服务停止
StopService();
//关闭和停止服务的时候需要同时将服务卸载
UninstallService();
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);//设置服务状态
return;
}
//安装服务的函数
void InstallService()
{
//首先获取当前进程的路径
char PathName[MAX_PATH];
char SysName[MAX_PATH];
GetModuleFileName(NULL,PathName,MAX_PATH);
GetSystemDirectory(SysName, MAX_PATH);
wsprintf(SysName, "%s\\Test.exe", SysName);
if (!MoveFile(PathName, SysName))
{
printf(" Move File Error!\n");
system("pause");
return;
}
SC_Manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!SC_Manager)
{
printf("打开服务控制管理器失败");
system("pause");
return;
}
//c创建目标服务
SC_Service=CreateService(SC_Manager,"Demo","Win32Test", SC_MANAGER_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,SysName,NULL,NULL,NULL,NULL,NULL);
if (!SC_Service)
{
printf("创建服务失败");
}
printf("创建服务成功");
CloseServiceHandle(SC_Service);
CloseServiceHandle(SC_Manager);
}
//卸载服务函数
void UninstallService()
{
SC_Manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!SC_Manager)
{
printf("打开服务控制管理器失败");
system("pause");
return;
}
//打开目标服务
SC_Service = OpenService(SC_Manager, "Demo", SC_MANAGER_ALL_ACCESS);
if (!SC_Service)
{
printf("打开服务失败");
CloseServiceHandle(SC_Manager);
system("pause");
return;
}
if (DeleteService(SC_Service))
{
printf("服务卸载成功");
}
CloseServiceHandle(SC_Service);
CloseServiceHandle(SC_Manager);
return;
}
//停止服务的函数
void StopService()
{
//停止服务的主要思路是,发送控制吗到服务,将服务状态设置为暂停
SC_Manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!SC_Manager)
{
printf("打开服务控制管理器失败");
system("pause");
return;
}
//打开目标服务
SC_Service = OpenService(SC_Manager, "Demo", SC_MANAGER_ALL_ACCESS);
if (!SC_Service)
{
printf("打开服务失败");
CloseServiceHandle(SC_Manager);
system("pause");
return;
}
if (ControlService(SC_Service, SERVICE_CONTROL_STOP, &ServiceStatus))
{
while (QueryServiceStatus(SC_Service, &ServiceStatus))
{
if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
break;
}
CloseServiceHandle(SC_Service);
CloseServiceHandle(SC_Manager);
return;
}
}
//启动服务
void StartDestService()
{
SC_Manager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!SC_Manager)
{
printf("打开服务控制管理器失败");
system("pause");
return;
}
//打开目标服务
SC_Service = OpenService(SC_Manager,"Demo", SC_MANAGER_ALL_ACCESS);
if (!SC_Service)
{
printf("打开服务失败");
CloseServiceHandle(SC_Manager);
system("pause");
return;
}
if (StartService(SC_Service, NULL, NULL))//启动服务,没有参数
{
//启动成功之后查看服务的状态
while (QueryServiceStatus(SC_Service, &ServiceStatus))
{
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
break;
}
printf("服务正常启动");
}
CloseServiceHandle(SC_Service);
CloseServiceHandle(SC_Manager);
return;
}
void WorkThing()
{
return;
}
之后使用命令安装服务
csc create Win32Test bin= "文件目录"
参考链接:
https://www.cnblogs.com/lgxZJ/p/7440116.html
https://www.cnblogs.com/mephisto/p/4142608.html
https://www.cnblogs.com/M-Anonymous/p/9393088.html