在指定的服务控制管理器数据库中枚举服务。
函数原型:
BOOL
WINAPI
EnumServicesStatusExW(
_In_ SC_HANDLE hSCManager,
参数1:服务控制管理器数据库的句柄。该句柄由OpenSCManager函数返回 ,并且必须具有SC_MANAGER_ENUMERATE_SERVICE访问权限。
_In_ SC_ENUM_TYPE InfoLevel,
参数2:要返回的服务属性。使用SC_ENUM_PROCESS_INFO检索数据库中每个服务的名称和服务状态信息。所述lpServices参数是一个指向接收数组的缓冲器 ENUM_SERVICE_STATUS_PROCESS结构。缓冲区必须足够大以容纳结构及其成员指向的字符串。
_In_ DWORD dwServiceType,
参数3:
要枚举的服务类型。此参数可以是以下值中的一个或多个。
价值 | 意义 |
---|---|
|
类型为SERVICE_KERNEL_DRIVER和SERVICE_FILE_SYSTEM_DRIVER的服务。 |
|
文件系统驱动程序服务。 |
|
驱动服务。 |
|
类型为SERVICE_WIN32_OWN_PROCESS和SERVICE_WIN32_SHARE_PROCESS的服务。 |
|
在自己的进程中运行的服务。 |
|
与一个或多个其他服务共享一个流程的服务。有关更多信息,请参见服务程序。 |
_In_ DWORD dwServiceState,
参数4:
要枚举的服务状态。此参数可以是以下值之一。
价值 | 意义 |
---|---|
|
枚举处于以下状态的服务:SERVICE_START_PENDING,SERVICE_STOP_PENDING,SERVICE_RUNNING,SERVICE_CONTINUE_PENDING,SERVICE_PAUSE_PENDING和SERVICE_PAUSED。 |
|
枚举处于SERVICE_STOPPED状态的服务。 |
|
合并SERVICE_ACTIVE和SERVICE_INACTIVE状态。 |
_Out_writes_bytes_opt_(cbBufSize) LPBYTE lpServices,
参数5:指向接收状态信息的缓冲区的指针。该数据的格式取决于InfoLevel参数的值。该数组的最大大小为256K字节。若要确定所需的大小,请为此参数指定NULL,为cbBufSize参数指定0 。该函数将失败,并且GetLastError将返回ERROR_MORE_DATA。该pcbBytesNeeded参数将接收到所需的大小。
_In_ DWORD cbBufSize,
参数6:lpServices参数指向的缓冲区大小,以字节为单位。
_Out_ LPDWORD pcbBytesNeeded,
参数7:如果缓冲区太小,则指向变量的指针,该变量接收返回剩余服务条目所需的字节数。
_Out_ LPDWORD lpServicesReturned,
参数8:指向一个变量的指针,该变量接收返回的服务条目数。
_Inout_opt_ LPDWORD lpResumeHandle,
参数9:指向变量的指针,该变量在输入时指定枚举的起点。您必须在第一次调用EnumServicesStatusEx函数时将此值设置为零 。在输出中,如果函数成功,则该值为零。但是,如果函数返回零,并且 GetLastError函数返回ERROR_MORE_DATA,则此值指示调用EnumServicesStatusEx函数以检索其他数据时要读取的下一个服务条目 。
_In_opt_ LPCWSTR pszGroupName
参数10:加载顺序组名称。如果此参数是字符串,则枚举的唯一服务是属于具有由字符串指定的名称的组的服务。如果此参数为空字符串,则仅枚举不属于任何组的服务。如果此参数为NULL,则将忽略组成员身份,并枚举所有服务。
);
示例:
#include <stdio.h> #include <Windows.h> #include <locale.h> int main(int argc, char* argv[]) { HANDLE handle_service_manager = 0; int return_value = 0; unsigned char* service_status_process = NULL; DWORD buffer_size = 0; DWORD bytes_needed = 0; DWORD services_returned = 0; ENUM_SERVICE_STATUS_PROCESS* enmu_service_status_process; setlocale(LC_ALL, "chs"); do { handle_service_manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (handle_service_manager == NULL) { printf("OpenSCManager Error:%d\n", GetLastError()); break; } return_value = EnumServicesStatusExW( handle_service_manager, //服务控制管理器数据库的句柄。 SC_ENUM_PROCESS_INFO, //要返回的服务属性。 SERVICE_WIN32, //要枚举的服务类型。 SERVICE_STATE_ALL, //要枚举的服务状态。 NULL, //指向接收状态信息的缓冲区的指针。该数据的格式取决于InfoLevel参数的值。 buffer_size, //lpServices参数指向的缓冲区大小,以字节为单位。 &bytes_needed, //如果缓冲区太小,则指向变量的指针,该变量接收返回剩余服务条目所需的字节数。 &services_returned, //指向一个变量的指针,该变量接收返回的服务条目数。 0, //指向变量的指针,该变量在输入时指定枚举的起点。您必须在第一次调用EnumServicesStatusEx函数时将此值设置为零。 NULL //加载顺序组名称。 ); if (return_value == 0 && GetLastError() != ERROR_MORE_DATA) { printf("get bytes needed faild\n"); break; } printf("bytes_needed:%d\n", bytes_needed); buffer_size = bytes_needed; service_status_process = LocalAlloc(LPTR, buffer_size); if (service_status_process == NULL) { break; } SecureZeroMemory(service_status_process, buffer_size); return_value = EnumServicesStatusExW( handle_service_manager, //服务控制管理器数据库的句柄。 SC_ENUM_PROCESS_INFO, //要返回的服务属性。 SERVICE_WIN32, //要枚举的服务类型。 SERVICE_STATE_ALL, //要枚举的服务状态。 service_status_process, //指向接收状态信息的缓冲区的指针。该数据的格式取决于InfoLevel参数的值。 buffer_size, //lpServices参数指向的缓冲区大小,以字节为单位。 &bytes_needed, //如果缓冲区太小,则指向变量的指针,该变量接收返回剩余服务条目所需的字节数。 &services_returned, //指向一个变量的指针,该变量接收返回的服务条目数。 0, //指向变量的指针,该变量在输入时指定枚举的起点。您必须在第一次调用EnumServicesStatusEx函数时将此值设置为零。 NULL //加载顺序组名称。 ); if (return_value == 0) { printf("EnumServicesStatusExW2 faild:%d\n", GetLastError()); break; } printf("services returned:%d\n\n", services_returned); enmu_service_status_process = (ENUM_SERVICE_STATUS_PROCESS*)service_status_process; for (size_t i = 0; i < services_returned; i++) { printf("ServiceName:%ws\n", enmu_service_status_process[i].lpServiceName); printf("DisplayName:%ws\n", enmu_service_status_process[i].lpDisplayName); printf("ProcessId:%d\n", enmu_service_status_process[i].ServiceStatusProcess.dwProcessId); printf("CurrentState:%d\n\n", enmu_service_status_process[i].ServiceStatusProcess.dwCurrentState); } } while (0); return 0; }
注:遍历多个相同的结构体时可以把结构体看做数组,以数组下标的方式表示。
https://docs.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-enumservicesstatusexw