Windows枚举设备信息

枚举设备信息主要通过 SetupAPI 模块中的接口来实现,配合对应的设备类 GUID。 

这里以枚举 USB 设备信息为例,包含设备实例地址等:

#include <stdio.h>
#include <Windows.h>
#include <SetupAPI.h>
#pragma comment(lib, "SetupAPI.lib")
#include <devguid.h>
// 具体的设备 GUID 需要 initguid, 如 usbiodef
#include <initguid.h>
// USB 设备
// GUID_DEVINTERFACE_USB_DEVICE
#include <usbiodef.h>

void enum_device_info()
{
    // HDEVINFO 标识设备信息集
    HDEVINFO info_set;
    // SetupDiGetClassDevs 返回包含本地计算机请求的设备信息元素的设备信息集的句柄
    // 接口文档:https://learn.microsoft.com/zh-cn/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsa
    // 若要返回支持任何类的设备接口的设备,设置 DIGCF_DEVICEINTERFACE 和 DIGCF_ALLCLASSES 标志,然后将 ClassGuid 设置为 NULL
    //info_set = SetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    // 若要仅返回支持指定类的设备接口的设备,设置 DIGCF_DEVICEINTERFACE 标志并使用 ClassGuid 参数提供设备接口类的类 GUID
    // 实际使用对应设备的 GUID
    GUID device_guid{GUID_DEVINTERFACE_USB_DEVICE};
    info_set = SetupDiGetClassDevsA(&device_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    // 如果操作失败,返回 INVALID_HANDLE_VALUE
    if (info_set == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "SetupDiGetClassDevs: [err code] %d.\n", GetLastError());
        return;
    }

    // SP_DEVINFO_DATA 标识设备信息集中的设备
    SP_DEVINFO_DATA info_data = { 0 };
    info_data.cbSize = sizeof(info_data);
    constexpr DWORD buf_size = 2048;
    BYTE info_buf[buf_size + 1] = { 0 };
    // SetupDiEnumDeviceInfo 枚举设备信息
    for (int index = 0; SetupDiEnumDeviceInfo(info_set, index, &info_data); index++)
    {
        fprintf(stderr, "Device %d:\n", index);

        // SetupDiGetDeviceRegistryProperty 检索指定的即插即用设备属性
        // SPDRP_* 参数这里只列举了一部分
        // 如果返回 ERROR_INSUFFICIENT_BUFFER 错误,表示缓冲区不够存放数据,根据最后一个参数返回的大小重新设置缓冲区
        // 设备描述
        // SPDRP_DEVICEDESC 函数检索包含设备说明的 REG_SZ 字符串
        if (!SetupDiGetDeviceRegistryPropertyA(info_set, &info_data, SPDRP_DEVICEDESC, NULL, info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Desc: [err code] %d %d.\n", GetLastError(), ERROR_INSUFFICIENT_BUFFER);
        } else {
            fprintf(stderr, "Device Desc: %s.\n", info_buf);
        }

        // 设备设备类
        // SPDRP_CLASS 函数检索包含设备的设备设置类的 REG_SZ 字符串
        if (!SetupDiGetDeviceRegistryPropertyA(info_set, &info_data, SPDRP_CLASS, NULL, info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Class: [err code] %d.\n", GetLastError());
        } else {
            fprintf(stderr, "Device Class: %s.\n", info_buf);
        }

        // 设备设置类 GUID
        // SPDRP_CLASSGUID 函数检索一个 REG_SZ 字符串,该字符串包含表示设备的设备设置类的 GUID
        if (!SetupDiGetDeviceRegistryPropertyA(info_set, &info_data, SPDRP_CLASSGUID, NULL, info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Class GUID: [err code] %d.\n", GetLastError());
        } else {
            fprintf(stderr, "Device Class GUID: %s.\n", info_buf);
        }

        // 设备友好名称
        // SPDRP_FRIENDLYNAME 函数检索包含设备的友好名称的 REG_SZ 字符串
        if (!SetupDiGetDeviceRegistryPropertyA(info_set, &info_data, SPDRP_FRIENDLYNAME, NULL, info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Friendly Name: [err code] %d.\n", GetLastError());
        } else {
            fprintf(stderr, "Device Friendly Name: %s.\n", info_buf);
        }

        // 返回硬件 ID 列表
        // SPDRP_HARDWAREID 函数检索包含设备硬件 ID 列表的 REG_MULTI_SZ 字符串
        if (!SetupDiGetDeviceRegistryPropertyA(info_set, &info_data, SPDRP_HARDWAREID, NULL, info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Hardware ID: [err code] %d.\n", GetLastError());
        } else {
            fprintf(stderr, "Device Hardware ID: %s.\n", info_buf);
        }

        // 获取设备实例 ID
        // SetupDiGetDeviceInstanceIdA 函数检索与设备信息元素关联的设备实例 ID
        if (!SetupDiGetDeviceInstanceIdA(info_set, &info_data, (PSTR)info_buf, buf_size, NULL)) {
            fprintf(stderr, "Device Instance ID: [err code] %d.\n", GetLastError());
        } else {
            fprintf(stderr, "Device Instance ID: %s.\n", info_buf);
        }

        // 获取设备实例路径
        // SP_DEVICE_INTERFACE_DATA 设备信息集中的设备接口
        SP_DEVICE_INTERFACE_DATA interface_data = { 0 };
        interface_data.cbSize = sizeof(interface_data);
        // SetupDiEnumDeviceInterfaces 枚举包含在设备信息集中的设备接口
        BOOL ret = SetupDiEnumDeviceInterfaces(info_set, NULL, (LPGUID)&device_guid, index, &interface_data);
        if (!ret) continue;
        ULONG required_len = 0;
        // SetupDiGetDeviceInterfaceDetail 返回有关设备接口的详细信息
        // 第一次调用是获取长度,这里是返回false
        SetupDiGetDeviceInterfaceDetailA(info_set, &interface_data, NULL, 0, &required_len, NULL);
        if (required_len <= 0) continue;
        ULONG predicted_len = required_len;
        // SP_INTERFACE_DEVICE_DETAIL_DATA 包含设备接口的路径
        SP_INTERFACE_DEVICE_DETAIL_DATA_A detail_data = { 0 };
        detail_data.cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_A);
        // 检索即插即用设备信息
        if (SetupDiGetDeviceInterfaceDetailA(info_set,
                                             &interface_data,
                                             &detail_data,
                                             predicted_len,
                                             &required_len,
                                             &info_data)) {
            fprintf(stderr, "Device Instance Path: %s.\n", detail_data.DevicePath);
        }
    }

    // SetupDiDestroyDeviceInfoList 删除设备信息集并释放所有关联的内存
    SetupDiDestroyDeviceInfoList(info_set);
}

 输出结果:

Device 0:
Device Desc: USB Composite Device.
Device Class: USB.
Device Class GUID: {36fc9e60-c465-11cf-8056-444553540000}.
Device Friendly Name: [err code] 13. // 13 对应 ERROR_INVALID_DATA
Device Hardware ID: USB\VID_04CA&PID_7070&REV_0023.
Device Instance ID: USB\VID_04CA&PID_7070\5&20D34A76&0&6.
Device Instance Path: \\?\usb#vid_04ca&pid_7070#5&20d34a76&0&6#{a5dcbf10-6530-11d2-901f-00c04fb951ed}.
Device 1:
Device Desc: Generic Bluetooth Adapter.
Device Class: Bluetooth.
Device Class GUID: {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}.
Device Friendly Name: [err code] 13.
Device Hardware ID: USB\VID_0CF3&PID_E500&REV_0001.
Device Instance ID: USB\VID_0CF3&PID_E500\5&20D34A76&0&14.
Device Instance Path: \\?\usb#vid_0cf3&pid_e500#5&20d34a76&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed}.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值