Get parent device
I have two USB device IDs for example. USB\VID_E4F1&PID_0661\00000115FA9CE7750000000000000000
andUSB\VID_E4F1&PID_0661&MI_00\7&B5A5DDF&0&0000
How can I verify that device # 2 is a direct descendant of device # 1 (physically they are part of the same USB-composite device)?
In real life scenarios, many of them will be connected to a single USB controller. Moreover, it is possible that they will be of the same manufacturer and model. So I cannot check VID, PID and use Win32_USBControllerDevice
WMI query to check that they are connected to the same USB controller. I need to somehow check for the parent-child relationship, not just the fact that they are connected to the same controller.
If it matters, I only need to support Windows 8+.
source to share
The PnP Configuration Manager API is your friend here:
-
CM_Locate_DevNode opens a device descriptor with the specified device ID;
-
CM_Get_Parent finds the parent device;
-
CM_Get_Device_ID_Size and CM_Get_Device_ID take a device descriptor and return a device ID.
source to share
If you can use the new WinRT API, you should take a look at the class PnpObject
and namespace.
Here's some sample code:
var propertiesToQuery = new List<string>() {
"System.ItemNameDisplay",
"System.Devices.DeviceInstanceId",
"System.Devices.Parent",
"System.Devices.LocationPaths",
"System.Devices.Children"
};
var id1 = @"USB\VID_E4F1&PID_0661\00000115FA9CE7750000000000000000";
var device1 = await PnpObject.FindAllAsync(PnpObjectType.Device,
propertiesToQuery,
"System.Devices.DeviceInstanceId:=\"" + id1 + "\"");
var id2 = @"USB\VID_E4F1&PID_0661&MI_00\7&B5A5DDF&0&0000";
var device2 = await PnpObject.FindAllAsync(PnpObjectType.Device,
propertiesToQuery,
"System.Devices.DeviceInstanceId:=\"" + id2 + "\"");
var parent1 = device1.Properties["System.Devices.Parent"] as string;
var parent2 = device2.Properties["System.Devices.Parent"] as string;
if (parent1 && parent1 == id2)
{
WriteLine("Device 2 is parent of device 1");
}
if (parent2 && parent2 == id1)
{
WriteLine("Device 11 is parent of device 2");
}
var child_ids = device1.Properties["System.Devices.Children"] as string[];
if (child_ids != null){
foreach (var id in child_ids)
{
if (id == id2){
WriteLine("Device 2 is child of device 1")
}
}
}
child_ids = device2.Properties["System.Devices.Children"] as string[];
if (child_ids != null){
foreach (var id in child_ids)
{
if (id == id1){
WriteLine("Device 1 is child of device 2")
}
}
}
If that's not enough, you can try going up or down the parent / child path.
You can also look at the property System.Devices.LocationPaths
(which is an array of strings) and check if it is a prefix of another.
source to share
Continuing on Harry Johnston's excellent answer:
Once called, CM_Locate_DevNode
you can get the ID of the parent device instance with a single function call:
#include <propkey.h>
// Get the Parent Device Property
DEVPROPTYPE propType;
wchar_t propBuf[MAX_DEVICE_ID_LEN] = {};
ULONG propBufSize = sizeof(propBuf);
CONFIGRET cres = CM_Get_DevNode_Property(devInst, (DEVPROPKEY*)&PKEY_Devices_Parent, &propType, (BYTE*)propBuf, &propBufSize, 0);
if (cres == CR_SUCCESS) {
// propBuf now contains the Parent System Device ID!
}
source to share