I am updating my question to better reflect what I was actually going after. To state a fact about my original confusion quickly, it is incorrect to say that there is a 1-to-1 relationship between "Device Interface Class GUID" and the Device Instance ID. A device can have many device interfaces. As Ben Voigt noted in the comments, see this for more information.
How can one open a handle to a child device after calling the CM_Get_Child (...) function?
Take the following code snip as an example:
#pragma comment (lib, "Setupapi.lib")
#pragma comment (lib, "Cfgmgr32.lib")
#include <iostream>
#include <Windows.h>
#include <Setupapi.h>
#include <Cfgmgr32.h>
#define GUID_STRING_SIZE 40
int main ()
{
CONFIGRET CMResult = CR_SUCCESS;
WCHAR DeviceInstanceID[] = L"USB\\VID_2109&PID_0813\\8&216C1825&0&4\0"; // Parent Device Instance ID.
DEVNODE ParentDeviceNode = (DWORD) 0; // A device instance handle. This handle is bounded to the local machine.
CMResult = CM_Locate_DevNode ((PDEVINST) &ParentDeviceNode, DeviceInstanceID, CM_LOCATE_DEVNODE_NORMAL);
if (CMResult != CR_SUCCESS)
{
std::cout << "No parent device node found." << std::endl;
return -1;
}
else
{
DEVINST NextChildDeviceNode = (DWORD) 0;
CMResult = CM_Get_Child ((PDEVINST) &NextChildDeviceNode, ParentDeviceNode, 0x0); // Gets the first child of the parent node. If this returns "CR_NO_SUCH_DEVNODE," then there is no child attached.
if (CMResult != CR_SUCCESS)
{
std::cout << "No child device node found." << std::endl;
return -2;
}
else
{
ULONG ChildInstanceIDBuffLength = 0;
CMResult = CM_Get_Device_ID_Size (&ChildInstanceIDBuffLength, NextChildDeviceNode, 0x0);
if (CMResult != CR_SUCCESS)
{
std::cout << "Could not get the size of the device instance ID of child device." << std::endl;
return -3;
}
else
{
WCHAR * ChildInstanceIDBuff = (WCHAR *) malloc (ChildInstanceIDBuffLength);
CMResult = CM_Get_Device_IDW (NextChildDeviceNode, ChildInstanceIDBuff, ChildInstanceIDBuffLength, 0x0);
if (CMResult != CR_SUCCESS)
{
std::cout << "Could not actual device instance ID string of child device" << std::endl;
return -4;
}
else
{
std::cout << "Found child device instance ID: ";
std::wcout << ChildInstanceIDBuff << std::endl;
/*
* Open handle to the child device node now!
*/
}
free (ChildInstanceIDBuff);
}
}
}
return 0;
}
How can I use the newly obtained child Device Instance ID to open a handle to the device? CreateFile (...) requires the complete device path, which includes the missing "Device Interface Class GUID."
More specifically, a device path has the following format:
\\?\usb#vid_2109&pid_0813#7&3981C8D6&0&2#{[DEVICE_INTERFACE_GUID]}, where:
- [DEVICE_INTERFACE_GUID] - This the "Device Interface Class GUID." This is NOT the same as the "Device Setup Class GUID."
There does not appear to be an easy way to get this "Device Interface Class GUID" without some level of brute force (e.g. CM_Enumerate_Classes (...) using the CM_ENUMERATE_CLASSES_INTERFACE flag). Is there a function I can call to get a handle to a device using only its "Device Instance ID," so that I can then call DeviceIoControl (...) and query information about the device?
You can use the
CM_Enumerate_Classesfunction with theCM_ENUMERATE_CLASSES_INTERFACEflag (Requires Windows 8) to get possible values to pass as that third parameter ofSetupDiEnumDeviceInterfaces.Note that finding all interfaces on a device is very useful for diagnosing driver problems and/or reverse engineering random peripherals rescued from scrap. But you should know what interface class you are dealing with long before you get to the point of calling
CreateFile.