首页  > 02年世界杯巴西

Windows服务二三事——编写Windows服务

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

#include

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