Windows - 如何枚举所有已连接的USB设备的设备路径?

18

我正尝试使用SetupDi函数枚举所有连接的USB设备的设备路径。设备路径是在CreateFile()中使用的路径,因此我可以与设备通信。

然而,SetupDiGetDeviceInterface需要一个接口GUID,但我不特别寻找特定的接口(除了所有连接的USB设备)。下面的源代码中这部分被注释为 /* ??? */。

尝试的解决方法:

我尝试提供GUID_DEVCLASS_UNKNOWN = {0x4d36e97e, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}; 但这引发了“没有更多接口”错误。

我也尝试将deviceInfoData.ClassGuid提供给SetupDiGetDeviceInterface,但我得到了与上述相同的错误,“没有更多接口”。

问题:

是否有一般的接口类可以涵盖所有USB设备?(HID,通用等)

或者是否有另一种函数可以给我设备的路径?(而不是由SetupDiGetDeviceInterfaceDetail返回的SP_DEVICE_INTERFACE_DETAIL_DATA结构)。

源代码:

HDEVINFO deviceInfoList
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
DWORD requiredLength = 0;
char *hardwareID = 0;

// Retrieve a list of all present devices
deviceInfoList = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);

if (deviceInfoList == INVALID_HANDLE_VALUE) {
    SetupDiDestroyDeviceInfoList(deviceInfoList);
    return false;
}

// Iterate over the list
for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoList, i, &deviceInfoData); i++) {
    if (deviceInterfaceDetailData) LocalFree(deviceInterfaceDetailData);

    requiredLength = 0;

    SetupDiGetDeviceRegistryProperty(deviceInfoList, &deviceInfoData, SPDRP_HARDWAREID, &DataT, NULL, 0, &requiredLength);

    if (requiredLength <= 0) {
        SetupDiDestroyDeviceInfoList(deviceInfoList);
        return false;
    }

    hardwareID = new char[requiredLength]();

    SetupDiGetDeviceRegistryProperty(deviceInfoList, &deviceInfoData, SPDRP_HARDWAREID, &DataT, (PBYTE)hardwareID, requiredLength, NULL);

    // Parse hardwareID for vendor ID and product ID

    delete hardwareID;
    hardwareID = 0;

    deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);

    // Requires an interface GUID, for which I have none to specify
    if (!SetupDiEnumDeviceInterfaces(deviceInfoList, &deviceInfoData, /* ??? */, 0, &deviceInterfaceData)) {
        SetupDiDestroyDeviceInfoList(deviceInfoList);
        return false;
    }

    if (!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInterfaceData, NULL, 0, &requiredLength, NULL)) {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && requiredLength > 0) {
            deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredLength);

            if (!deviceInterfaceDetailData) {
                SetupDiDestroyDeviceInfoList(deviceInfoList);
                return false;
            }
        } else {
            SetupDiDestroyDeviceInfoList(deviceInfoList);
            return false;
        }
    }

    deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    if (!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInterfaceData, deviceInterfaceDetailData, requiredLength, NULL, &deviceInfoData)) {
        SetupDiDestroyDeviceInfoList(deviceInfoList);
        return false;
    }

    SetupDiDestroyDeviceInfoList(deviceInfoList);

    // deviceInterfaceDetailData->DevicePath yields the device path
}

我尝试了答案中给出的代码,但是我收到了一个“请从项目属性页面选择一个有效的目标机器进行部署”的错误提示。它可以编译,但我无法运行它。你有同样的问题吗?我正在Windows 7上使用VS 2015和WDK 10。 - lads
1个回答

23

MSDN称有一个名为GUID_DEVINTERFACE_USB_DEVICE的通用USB设备接口类,其GUID为{A5DCBF10-6530-11D2-901F-00C04FB951ED}:

系统提供的USB集线器驱动程序注册GUID_DEVINTERFACE_USB_DEVICE实例,以通知系统和应用程序已连接到USB集线器的USB设备的存在。

这里是一个代码示例,似乎可以使用DEVINTERFACE_USB_DEVICE GUID来实现所需功能。


刚试了一下,正是我想要的!谢谢! - Daniel
2
未来的读者注意:非常小心使用设备“接口”类GUID,而不是设备“安装”类,它们并不相同。请参阅此文章获取更多详细信息。 - jrh
1
那个GUID在usbiodef.h中定义。别忘了事先要#include <initguid.h>以避免链接器错误。 - YePhIcK
这段代码给我返回了“undefined reference to `__imp_SetupDiGetClassDevsA'”和其他未定义引用的错误。查阅资料后,似乎需要使用链接器来链接一些库,我也这样做了,但它说找不到这些库。我做错了什么?我使用的是Code::Blocks。 - Christianidis Vasileios
@ChristianidisVasileios 对于 SetupDiGetClassDevsA,你需要像文档中提到的那样链接到 SetupAPI.lib - DJm00n

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接