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<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

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Windows API开发是指利用Windows操作系统提供的一系列函数、接口来进行软件开发的过程。在Windows API开发中,函数是指一组具有特定功能的代码块,通过调用这些函数可以实现相应的操作。接口是一组规定了函数调用方式和参数要求的规范,开发者根据接口规范来编写代码实现具体功能。编程实例则是实际应用Windows API进行开发的案例,可以帮助开发者更好地理解和掌握Windows API的使用。 在Windows API开发中,函数的使用非常重要。常见的函数包括用于窗口创建、消息处理、线程管理、文件操作等等。通过调用这些函数,我们可以实现窗口的创建和管理、消息的处理和分发、线程的创建和管理、文件的读等一系列操作。 接口是函数的集合,它规定了函数的定义和使用方式,以及参数的传递方式等。我们需要了解接口的定义和要求,根据接口规范编写相应的代码实现接口提供的功能。比如,Windows API中的GDI接口提供了一系列函数,可以用于绘制图形、文字等。通过了解GDI接口的规范,我们可以编写代码实现绘制各种图形的功能。 编程实例是一种学习的有效方式,通过实际的案例来演示如何使用Windows API进行开发,可以帮助开发者更好地理解API的使用方法和具体实现。例如,我们可以通过一个窗口程序的编写实例来学习窗口的创建、消息的处理等基本操作。通过编程实例的实践,我们可以加深对Windows API的理解,并能够更加熟练地运用它进行开发。 总之,Windows API开发是一种利用操作系统提供的函数、接口来进行软件开发的方式。在API开发中,函数是实现具体功能的代码块,接口是描述函数调用方式和参数要求的规范。编程实例则帮助开发者更好地掌握API的使用方法和实现技巧。通过深入学习和实践,我们能够更加熟练地使用Windows API进行开发。 ### 回答2: Windows API开发是指利用Windows操作系统提供的应用程序接口(API)来进行软件开发的过程。在Windows API开发中,函数、接口以及编程实例是非常重要的组成部分。 函数是Windows API开发中的基本单位。函数是一段可重复使用的代码,用于执行特定的任务。Windows API提供了大量的函数供开发者使用,这些函数可以用于实现各种功能,比如创建窗口、绘制图形、处理消息等等。开发者可以根据需要选择适合的函数来完成相应的任务。 接口是Windows API开发中定义函数的规范。接口定义了函数的名称、参数以及返回值等信息,开发者在使用函数之前必须先了解接口的相关信息。通过查阅开发文档或者使用开发工具提供的帮助文档,开发者可以获得接口的详细信息,并根据接口的要求来使用函数。 编程实例是Windows API开发中的具体应用案例。通过编程实例,开发者可以了解如何使用Windows API来完成具体的功能。例如,一个窗口管理程序可以通过调用Windows API中的函数来创建、移动、调整窗口大小等操作。编程实例可以帮助开发者更好地理解函数和接口的使用方法,从而提高开发效率。 总之,函数、接口和编程实例是Windows API开发中的重要组成部分。了解函数的功能、接口的规范以及编程实例的具体应用,可以帮助开发者更好地进行Windows API开发,实现各种功能丰富的软件应用。 ### 回答3: Windows API(Application Programming Interface)是一套由微软提供的函数和接口,允许开发者在Windows操作系统上创建应用程序。下面将详细介绍函数、接口和编程实例。 函数在Windows API开发中起到了关键作用。函数是一段经过封装的可重用代码,它们执行特定的任务并返回一个结果。在Windows API开发中,函数用于执行各种操作,例如图形绘制、文件读、网络通信等。开发者可以通过调用这些函数来实现各种功能。 接口也是Windows API开发中非常重要的概念。接口定义了一组规范,规定了函数的使用方式和参数。通过使用接口,开发者可以方便地调用底层的函数,并实现与Windows操作系统的交互。Windows API提供了许多接口,例如图形设备接口(GDI)、用户界面接口(UI)、网络接口等。通过使用这些接口,开发者可以在应用程序中实现各种功能。 编程实例是通过实际的代码示例来演示如何使用函数和接口。例如,要创建一个Windows窗口应用程序,开发者可以使用Windows API中的函数和接口来实现。首先,开发者可以使用CreateWindow函数创建一个窗口,并设置窗口的属性。然后,可以使用SendMessage函数向窗口发送消息,以实现交互功能。最后,通过调用ShowWindow函数显示窗口,使其可见。 总而言之,Windows API是一个强大的开发工具,它提供了丰富的函数和接口,可以帮助开发者创建各种应用程序。通过使用函数和接口,开发者可以实现各种功能,从简单的图形绘制到复杂的网络通信。希望这篇文章对理解Windows API的函数、接口和编程实例有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值