服务控制程序

点击打开原文链接

一:服务控制程序概要

服务控制程序的编写与标准的Windows应用程序无异,它要用到服务管理函数,如:OpenSCManagerOpenServiceQueryServiceConfigStartServiceQueryServiceStatusControlService等;它都在系统的advapi32.dll中实现。在使用SCM的函数时,SCP必须要首先调用OpenSCManager函数,打开一个通向SCM的通道。调用这个函数的时候,SCP还必须指定它想要执行的动作类型;也就是dwDesiredAccess参数它的取值:

SC_MANAGER_ALL_ACCESS、
SC_MANAGER_CREATE_SERVICE、
SC_MANAGER_ENUMERATE_SERVICE、
SC_MANAGER_QUERY_LOCK_STATUS、
SC_MANAGER_ENUMERATE_SERVICE 、
SC_MANAGER_QUERY_LOCK_STATUS、
SC_MANAGER_LOCK、
SC_MANAGER_CONNECT。
例如:我们要枚举当前所有的服务就必须给dwDesiredAccess参数指定SC_MANAGER_ENUMERATE_SERVICE;同时也可以指定其它的值,当指写多个值时我们要把它用按位或(|)符号连接起来。
 
与此同时我们在调用OpenService时也必须告知SCM我们要对服务进行的动作;它有三个参数,最后一个参数dwDesiredAccess指出要对服务进行的操作,这些操作的标记与CreateService中的dwDesiredAccess参数标记值一样。当我们以SERVICE_ALL_ACCESS访问权限打开服务后就可以对它进行配置(QueryServiceConfig)、控制(ControlService)、查询状态(QueryServiceStatus)、设置状态(SetServiceStatus)、删除(DeleteService)等所有访问操作。
 
下面我们可以来看两服务控制的实例。
二:枚举服务

我们先来看EnumDependentStatus函数原型:

BOOL EnumServicesStatus (
SC_HANDLE hService,    // SCM控制句柄
DWORD dwServiceType,   // 要枚举服务还有驱动
DWORD dwServiceState,  // 要枚举什么状态的服务
LPENUM_SERVICE_STATUS lpServices,//存储枚举出服务的内存地址
DWORD cbBufSize,      // lpServices指向内存区大小
LPDWORD pcbBytesNeeded, //实际需要的内存大小
LPDWORD lpServicesReturned //返回枚举到服务年个数
LPDWORD lpResumeHandle //指向下一个有效的入口
);
dwServiceState参数由:SERVICE_ACTIVE、SERVICE_INACTIVE、SERVICE_STATE_ALL三种值分别枚举当前活动、不活动、全部的服务。
函数会返回一个ENUM_SERVICE_STATUSDE数组,ENUM_SERVICE_STATUS有三个域分别指出服务的服务名、显示名和当前状态一个指针;我们可以根据服务名打开枚举出的服务,以得到它更加详细的信息。
 
下面具体让我们看一段程序的例子。
//清空服务信息队列
DeletItemAll();
 
LPENUM_SERVICE_STATUS st=NULL;
st=NULL;
DWORD ret=0;
DWORD size=0;
ServiceInfo info;
SC_HANDLE sc=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
SC_HANDLE sh;
char* szInfo[1024*8];
DWORD dwSize=1024*8;
CString str;
//第一次调用来得到需要多大的内存区
EnumServicesStatus(sc,SERVICE_WIN32,SERVICE_STATE_ALL,st,size,&size,&ret,NULL);
//申请需要的内存
st=(LPENUM_SERVICE_STATUS)LocalAlloc(LPTR,size);
EnumServicesStatus(sc,SERVICE_WIN32,SERVICE_STATE_ALL,st,size,&size,&ret,NULL);
//开始记录枚举出服务的信息
for(DWORD i=0;i<ret;i++){< span="" style="word-wrap: break-word;">
     dwSize=1024*8;
     ZeroMemory(szInfo,dwSize);
     info.Name.Format("%s",st[i].lpDisplayName);
     info.serviceNmae.Format("%s",st[i].lpServiceName);
     info.State.Format("%d",st[i].ServiceStatus.dwCurrentState);
     sh=OpenService(sc,st[i].lpServiceName,SERVICE_ALL_ACCESS);
     //得到服务描述信息
     QueryServiceConfig2(sh,SERVICE_CONFIG_DESCRIPTION,(LPBYTE)szInfo,dwSize,&dwSize);
     info.Desc.Format("%s",((LPSERVICE_DESCRIPTION)szInfo)->lpDescription);
     //得到服务的启动账户名
     ZeroMemory(szInfo,dwSize);
     dwSize=1024*8;
     QueryServiceConfig(sh,(LPQUERY_SERVICE_CONFIG)szInfo,dwSize,&dwSize);
     info.LoginUser.Format("%s",((LPQUERY_SERVICE_CONFIG)szInfo)->lpServiceStartName);
     CloseServiceHandle(sh);
     //添加到信息队列中
     ItemAdd(&info);
}
CloseServiceHandle(sc);
return TRUE;

