长目录路径下SetupGetInfFileList返回ERROR_INSUFFICIENT_BUFFER的问题咨询
长目录路径下SetupGetInfFileList返回ERROR_INSUFFICIENT_BUFFER的解决方法
核心问题定位
从当前代码运行表现(第一次调用就返回122错误、RequiredSize返回0)可以拆解出三个叠加的问题:
- 没有把缓冲区探测阶段返回的ERROR_INSUFFICIENT_BUFFER(错误码122)识别为预期行为,直接被通用错误分支拦截,导致拿不到接口返回的缓冲区大小值
- 旧版SetupAPI对超过MAX_PATH长度的长路径支持不完善,无法正确计算需要的缓冲区长度,就会出现RequiredSize返回0的异常表现
- 代码中存在变量名不匹配的隐患:分配内存时引用的
dwRequiredSize和前面定义的RequiredSize不是同一个变量,后续运行还会触发其他异常
具体Workaround实现
1. 修正第一次调用的错误处理逻辑
调整错误分支的判断逻辑,单独识别缓冲区不足的预期返回,不要直接抛出通用错误码:
TCHAR *aBuffer = NULL; DWORD BufferSize = 0, RequiredSize = 0; DWORD lastError = 0; // 第一次调用做缓冲区探测 BOOL bError = SetupGetInfFileList(DirectoryPath, INF_STYLE_WIN4, NULL, BufferSize, &RequiredSize); lastError = GetLastError(); if (!bError) { if (lastError == ERROR_ACCESS_DENIED) { return RESULT2(ERR_SUCCESS); } // 关键:单独识别ERROR_INSUFFICIENT_BUFFER(122),不走到通用错误分支 if (lastError != ERROR_INSUFFICIENT_BUFFER) { return RESULT2(ERR_INI_FILELIST); } // 兼容长路径下RequiredSize返回0的异常,设置兜底初始大小 if (RequiredSize == 0) { RequiredSize = MAX_PATH * 4; } }
2. 对超长路径做长路径前缀兼容处理
旧版SetupAPI没有开启长路径感知时,无法识别超过MAX_PATH的目录路径,需要手动给路径补上长路径标记,绕过路径长度校验:
TCHAR longDirBuffer[MAX_PATH * 4] = {0}; // 仅当路径长度接近MAX_PATH、且没有已带长路径前缀时做处理 if (_tcslen(DirectoryPath) >= MAX_PATH && _tcsncmp(DirectoryPath, _T("\\\\?\\"), 4) != 0) { // UNC网络路径的特殊前缀处理 if (_tcsncmp(DirectoryPath, _T("\\\\"), 2) == 0) { _stprintf_s(longDirBuffer, _countof(longDirBuffer), _T("\\\\?\\UNC\\%s"), DirectoryPath + 2); } else { // 本地路径的常规长路径前缀 _stprintf_s(longDirBuffer, _countof(longDirBuffer), _T("\\\\?\\%s"), DirectoryPath); } // 后续全部用兼容处理后的路径做接口入参 DirectoryPath = longDirBuffer; }
3. 修正内存分配与第二次调用的传值逻辑
匹配变量名的同时,针对长路径下可能出现的缓冲区大小不准的问题,加上兜底重试机制:
// 修正变量名不匹配问题,按TCHAR单元计算分配大小 aBuffer = (TCHAR *)LocalAlloc(LPTR, RequiredSize * sizeof(TCHAR)); if (aBuffer == NULL) { return RESULT2(ERROR_MEMORY_EXCEPTION); } // BufferSize需要传入缓冲区的TCHAR数量,和接口要求的参数粒度匹配 BufferSize = RequiredSize; // 第二次调用传入实际分配的缓冲区 BOOL aError = SetupGetInfFileList(DirectoryPath, INF_STYLE_WIN4, aBuffer, BufferSize, NULL); if (!aError) { DWORD opError = GetLastError(); // 如果第二次调用还是缓冲区不足,按2倍扩容重试,最多重试2次避免死循环 int retryCount = 0; while (opError == ERROR_INSUFFICIENT_BUFFER && retryCount < 2) { LocalFree(aBuffer); aBuffer = NULL; BufferSize *= 2; aBuffer = (TCHAR *)LocalAlloc(LPTR, BufferSize * sizeof(TCHAR)); if (aBuffer == NULL) { return RESULT2(ERROR_MEMORY_EXCEPTION); } aError = SetupGetInfFileList(DirectoryPath, INF_STYLE_WIN4, aBuffer, BufferSize, NULL); if (aError) { break; } opError = GetLastError(); retryCount++; } // 超过重试次数后再抛出通用错误 if (!aError) { return RESULT2(ERR_INI_FILELIST); } }
内容的提问来源于stack exchange,提问作者EnZO
相关产品推荐
相关产品推荐

