在网上看到很多是通过枚举卷来枚举USB的,但是一个USB设备可能有多个卷,若想获取一个USB设备的描述符,就行不通了。
我这里使用的方法是先枚举所有的hub设备,然后再遍历每个hub下port所连接的设备。因为所有的port都是在hub下的,所有不会有遗漏。
1. 构建hub的GUID
DEFINE_GUID(GUID_DEVINTERFACE_USB_HUB,
0xf18a0e88, 0xc30c, 0x11d0, 0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8);
#define GUID_CLASS_USB_HUB GUID_DEVINTERFACE_USB_HUB
2. 通过hub的GUID来获取hub的信息集:
HDEVINFO info = SetupDiGetClassDevs(lpGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
3. 枚举信息集下的所有hub设备:
for (i = 0; SetupDiEnumDeviceInfo(info, i, &DeviceInfoData); i++)
{
......
if (!SetupDiGetDeviceInstanceId(info, &DeviceInfoData, (PTSTR)did, buffersize, &req_bufsize)){
continue;
......
}
通过 SetupDiEnumDeviceInfo 函数枚举hub设备,再通过 SetupDiGetDeviceInstanceId 函数获取到ID。
4. 获取hub句柄
将 1 中获取到的ID拼接成devicepath,即在ID的前面添加"\\\\.\\",ID后添加"#{f18a0e88-c30c-11d0-8815-00a0c906bed8}"。
HANDLE hubUsbHandle = CreateFile(hubDevicePathW,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
通过 CreateFile 函数获取到hub的句柄。
5. 获取hub连接信息
BOOL success = DeviceIoControl(hHubDevice,
IOCTL_USB_GET_NODE_INFORMATION,
HubInfo,
sizeof(USB_NODE_INFORMATION),
HubInfo,
sizeof(USB_NODE_INFORMATION),
&nBytes,
NULL);
通过 DeviceIoControl 获取到对应hub的信息。接着获取对应的hub下的port数:
HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts
6. 遍历所有port
PUSB_NODE_CONNECTION_INFORMATION connectionInfo;
connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);
if (connectionInfo == NULL)
return false;
connectionInfo->ConnectionIndex = index;
BOOL success;
success = DeviceIoControl(hHubDevice,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
connectionInfo,
nBytes,
connectionInfo,
nBytes,
&nBytes,
NULL);
首先构建 connectionInfo,设置其index。通过 DeviceIoControl 获取当前port的信息,信息储存在 connectionInfo 中。
UCHAR nSerialno = connectionInfo->DeviceDescriptor.iSerialNumber;
USHORT idVendor = connectionInfo->DeviceDescriptor.idVendor;
USHORT idProduct = connectionInfo->DeviceDescriptor.idProduct;
以上是获取SN的索引和vid及pid的值。
目前为止,我的需求只是获取USB设备的 pid ,所以并没有在此描述获取其他的数据信息。因为之前有在网上看到一个通过hub的句柄来获取连接到其port上的USB设备的信息,所以这里就遍历所有的hub。当然也可以直接遍历所有的USB,只需将 1 中的GUID换成USB的GUID:
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE,
0xA5DCBF10/*L*/, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
#define GUID_CLASS_USB_DEVICE GUID_DEVINTERFACE_USB_DEVICE
接下的步骤和获取hub句柄类似,也是先构建好devicepath,便可获取到USB的句柄,然后通过DeviceIoControl 来获取到连接的设备信息,不过具体要传哪些参数就得自己去琢磨了。
以下是通过 usb device tree viewer 看到的结构图。强烈建议下载一个 UsbTreeView ,开发时有很大的帮助。