本文主要介绍基于控制台的服务程序控制程序的编写,主要完成创建、启动、停止、卸载等功能,读者可自行添加功能。
首先来介绍需要用到的几个主要的函数。
1. SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess)
OpenSCManager 函数打开指定计算机上的service control manager database(WINNT通过一个名为service control manager database的数据库来管理所有的Service,因此对Service的任何操作都应打开此数据库。)。
其中参数lpMachineName指定计算机名,若为空则指定为本机。
LpDatabaseName为指定要打开的service control manager database名, 默认为空。
dwDesiredAccess指定操作的权限, 可以为下面取值之一:
SC_MANAGER_ALL_ACCESS //所有权限
SC_MANAGER_CONNECT //允许连接到service control manager database
SC_MANAGER_CREATE_SERVICE //允许创建服务对象并把它加入database
SC_MANAGER_ENUMERATE_SERVICE //允许枚举database 中的Service
SC_MANAGER_LOCK //允许锁住database
SC_MANAGER_QUERY_LOCK_STATUS //允许查询database的封锁信息
如果函数成功,返回值是一个句柄指定的服务控制管理器数据库。如果函数失败,返回值为NULL 。要获得扩展错误信息,请使用GetLastError 获得错误代码。
例: SC_HANDLE sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
2.SC_HANDLE CreateService(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPCTSTR lpDisplayName,
DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl,
LPCTSTR lpBinaryPathName,
LPCTSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword)
CreatService函数产生一个新的SERVICE。其中参数hSCManager为指向service control manager database 的句柄,由OpenSCManager返回。LpServiceName为SERVICE的名字,lpDisplayName为Service显示用名,dwDesiredAccess是访问权限,本程序中用SERVICE_ALL_ACCESS。wServiceType,指明SERVICE类型,本程序中用SERVICE_WIN32_OWN_PROCESS| SERVICE_INTERACTIVE_PROCESS。dwStartType为Service启动方式,本程序采用自启动,即dwStartType等于SERVICE_AUTO_START。 dwErrorControl说明当Service在启动中出错时采取什么动作,本程序采用SERVICE_ERROR_IGNORE即忽约错误,读者可以改为其他的。LpBinaryPathName指明Service本体程序的路径名。剩下的五个参数一般可设为NULL。如函数调用成功则返回这个新Service的句柄,失败则返回NULL。与此函数对应的是DeleteService( hService),它删除指定的Service。
例: CreateService(sc,TEXT(SERVICENAME),TEXT(SERVICENAME),SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,TEXT(SERVICEPATH),NULL,NULL,NULL,NULL,NULL )
3. SC_HANDLE OpenService(SC_HANDLE hSCManager,LPCTSTR lpServiceName, DWORD dwDesiredAccess )
函数调用成功则返回打开的Service句柄,失败则返回NULL。
例:OpenService(sc,TEXT(SERVICENAME),SERVICE_ALL_ACCESS);
4. BOOL
StartService( SC_HANDLE hService, DWORD dwNumServiceArgs,LPCTSTR *lpServiceArgVectors )
StartService函数启动指定的Service。其中参数hService 为指向Service的句柄,由OpenService返回。dwNumServiceAr为启动服务所需的参数的个数。lpszServiceArgs 为启动服务所需的参数。若服务没有参数可分别设为0和NULL。
函数执行成功则返回True, 失败则返回False。
例:StartService(service,0,NULL)
5.BOOL
ControlService(SC_HANDLE hService DWORD dwControl,LPSERVICE_STATUS lpServiceStatus )
Service程序没有专门的停止函数,而是用ControlService函数来控制Service的暂停、继续、停止等操作。参数dwControl指定发出的控制命令,可以为以下几个值:
SERVICE_CONTROL_STOP //停止Service
SERVICE_CONTROL_PAUSE //暂停Service
SERVICE_CONTROL_CONTINUE //继续Service
SERVICE_CONTROL_INTERROGATE //查询Service的状态
SERVICE_CONTROL_SHUTDOWN //让ControlService调用失效
参数lpServiceStatus是一个指向SERVICE_STATUS的指针。SERVICE_STATUS是一个比较重要的结构,它包含了Service的各种信息,如当前状态、可接受何种控制命令等等。
函数执行成功则返回True, 失败则返回False。
例:SERVICE_STATUS ServiceStatus;
ControlService(service, SERVICE_CONTROL_STOP,&ServiceStatus)
6.BOOL
QueryServiceStatus( SC_HANDLE hService,LPSERVICE_STATUS lpServiceStatus )
QueryServiceStatus函数比较简单,它查询并返回当前Service的状态。
例: QueryServiceStatus(service,&ServiceStatus);
if(ServiceStatus.dwCurrentState== SERVICE_RUNNING) //正在运行
{
//do something
}
if(ServiceStatus.dwCurrentState==SERVICE_STOPPED ) //停止
{
//do something
}
编制一个Service一般需要两个程序,一个是Service本体,一个是用于对Service进行控制的控制程序。 对于Service本体程序的编写本文不再介绍,上一篇文章有详细介绍。下面看看控制程序的完整源代码。
#include <stdio.h>
#include <windows.h>
#define SERVICENAME "UDPserver"
#define SERVICEPATH "C:\\UDPservice\\UDPservice.exe"
void menu();
int main()
{
SC_HANDLE sc,service;
sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
SERVICE_STATUS ServiceStatus;
int num = 1;
while(num)
{
menu();
scanf("%d",&num);
switch (num)
{
case 1:
{
if(CreateService(sc,TEXT(SERVICENAME),TEXT(SERVICENAME),
SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS| SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START,SERVICE_ERROR_IGNORE,TEXT(SERVICEPATH),
NULL,NULL,NULL,NULL,NULL )== NULL)
{
CloseServiceHandle(sc);
printf("创建失败!\n");
return -1;
}
else
{
printf("创建成功!\n");
}
break;
}
case 2:
{
service = OpenService(sc,TEXT(SERVICENAME),SERVICE_ALL_ACCESS);
if( service == NULL)
{
printf("%d",GetLastError());
CloseServiceHandle(sc);
printf("打开失败!\n");
return -1;
}
else
{
if(StartService(service,0,NULL))
{
printf("启动成功!\n");
}
else
{
printf("启动失败!\n");
CloseServiceHandle(service);
CloseServiceHandle(sc);
return -1;
}
}
break;
}
case 3:
{
if(ControlService(service, SERVICE_CONTROL_STOP,&ServiceStatus))
{
printf("停止成功!\n");
}
else
{
printf("停止失败!\n");
CloseServiceHandle(sc);
return -1;
}
break;
}
case 4:
{
if(DeleteService(service))
{
printf("卸载成功!\n");
}
else
{
printf("卸载失败!\n");
CloseServiceHandle(sc);
return -1;
}
break;
}
default:
{
printf("请输入 0-5 之间的数字!\n");
break;
}
}
}
CloseServiceHandle(sc);
return 0;
}
void menu()
{
printf("*************欢迎使用UDPservice Control************\n");
printf("请选择要执行的功能:\n");
printf("1.创建UDPservice \n");
printf("2.启动UDPservice \n");
printf("3.停止UDPservice \n");
printf("4.卸载UDPservice \n");
printf("0.退出程序 \n");
printf("请选择:");
}