Windows获取硬件ID的坑——SetupDiGetDeviceRegistryPropertyA这个接口不太可靠

最近在搞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来解决这个问题。

RSS
Follow by Email
YouTube
YouTube
Pinterest
fb-share-icon
LinkedIn
Share
VK
Weibo
WeChat
WhatsApp
Reddit
FbMessenger
Copy link
URL has been copied successfully!