How to get USB Device handle using device instance handle?

3.3k views Asked by At

I'm enumerating device manager tree using the CM_Locate_DevNode(), CM_Get_Child() and CM_Get_DevNode_Registry_Property() APIs. I'm able to get the device instance handle.

Using that handle I'm trying to get the device handle to query the string descriptor of the device.

Are both device instance handle and device handle same or is there any way to get the device handle from device instance handle?

1

There are 1 answers

2
gog On

Are both device instance handle and device handle same or is there any way to get the device handle from device instance handle?

No, they are not the same. One is called Device Instance ID, and the other is called the Device Path.

Your question is similar to this one.

Using that handle I'm trying to get the device handle to query the string descriptor of the device.

In order to get a USB String descriptor from a device, given its Device Instance ID, you need to:

  1. Get its parent USB Hub using CM_Get_Parent
  2. Then, get its USB Hub Device Interface using the GetInterfaces function I'm providing below
  3. Then, you can use the USB Device Interface as a Device Path in CreateFile, and then call DeviceIoControl to get the USB String Descriptor that you want.

This function returns a list of NULL-terminated Device Paths (that's what we get from CM_Get_Device_Interface_List)

You need to pass it the Device Instance ID, and the wanted interface GUID, which, for a USB HUB, is

const GUID* ptrGUID = &GUID_DEVINTERFACE_USB_HUB;

Since both the Device Instance ID and interface GUID are specified, it is highly likely that CM_Get_Device_Interface_List will return a single Device Path for that interface, but technically you should be prepared to get more than one result.

I used a slight variation of this function successfully in production code for getting the Device Interface of a USB HUB (GUID_CLASS_USBHUB): I used the resulting Device Path with CreateFile and opened it succesfully.

It is responsibility of the caller to delete[] the returned list if the function returns successfully (return code 0)

int GetInterfaces(const WCHAR* sysDeviceID, const LPGUID interfaceGUID, wchar_t**outIfaces, ULONG* outIfacesLen)
{
    CONFIGRET cres;
    if (!outIfaces)
        return -1;
    if (!outIfacesLen)
        return -2;

    // Get list size
    ULONG ifaceListSize = 0;
    cres = CM_Get_Device_Interface_List_Size(&ifaceListSize, interfaceGUID, sysDeviceID, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
    if (cres != CR_SUCCESS)
        return -12;

    // Allocate memory for the list
    wchar_t* ifaceList = new wchar_t[ifaceListSize*2];    // Double the required size, in order minimize the chances of getting CR_BUFFER_SMALL errors

    // Populate the list
    cres = CM_Get_Device_Interface_List(interfaceGUID, sysDeviceID, ifaceList, ifaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
    if (cres != CR_SUCCESS) {
        delete[] ifaceList;
        return -13;
    }

    // Return list
    *outIfaces = ifaceList;
    *outIfacesLen = ifaceListSize;

    return 0;
}