NetWkstaUserEnum中resumeHandle失效致循环卡死问题排查
问题根源与解决办法
为什么会死循环?因为NetWkstaUserEnum根本不支持分页
你踩的坑是对这个函数的行为误解了——NetWkstaUserEnum不支持通过resumeHandle分页枚举,这个参数是系统保留的,实际调用时会被直接忽略。
当你把dwPrefMaxLen设成100这种小值时,函数并不会返回部分结果并更新resumeHandle等你下次接着取。要么系统能分配足够内存一次性返回所有用户,返回NERR_Success;要么内存不够直接报错,根本不会返回ERROR_MORE_DATA。
你的代码里,就算函数真返回了ERROR_MORE_DATA,因为resumeHandle被忽略,下次调用还是从头开始枚举,每次都拿到相同的列表,自然死循环。
怎么解决?
办法1:直接用MAX_PREFERRED_LENGTH
如果内存占用在可接受范围内,直接把dwPrefMaxLen设为MAX_PREFERRED_LENGTH,让函数一次性返回所有结果,同时把resumeHandle设为NULL(符合函数要求):
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; // ... nStatus = NetWkstaUserEnum( pszServerName, dwLevel, (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, NULL); // 保留参数必须传NULL
办法2:换用支持分页的函数
如果必须分页获取,就别用NetWkstaUserEnum了,改用NetSessionEnum——这个函数支持通过resumeHandle分页枚举会话,你可以从会话信息里提取登录用户。举个简单的例子:
LPSESSION_INFO_10 pBuf = NULL; DWORD dwResumeHandle = 0; do { nStatus = NetSessionEnum(pszServerName, NULL, NULL, 10, (LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); if (nStatus == NERR_Success || nStatus == ERROR_MORE_DATA) { LPSESSION_INFO_10 pTmp = pBuf; for (DWORD i = 0; i < dwEntriesRead; i++) { wprintf(L"\t-- %s\n", pTmp->sesi10_username); pTmp++; } NetApiBufferFree(pBuf); } } while (nStatus == ERROR_MORE_DATA);
最后说一句
这不是Windows的bug,是NetWkstaUserEnum的设计就是这样——它本来就是用来一次性获取当前工作站所有登录用户的,根本没做分页的支持。你的循环逻辑依赖ERROR_MORE_DATA,但这个函数不会按你预期的触发这个返回值,自然出问题。
内容的提问来源于stack exchange,提问作者Stefano Balzarotti
相关产品推荐
相关产品推荐

