编程控制Windows服务

本文介绍如何通过编程控制Windows服务,包括枚举系统服务、获取服务详细信息及描述、以及服务的状态控制和配置修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一篇我们来介绍如何编程控制Windows服务,主要介绍两方面的内容,一是枚举系统所有服务,二是编程对服务进行控制,下面我们分别进行讲解。

枚举服务

我们主要用到两个函数:EnumServicesStatus和QueryServiceConfig,其中函数EnumServicesStatus可以获取系统中所有服务的基本信息,包括服务名称、显示名称、当前状态,如果想获取更加详细的信息,就需要QueryServiceConfig函数的帮助了,它需要传递一个SC_HANDLE句柄,这个句柄可以用OpenService获得,而OpenService需要的服务名称参数可以通过前面的EnumServicesStatus函数获得,他们配合使用就可以获取非常详尽的信息;相关结构体如下所示,它已经在Windows.h头文件中声明过了,我们可以直接使用:

typedef struct _QUERY_SERVICE_CONFIG {

DWORD dwServiceType;

DWORD dwStartType;

DWORD dwErrorControl;

LPTSTR lpBinaryPathName;

LPTSTR lpLoadOrderGroup;

DWORD dwTagId;

LPTSTR lpDependencies;

LPTSTR lpServiceStartName;

LPTSTR lpDisplayName;

} QUERY_SERVICE_CONFIG, *LPQUERY_SERVICE_CONFIG;

细心的读者可能会看出来,虽然上面的结构已经非常详尽了,但是它好像还是缺少了点什么?对,是服务描述,当我们在Windows的服务管理器中选中某个服务后,就会显示出该服务的相关描述,更好地帮助用户。

那么我们该如何获取服务描述呢?答案是使用QueryServiceConfig2函数,它需要用到一个SERVICE_DESCRIPTION结构(同样不需要我们自己定义),与QueryServiceConfig函数一样,它同样需要一个标明服务的SC_HANDLE句柄作为参数,如下代码显示了获取系统所有服务详细信息的方法:

LPENUM_SERVICE_STATUS st; // 基本信息

LPQUERY_SERVICE_CONFIG sc; // 详细信息

LPSERVICE_DESCRIPTION sd; // 服务描述

DWORD ret = 0;

DWORD size= 0;

char szState[30]; // 状态

char szServiceName[MAX_PATH]; // 名称

char szStartType[30]; // 启动类型

char szApplication[MAX_PATH]; // 应用程序

char szDescription[MAX_PATH*4]; // 服务描述

// 为st分配足够空间

st = (LPENUM_SERVICE_STATUS)LocalAlloc(LPTR,64 * 1024);

HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

EnumServicesStatus(hSCManager,SERVICE_WIN32,SERVICE_STATE_ALL,st,1024 * 64,&size,&ret,NULL);

for(DWORD i = 0; i lpBinaryPathName);

if(sc->dwStartType == SERVICE_AUTO_START)

{

sprintf(szStartType,"自动");

}

else if(sc->dwStartType == SERVICE_DEMAND_START)

{

sprintf(szStartType,"手动");

}

else if(sc->dwStartType == SERVICE_DISABLED)

{

sprintf(szStartType,"已禁用");

}

else

{

sprintf(szStartType," ");

}

// 查询服务描述信息

char temp[1024];

QueryServiceConfig2(hService,SERVICE_CONFIG_DESCRIPTION,(LPBYTE)temp,sizeof(temp),&nRet);

sd = (LPSERVICE_DESCRIPTION)temp;

sprintf(szDescription,"%s",sd->lpDescription);

// 输出到列表框

m_lstService.InsertItem(i, szServiceName, NULL);

m_lstService.SetItemText(i,1, szState);

m_lstService.SetItemText(i,2, szStartType);

m_lstService.SetItemText(i,3, szApplication);

m_lstService.SetItemText(i,4, szDescription);

}

::CloseServiceHandle(hService);

}

::CloseServiceHandle(hSCManager);

上述代码有一个需要注意的地方,在调用EnumServicesStatus时需要分配足够大的空间,本程序是64*1024,而在调用QueryServiceConfig同样要分配足够的空间,但注意,这里不能过大,我起初也是给它分配64*1024,但这里的调用总是失败,百思不得其解,后来偶然才给解决;其实仔细想想也对,前面是需要枚举所有的服务信息,分配的空间当然要大,但后面是单个服务的相信描述,显然用不了那么大的空间。

服务控制

服务控制的函数较多,MSDN里面有很专门的Service Functions,非常详细,因此这里就不再赘述各函数的用法了,至少每个函数的作用,你看下名字就大概知道了,还不知道的就去百度一下。

我们主要用到下面这些函数:OpenSCManager、OpenService、CreateService、StartService、DeleteService、ControlService、ChangeServiceConfig等函数。其中需要注意的几点是:(1)StartService可以用来启动一个服务,但并没有相应的暂停、停止服务函数,除了启动之外的操作都需要调用ControlService函数,通过向其发送一个控制码来使系统改变服务状态;(2)在修改服务配置时,需要首先调用LockServiceDatabase锁定数据库,以免多个线程同时操作而引起不可预料的后果,当然在修改完毕后别忘了调用UnlockServiceDatabase进行解锁。下面是我写的一个服务管理函数:

//

// 服务控制函数

//

// 参数flag1控制服务状态,0-忽略,1-启动,2-停止

//

// 参数flag2控制启动类型,0-忽略,1-自动,2-手动,3-禁用

//

// 运行成功返回TRUE,否则返回FALSE

//

BOOL CDlgService::ControlService(const char *szServiceName,int flag1, int flag2)

{

HANDLE hSCManager = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

if(!hSCManager)

{

MessageBox("OpenSCManager Error!");

return FALSE;

}

SC_HANDLE hService = ::OpenService(hSCManager,szServiceName,SERVICE_ALL_ACCESS);

if(!hService)

{

MessageBox("OpenService Error!");

return FALSE;

}

// 改变服务状态

if(flag1 != 0)

{

// 查询服务状态

SERVICE_STATUS status;

::QueryServiceStatus(hService,&status);

if((flag1 == 1) && (status.dwCurrentState != SERVICE_RUNNING)) // 启动服务

{

if(!(::StartService(hService,NULL,NULL)))

return FALSE;

}

if((flag1 == 2) && (status.dwCurrentState != SERVICE_STOPPED)) // 停止服务

{

if(!(::ControlService(hService,SERVICE_CONTROL_STOP,&status)))

return FALSE;

}

}

// 配置服务启动方式

if(flag2 != 0)

{

// 锁定

SC_LOCK sclLock;

sclLock = LockServiceDatabase(hSCManager);

if (sclLock == NULL)

{

MessageBox("LockServiceDatabase Error!");

return FALSE;

}

DWORD dwStartType;

switch(flag2)

{

case 1:

dwStartType = SERVICE_AUTO_START;

break;

case 2:

dwStartType = SERVICE_DEMAND_START;

break;

case 3:

dwStartType = SERVICE_DISABLED;

break;

default:

return FALSE;

}

if(!ChangeServiceConfig(hService,SERVICE_NO_CHANGE,dwStartType,SERVICE_NO_CHANGE,NULL,NULL,NULL,NULL,NULL,NULL,NULL))

{

UnlockServiceDatabase(sclLock);

return FALSE;

}

// 解锁

UnlockServiceDatabase(sclLock);

}

::CloseServiceHandle(hService);

::CloseServiceHandle(hSCManager);

return TRUE;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值