windows - How to enumerate all connected USB devic

2019-01-13 16:46发布

问题:

I'm trying to use the SetupDi functions to enumerate all connected USB devices' device path. The device path is the path used in CreateFile() so I can communicate with the device.

However, SetupDiGetDeviceInterface requires an interface GUID but I'm not specifically looking for a particular interface (other than all connected USBs). This part has been commented as /* ??? */ in the source below.

Attempted Solutions:

I've tried to supply GUID_DEVCLASS_UNKNOWN = {0x4d36e97e, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}; but this threw a "no more interfaces" error.

I've also tried to supply deviceInfoData.ClassGuid into SetupDiGetDeviceInterface but I get the same error as above, "no more interfaces".

Questions:

Is there a general interface class which will cover all USB devices? (HID, generic, etc.)

Or is there an alternate function which will give me the path to the device? (Instread of the SP_DEVICE_INTERFACE_DETAIL_DATA structure returned by SetupDiGetDeviceInterfaceDetail).

Source:

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
}

回答1:

MSDN says that there's a generic USB device interface class named GUID_DEVINTERFACE_USB_DEVICE with the GUID {A5DCBF10-6530-11D2-901F-00C04FB951ED}:

The system-supplied USB hub driver registers instances of GUID_DEVINTERFACE_USB_DEVICE to notify the system and applications of the presence of USB devices that are attached to a USB hub.

Here's a code example that seems to do what you want to do, using the DEVINTERFACE_USB_DEVICE GUID.