上面程序中用到了两个查询服务当前配置的函数QueryServiceConfig2和QueryServiceConfig。它们有所不同是QueryServiceConfig2可以通过设置第二个参数是SERVICE_CONFIG_DESCRIPTION还是SERVICE_CONFIG_FAILURE_ACTIONS来得到服务的描述信息和失败的活动;而QueryServiceConfig则查询返回一个QUERY_SERVICE_CONFIG结构,这个结构存储了服务的类型、启动类型、错误控制标记、服务文件所在路径、显示名等信息详细可以查看MSDN。与这个两函数相对应还有两个配置函数ChangeServiceConfig2和ChangeServiceConfig。

它们的具体使用方法我们来看下面的这段程序。

三:配置服务
bool RegterService(char* pszServiceName,
                      char* pszDisplayName,
                      char* pszServicePath,
                      char* pszDescription)
{
     SC_HANDLE newService,scm;
     BOOL success = FALSE;
     SERVICE_STATUS status;
     SERVICE_DESCRIPTION description;
 
     if (pszDisplayName==NULL&&pszServiceName==NULL&&pszServicePath==NULL)
     {
         return false;
     }
     description.lpDescription=pszDescription;
     scm = OpenSCManager(NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE|SC_MANAGER_CREATE_SERVICE);
     if (!scm){
         OUT_DEBUG("OpenSCManager ERROR!");
         return false;
     }
     newService = CreateService(scm,pszServiceName,pszDisplayName,
         SERVICE_ALL_ACCESS|SERVICE_STOP,SERVICE_WIN32_OWN_PROCESS,
         SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,pszServicePath,
         0,0,0,0,0);
     if (!newService){
         OUT_DEBUG("CreateService ERROR!");
          CloseServiceHandle(scm);
         return false;
     }
     if (description.lpDescription!=NULL)
     {
         success=ChangeServiceConfig2(newService,
                       SERVICE_CONFIG_DESCRIPTION,
                       &description);
     }
     success = QueryServiceStatus(newService,&status);
     if (!success){
         cout<<"QueryServiceStatus ERROR:"<<getlasterror()<<endl;< span="" style="word-wrap: break-word;">
         CloseServiceHandle(newService);
         CloseServiceHandle(scm);
         return false;
     }
     if (status.dwCurrentState!=SERVICE_RUNNING)
     {
         success = StartService(newService,NULL,NULL);
         if (!success){
              cout<<"ControlService ERROR:"<<getlasterror()<<endl;< span="" style="word-wrap: break-word;">
              CloseServiceHandle(newService);
              CloseServiceHandle(scm);
              return false;
         }
     }
     CloseServiceHandle(newService);
     CloseServiceHandle(scm);
     return true;
}
 
ChangeServiceConfig函数可以配置更多关于服务的信息,下面列出其原型:
BOOL ChangeServiceConfig(
SC_HANDLE hService     //打开服务时返回的句柄
DWORD dwServiceType,   //服务的类型
DWORD dwStartType,     //何时启动服务
DWORD dwErrorControl, //错误控制代码
LPCTSTR lpBinaryPathName, //服务的路径
LPCTSTR lpLoadOrderGroup,//服务所属的组
LPDWORD lpdwTagId,     //服务的标记
LPCTSTR lpDependencies, //依赖的其它服务和组
LPCTSTR lpServiceStartName,//服务的启动用户
LPCTSTR lpPassword,  //服务启动用户的密码
LPCTSTR lpDisplayName      //服务的显示名
);

它主要在服务安装完成后,需要对服务的配置进行修改时调用,除了lpDisplayName改变时需要服务停止才能生效外,其它都可以运行时动态改变;

四:控制服务

有时我们要根据实际情况启动、暂停、停止一个服务。在3中的程序示例里面就一个启动服务的调用。这里我们再简单介绍一下这个函数:

BOOL StartService(
    SC_HANDLE hService,        //打开服务时返回的句柄
    DWORD dwNumServiceArgs,    //服务程序参数的个数
    LPCTSTR *lpServiceArgVectors //存放服务程序参数的数组
);
当服务程序需要配置启动参数时就需要使用 StartService后面的两个参数,服务程序的入口函数也就可以接到相关的>参数了。函数调用成功时返回非零,当返回零时调用失败;更详细的出错信息可以调用GetLastError获得。
启动后如果我们还要控制其暂停、继续、停止的话,还需要另一个函数调用来完成。在上面删除服务的例示程序片段中我们调用了 ControlService函数来停止服务,下面我们介绍一下它的详细信息:
BOOL ControlService(
SC_HANDLE hService, //打开服务时返回的句柄
DWORD  dwControl,  //控制代码
LPSERVICE_STATUS lpServiceStatus //服务的状态
);

调用此函数会把控制代码发给指定服务程序的Handler处理函数同时返回服务的状态,服务程序得到相应的控制代码后根据协议要执行相应的操作;控制代码就是Handler规定响应的所有代码。我们不能启动和停止服务安全描述符不允许的服务程序。默认的安全描述符只允许LocalSystem、 Administrators和 Power Users来启动和停止服务程序。服务的安全描述符来用SetServiceObjectSecurity来设置。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值