枚举服务状态EnumServicesStatusExW

在指定的服务控制管理器数据库中枚举服务。

函数原型:
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:
要枚举的服务类型。此参数可以是以下值中的一个或多个。

表1
价值 意义
SERVICE_DRIVER
0x0000000B
类型为SERVICE_KERNEL_DRIVERSERVICE_FILE_SYSTEM_DRIVER的服务
SERVICE_FILE_SYSTEM_DRIVER
0x00000002
文件系统驱动程序服务。
SERVICE_KERNEL_DRIVER
0x00000001
驱动服务。
SERVICE_WIN32
0x00000030
类型为SERVICE_WIN32_OWN_PROCESSSERVICE_WIN32_SHARE_PROCESS的服务
SERVICE_WIN32_OWN_PROCESS
0x00000010
在自己的进程中运行的服务。
SERVICE_WIN32_SHARE_PROCESS
0x00000020
与一个或多个其他服务共享一个流程的服务。有关更多信息,请参见服务程序

_In_ DWORD dwServiceState,
参数4:
要枚举的服务状态。此参数可以是以下值之一。

表2
价值 意义
SERVICE_ACTIVE
0x00000001
枚举处于以下状态的服务:SERVICE_START_PENDINGSERVICE_STOP_PENDINGSERVICE_RUNNINGSERVICE_CONTINUE_PENDINGSERVICE_PAUSE_PENDINGSERVICE_PAUSED
SERVICE_INACTIVE
0x00000002
枚举处于SERVICE_STOPPED状态的服务。
SERVICE_STATE_ALL
0x00000003
合并SERVICE_ACTIVESERVICE_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