18

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
}
Daniel
  • 8,655
  • 5
  • 60
  • 87
  • I tried the code given in the answer but I get a `Please select a valid target machine for deployment from the project property page`. It build but I cannot run it. Did you have the same problem ? I'm using VS 2015 and WDK 10 on Windows 7 – lads Jul 28 '16 at 11:34

1 Answers1

22

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.

Michael
  • 57,169
  • 9
  • 80
  • 125
  • Just tried it out and it's exactly what I was looking for! Thanks! – Daniel Dec 19 '12 at 02:28
  • 2
    Note for future readers: Be very careful that you are using a device **interface** class GUID and not a device **setup** class, they are not the same thing. [See this article for more details.](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/setup-classes-versus-interface-classes) – jrh Oct 06 '17 at 15:45
  • 1
    That GUID is defined in `usbiodef.h`. Don't forget to `#include ` beforehand to avoid linker error – YePhIcK Aug 19 '18 at 21:54
  • This code gives me undefined reference to `__imp_SetupDiGetClassDevsA' And other errors of undefined reference. After looking it up, it seems like I need to use my linker to link some libraries, which I did and it says it cannot find these libraries. What did I do wrong? I use Code::Blocks – Christianidis Vasileios Jul 06 '21 at 14:43
  • @ChristianidisVasileios for `SetupDiGetClassDevsA` you need to link to `SetupAPI.lib` as mentioned in its docs. – DJm00n Oct 14 '22 at 19:41