服务是一种在操作系统启动时就启动的进程。在操作系统启动时有两种程序会一起随着系统启动,一种是普通的Win32程序,另一种是驱动程序。这里讨论的并不是要如何编写一个系统的服务,而是编写一个如何可以显示出这些随系统启动而启动的服务项。
一、如何查看系统服务
在Windows下,有很多服务是跟随操作系统一起进行启动的,具体有哪些服务是跟随操作系统一起启动的呢?如何查看呢?其实非常得简单。在“我的电脑”上单击鼠标右键,然后在弹出的菜单上选择“管理”命令会打开“计算机管理”工具,单击左侧树形列表中的“服务和应用程序”会出现一个列表,选择“服务”则在右侧出现了服务项列表,如图1所示。
图1 Windows下的服务管理程序
在这个列表中,只能查看到Win32应用程序的服务,无法查看关于驱动程序的服务。我们可以借助其他一些小工具来查看驱动服务的程序,如图2所示。
图2 使用SREng查看驱动服务程序列表
接下来编写一个程序,既可以查看应用程序服务列表,也可以查看驱动程序服务列表。编写的程序如图3所示。
图3 服务管理程序的界面
这个服务控制管理器依然是使用MFC的对话框进行开发的,其中还是用到了CListCtrl这个控件。让我们现在就动手开始打造一个自己的服务控制管理器吧。
二、服务控制管理器的开发
服务控制管理器的开发和注册表启动管理器的开发是差不多的,主要也是枚举服务并将其显示到列表控件中。至于对服务状态的控制,是通过服务相关的API函数来完成的。这次,我们先来看代码,希望通过阅读代码大家能自己掌握与服务相关的API函数。在代码的后面,会对开发服务控制管理器涉及到的API进行相应的解释。
学习API函数的使用,最好的老师是MSDN。在大家学习编程的道路上,要通过阅读大量的代码来提高自己的编程能力,那时大家就要自行学习API函数的使用,因此希望大家能养成好的学习习惯,也就是自己能够独立查阅MSDN来进行API函数的使用。
我们要枚举的服务分为“Win32服务应用程序”和“驱动程序”两类。对于枚举这两类服务,只是枚举函数的参数有所不同,这个函数参数是系统定义的两个常量,定义分别如下:
看一下服务枚举时的代码:
该成员函数有一个参数,这个参数就是用来指明是枚举“Win32应用程序服务”,还是用来枚举“驱动程序服务”的。也就是我们前面提到的两个系统定义的常量了,参数根据两个常量的不同,枚举到的服务也不同。
三、枚举服务的相关API函数
打开服务管理器:
参数说明如下。
(1)lpMachineName:指向欲打开服务控制管理器数据库的目标主机名,本机则设置为NULL。
(2)lpDatabaseName:指向了目标主机SCM数据库名字的字符串。
(3)dwDesiredAccess:指定对SCM数据库的访问权限。
这里介绍一下,SCM是服务控制管理器的意思,它是系统服务的一个组成部分,跟我们开发的软件不是一个概念。由于我们不是编写一个具体的服务,而只是对系统现有的服务进行一个枚举,因此,一些概念性的知识希望大家可以自行查阅相关的资料。
该函数调用成功,返回一个SCM句柄,否则返回NULL。
关闭服务句柄:
该函数用来关闭OpenSCManager()和OpenService()打开的句柄。
枚举服务:
参数说明如下。
(1)hSCManager:OpenSCManager()函数返回的句柄。
(2)dwServiceType:指定枚举的服务类型,也就是我们自定义函数的那个参数。
(3)dwServiceState:枚举指定状态的服务。
(4)lpService:指向ENUM_SERVICE_STATUS类型的指针。
(5)cbBufSize:指定缓冲区的大小。
(6)pcbBytesNeeded:返回实际使用的内存空间大小。
(7)lpServicesReturn:返回枚举服务的个数。
(8)lpResumeHandle:返回枚举是否成功。
四、服务的停止
对于枚举到的服务,对我们来说只有两种操作,一种是启动服务,另一种是停止服务。系统中有很多我们不用的服务,它会随着电脑的启动而启动,这样既会影响系统的启动速度,也会占用宝贵的系统资源,因此,没用的系统服务要停掉。先来看看停止系统服务的代码。
五、停止服务的相关API函数
打开服务函数:
参数说明如下。
(1)hSCManager:指定由OpenSCManager()函数打开的服务句柄。
(2)lpServiceName:指向要打开的服务的名称。
(3)dwDesiredAccess:对要打开服务的访问权限。
控制服务函数:
参数说明如下。
(1)hService:指定一个由OpenService()打开的服务句柄。
(2)dwControl:指定了要发送的控制码,ControlService()可以对服务进行多种控制,每种控制对应一种控制码。
(3)lpServiceStatus:用于返回服务的状态。
六、服务的启动
启动服务的代码与停止服务的代码类似。这里简单地给出启动服务的部分代码,具体的代码自己动手写写。启动服务的部分代码如下:
启动服务相关API函数解释:
参数说明如下。
(1)hService:指定了要启动服务的句柄。
(2)dwNumServiceArgs:指向了启动服务所需的参数个数。
(3)lpServiceArgVectors:指向了启动服务的参数。
该函数最后两个参数类似main(int argc, char *argv[])中的两个参数的作用。