gpt4 book ai didi

c++ - 两次调用 EnumServicesStatusEx() 时,我仍然在 C++ 中得到 EROR_MORE_DATA

转载 作者:行者123 更新时间:2023-11-30 02:57:20 27 4
gpt4 key购买 nike

我在我的代码中调用了 EnumServicesStatusEx() 两次,第一次应该失败并将正确的缓冲区大小放入 dwBuffNeeded 中,这样当我第二次调用它时缓冲区大小应该是正确的。但是,有时,在第二次通话后,我并不总是会收到 ERROR_MORE_DATA。任何想法为什么?谢谢

DWORD pId=GetCurrentProcessId();
SC_HANDLE hSCM = NULL;
PUCHAR pBuf = NULL;
ULONG dwBufSize = 0x00;
ULONG dwBufNeed = 0x00;
ULONG dwNumberOfService = 0x00;
LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL;

hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT );

if (hSCM == NULL)
{
GetCustomLog().Log( SV_ERROR, 10004807, "Could not open Service Control Manager: %s", GetLastOSErrorString().c_str() );
return;
}

//Query services once to get correct buffer size, always fails
if ( EnumServicesStatusEx(
hSCM,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32,
SERVICE_ACTIVE,
NULL,
dwBufSize,
&dwBufNeed,
&dwNumberOfService,
NULL,
NULL) == 0 )
{

DWORD err = GetLastError();
if ( ERROR_MORE_DATA == err )
{
dwBufSize = dwBufNeed + 0x10;
pBuf = (PUCHAR) malloc(dwBufSize);

//Query services again with correct buffer size
if ( EnumServicesStatusEx(
hSCM,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32,
SERVICE_ACTIVE,
pBuf,
dwBufSize,
&dwBufNeed,
&dwNumberOfService,
NULL,
NULL ) == 0 )

{
//FAILS HERE
GetCustomLog().Log( SV_ERROR, 10004808, "Could not enumerate services, error: %s", GetLastOSErrorString().c_str() );
free(pBuf);
return;
}
}
else
{
GetCustomLog().Log( SV_ERROR, 10004809, "Could not enumerate services, error: %s", GetLastOSErrorString().c_str() );
return;
}

最佳答案

我也有同样的问题,但在查询 SERVICE_STATE_ALL 时,我认为每次调用都需要相同数量的内存(除非已安装/卸载服务)。仅使用 pcbBytesNeeded 参数中返回大小的缓冲区重试是不够的:

BOOL WINAPI EnumServicesStatusEx(
_In_ SC_HANDLE hSCManager,
_In_ SC_ENUM_TYPE InfoLevel,
_In_ DWORD dwServiceType,
_In_ DWORD dwServiceState,
_Out_opt_ LPBYTE lpServices,
_In_ DWORD cbBufSize,
_Out_ LPDWORD pcbBytesNeeded,
_Out_ LPDWORD lpServicesReturned,
_Inout_opt_ LPDWORD lpResumeHandle,
_In_opt_ LPCTSTR pszGroupName
);

与其他 WIN32 API 调用不同,这不是返回所需字节的绝对数量,而是返回相对于 cbBufSize 参数所需的额外 字节。作为实验,我特意提供了一个较小的缓冲区,并且每次都将其加倍,以找出系统将在 pcbBytesNeeded 中返回什么作为响应。在这个系统上 sizeof(ENUM_SERVICE_STATUS_PROCESS) 是 56 字节。最后一行是导致调用成功的最小缓冲区。

+-----------+----------------+
| cbBufSize | pcbBytesNeeded |
+-----------+----------------+
| 112 | 37158 |
| 224 | 37013 |
| 448 | 36766 |
| 896 | 36374 |
| 1792 | 35280 |
| 3584 | 33202 |
| 7168 | 28972 |
| 14336 | 20765 |
| 28672 | 4215 |
| 32032 | 0 |
+-----------+----------------+

您可以看到每一行粗略地加起来就是所需的缓冲区大小,而且就系统而言,所需的缓冲区大小并不是很容易预测。本例调用成功返回的服务条目数为233条,仅需13048字节。事实证明,ENUM_SERVICE_STATUS_PROCESS lpDisplayName 和 lpServiceName 指针指向的字符串只是存储在所提供缓冲区的尾端(我一直想知道它们的支持在哪里,以及为什么它稳定并且不需要单独存储释放)。无论如何,这解释了有些不确定的响应以及奇数:系统可能有不适合的当前条目,并且确切知道它需要多少大小,但猜测其余部分。

下面的代码是可靠的,通常只需要两次调用,但有时可以调用三次(即使使用 SERVICE_STATE_ALL)。我不知道为什么需要三个,系统的低估一次会持续几分钟,但最终会自行解决。我从未见过它需要四个调用。

int EnumerateAllServices(SC_HANDLE hSCM) {
void* buf = NULL;
DWORD bufSize = 0;
DWORD moreBytesNeeded, serviceCount;
for (;;) {
printf("Calling EnumServiceStatusEx with bufferSize %d\n", bufSize);
if (EnumServicesStatusEx(
hSCM,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32,
SERVICE_STATE_ALL,
(LPBYTE)buf,
bufSize,
&moreBytesNeeded,
&serviceCount,
NULL,
NULL)) {
ENUM_SERVICE_STATUS_PROCESS* services = (ENUM_SERVICE_STATUS_PROCESS*)buf;
for (DWORD i = 0; i < serviceCount; ++i) {
printf("%s\n", services[i].lpServiceName);
}
free(buf);
return 0;
}
int err = GetLastError();
if (ERROR_MORE_DATA != err) {
free(buf);
return err;
}
bufSize += moreBytesNeeded;
free(buf);
buf = malloc(bufSize);
}
}

“+=”是一个“技巧”,并没有非常清楚地记录(但事后看来,我现在理解了 MSDN 对 pcbBytesNeeded 参数的解释中的细微差别):

pcbBytesNeeded [out]

A pointer to a variable that receives the number of bytes
needed to return the remaining service entries, if the buffer
is too small.

关于c++ - 两次调用 EnumServicesStatusEx() 时,我仍然在 C++ 中得到 EROR_MORE_DATA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14756347/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com