最近在搞PCVR相关的东西,需要读取设备的硬件ID,偶然发现了一个微软API的坑。
示例代码如下:
#include <iostream>
#include <windows.h>
#include <setupapi.h>
#include <tchar.h>
#pragma comment(lib, "setupapi.lib")
int main()
{
// 获取所有设备信息集合
HDEVINFO hDevInfo = SetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) {
std::cerr << "SetupDiGetClassDevsA failed: " << GetLastError() << std::endl;
return 1;
}
// 遍历设备信息集合
SP_DEVINFO_DATA deviceInfoData = { 0 };
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &deviceInfoData); i++) {
// 获取设备
char buffer[MAX_PATH];
DWORD requiredSize = 0;
if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &deviceInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)buffer, sizeof(buffer), &requiredSize)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
std::cerr << "SetupDiGetDeviceRegistryPropertyA failed: " << GetLastError() << std::endl;
}
}
else {
uint32_t len = strlen(buffer);
if (requiredSize != len + 1)
{
std::cout << "!!!!!!!!!!!";
}
std::cout << "Device " << i << " Hardware ID: " << buffer << std::endl;
}
}
// 关闭设备信息集合句柄
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
按道理requiredSize应该是ID字符串的长度加一(一个’\0’),但是我惊喜的发现,实际上并不是这样。虽然我调用的是A结尾版本的函数,但是会看到buffer里边的数据是以两个’\0’结尾的(有时中间还会有0),而requiredSize是包含所有数据的buffer的大小,所以并不能用requiredSize作为字符串长度来使用。
这会造成什么问题呢?我把这个buffer直接当字符串去做base64编码,输出的数据与其他工具计算的不一样。最后只能手动操作做一次去0来解决这个问题。