1. 设备信息
1.1. 设备实例ID
- 设备ID
设备 ID(Device ID) 是一个字符串,由设备的报告枚举器。 设备只有一个设备 id。如USB存储设备ID:
USB\VID_23A9&PID_EF18\5&19353383&0&2
- 实例ID
实例 ID (Instance ID)是将设备与计算机上相同类型的其他设备进行区分的设备标识字符串。 实例 ID 包含序列号信息(如果基础总线支持)或某些类型的位置信息。 - 设备实例 ID
设备树的每个节点都称为一个设备节点中,或devnode。设备实例 ID 是系统提供的设备标识字符串,用于在系统中唯一标识设备。 即插即用(PnP)管理器为系统设备树中的每个设备节点(devnode)分配一个设备实例 ID。
此字符串的格式由连接到设备 ID的实例 ID组成,如下所示:
<instance-specific-ID>
- 设备实例 ID 的字符数(不包括 NULL 终止符)必须小于 MAX_DEVICE_ID_LEN。 此约束适用于设备 ID和实例特定 ID字段之间所有字段的长度与 “” 字段分隔符之和。
在系统重新启动期间,设备实例 ID 是永久性的。
下面是连接到 PCI 设备的设备 ID 的实例 ID (“1 & 08”)的示例:
PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08
1.2. 设备树
2. 使用CM系列函数枚举所有设备
CM 是Configuration Manager的简写。Configuration Manager functions是用来查询Windows系统中接入的设备信息。
2.1. 常用的函数
- 获取设备实例句柄
pDeviceID如果配置为设备ID,则返回对应设备的设备实例句柄。如果pDeviceID为NULL,则返回根设备的设备实例句柄。
CMAPI CONFIGRET CM_Locate_DevNode(
PDEVINST pdnDevInst,
DEVINSTID_A pDeviceID,
ULONG ulFlags);
- 从注册表中获取设备对应的属性
根据不同的ulProperty获取对应的属性,如设备描述、硬件ID、位置信息、GUID等。
CMAPI CONFIGRET CM_Get_DevNode_Registry_PropertyW(
DEVINST dnDevInst,
ULONG ulProperty,
PULONG pulRegDataType,
PVOID Buffer,
PULONG pulLength,
ULONG ulFlags
);
- 枚举函数
分别根据现有的设备实例句柄,找到子设备实例句柄、兄弟设备实例句柄、父设备实例句柄。
CMAPI CONFIGRET CM_Get_Child(
PDEVINST pdnDevInst,
DEVINST dnDevInst,
ULONG ulFlags
);
CMAPI CONFIGRET CM_Get_Sibling(
PDEVINST pdnDevInst,
DEVINST dnDevInst,
ULONG ulFlags
);
CMAPI CONFIGRET CM_Get_Parent(
PDEVINST pdnDevInst,
DEVINST dnDevInst,
ULONG ulFlags
);
- 获取设备ID
根据设备实例句柄获取对应的设备ID
CMAPI CONFIGRET CM_Get_Device_IDW(
DEVINST dnDevInst,
PWSTR Buffer,
ULONG BufferLen,
ULONG ulFlags
);
2.2. 示例
UINT EnumeAllDeviceByCM()
{
DEVINST devInst = {0};
DEVINST devInstNext = {0};
CONFIGRET cr = {0};
ULONG walkDone = 0;
ULONG len = 0;
char buf[1024] = {0};
// Get Root DevNode
cr = CM_Locate_DevNode(&devInst, NULL, 0);
// 可以指定根设备ID
//cr = CM_Locate_DevNode(&devInst, "PCI\\VEN_8086&DEV_9D2F&SUBSYS_17091D72&REV_21\\3&11583659&1&A0", 0);
if (cr != CR_SUCCESS)
{
return 1;
}
// Do a depth first search for the DevNode with a matching
// DriverName value
while (!walkDone)
{
char szDeviceID[1024] = {0};
char szProperty[1024] = {0};
len = 1024;
cr = CM_Get_Device_ID(devInst, szDeviceID, len, 0);
if (cr == CR_SUCCESS)
{
for (UINT uIdx = 1; uIdx <= _countof(CM_PROPERTY); uIdx++)
{
len = 1024;
cr = CM_Get_DevNode_Registry_Property(devInst,
uIdx,
NULL,
szProperty,
&len,
0);
if (cr == CR_SUCCESS)
{
std::cout<<CM_PROPERTY[uIdx-1]<<std::endl;
std::cout<<szProperty<<std::endl;
OutputDebugString(CM_PROPERTY[uIdx-1]);OutputDebugString(":");
OutputDebugString(szProperty);OutputDebugString("\r\n");
}
}
}
else
{
return 1;
}
// This DevNode didn't match, go down a level to the first child.
cr = CM_Get_Child(&devInstNext,
devInst,
0);
if (cr == CR_SUCCESS)
{
devInst = devInstNext;
continue;
}
// Can't go down any further, go across to the next sibling. If
// there are no more siblings, go back up until there is a sibling.
// If we can't go up any further, we're back at the root and we're
// done.
for (;;)
{
cr = CM_Get_Sibling(&devInstNext,devInst,0);
if (cr == CR_SUCCESS)
{
devInst = devInstNext;
break;
}
cr = CM_Get_Parent(&devInstNext,devInst,0);
if (cr == CR_SUCCESS)
{
devInst = devInstNext;
}
else
{
walkDone = 1;
break;
}
}
}
return 0;
}
3. 使用SetupAPI枚举所有设备
Windows的安装的设备都归为设备信息集中(device information set)中,并提供一套Setup开头的API来访问设备的相关信息。
3.1. 常用的函数
- 获取设备信息集句柄
ClassGuid可以指定对应设备类型的GUID,如果不指定,则枚举所有。Enumerator如果指定枚举字符串,则枚举相应枚举器下的设备,否则返回根设备信息集句柄。
WINSETUPAPI HDEVINFO SetupDiGetClassDevsW(
const GUID *ClassGuid,
PCWSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
- 获取指定设备信息集中的对应序号的设备信息数据
DeviceInfoData可以给相关函数标识设备,并且DeviceInfoData中有设备实例句柄可以给CM函数使用。
WINSETUPAPI BOOL SetupDiEnumDeviceInfo(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
);
- 从注册表中获取设备属性
根据不同的ulProperty获取对应的属性,如设备描述、硬件ID、位置信息、GUID等。作用基本与CM_Get_DevNode_Registry_Property相同。
WINSETUPAPI BOOL SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
);
- 获取设备所有属性
获取设备的所有属性,包括了注册表中的信息。并且其中有获取设备ID、子设备的实例ID、父设备的实例ID、兄弟设备的实例ID等,要以进行与CM类似的枚举。
WINSETUPAPI BOOL SetupDiGetDevicePropertyW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
const DEVPROPKEY *PropertyKey,
DEVPROPTYPE *PropertyType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize,
DWORD Flags
);
- 获取设备路径
DeviceInfoSet从SetupDiGetClassDevs获取,DeviceInterfaceData从SetupDiEnumDeviceInterfaces获取。
WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
PDWORD RequiredSize,
PSP_DEVINFO_DATA DeviceInfoData
);
- 获取设备ID
DeviceInfoSet从SetupDiGetClassDevs获取,DeviceInfoData从SetupDiEnumDeviceInfo获取。
WINSETUPAPI BOOL SetupDiGetDeviceInstanceIdA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PSTR DeviceInstanceId,
DWORD DeviceInstanceIdSize,
PDWORD RequiredSize
);
3.2. 示例
UINT EnumAllDeviceBySetup()
{
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE)
return 1;
for (int i = 0; ; i++)
{
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
if (!SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DeviceInfoData))
break;
char szDeviceID[256] = {};
DWORD dwTemp = 0;
SetupDiGetDeviceInstanceId(DeviceInfoSet, &DeviceInfoData, szDeviceID, 256, &dwTemp);
DEVPROPKEY devicePropertyKey[256] = {0};
DWORD RequiredSize = 0;
DEVPROPTYPE PropertyType = 0;
CHAR PropertyBuffer[8192] = { 0 };
for (UINT uIdx = 0; uIdx < _countof(szSPDRPName); uIdx++)
{
DWORD DataT = 0;
DWORD buffersize = 0;
if (SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, uIdx, &DataT, reinterpret_cast<PBYTE>(PropertyBuffer), 8192, &RequiredSize))
{
CString strLog = szSPDRPName[uIdx];
strLog += ":";
strLog += PropertyBuffer;
strLog += "\r\n";
OutputDebugString(strLog);
std::cout<<strLog.GetString();
}
}
}
return 0;
}
UINT GetAllUSBDeviceID(char** _ppDeviceID, char** _ppHubID)
{
GUID* pGUID = (GUID*)&GUID_DEVINTERFACE_DISK;
HDEVINFO hDevInfoSet = SetupDiGetClassDevs(pGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if ( hDevInfoSet == INVALID_HANDLE_VALUE )
{
return 0;
}
SP_DEVICE_INTERFACE_DATA ifdata;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(1024);
if (pDetail == NULL)
{
return 0;
}
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
U32 dwDeviceIdx = 0;
U32 dwUSBDeviceCnt = 0;
BOOL result = TRUE;
SP_DEVINFO_DATA spdd;
// device index = 0, 1, 2... test the device interface one by one
while (result)
{
ifdata.cbSize = sizeof(ifdata);
//enumerates the device interfaces that are contained in a device information set
result = SetupDiEnumDeviceInterfaces(
hDevInfoSet, // DeviceInfoSet
NULL, // DeviceInfoData
pGUID, // GUID
dwDeviceIdx, // MemberIndex
&ifdata // DeviceInterfaceData
);
if (result)
{
// get the buffer size of details
U32 dwSize = 0;
result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &ifdata, NULL, 0, &dwSize, NULL);
if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (dwSize > 0))
{
pDetail->cbSize = sizeof(*pDetail);
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
// get details about a device interface
result = SetupDiGetDeviceInterfaceDetail(
hDevInfoSet, // DeviceInfoSet
&ifdata, // DeviceInterfaceData
pDetail, // DeviceInterfaceDetailData
1024, // DeviceInterfaceDetailDataSize
&dwSize, // RequiredSize
&spdd // DeviceInfoData
);
dwDeviceIdx++;
// 设备路径必须是usbstor
if (NULL == strstr(pDetail->DevicePath, "usb"))
{
continue;
}
if (result)
{
DEVINST DevInstParent = 0;
CONFIGRET cr = CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
if (cr != CR_SUCCESS)
{
return 0;
}
char szBuff[512] = {0};
cr = CM_Get_Device_ID(DevInstParent, szBuff, 512, 0);
if (cr != CR_SUCCESS)
{
return 0;
}
strcpy_s(_ppDeviceID[dwUSBDeviceCnt], DEVICE_ID_SIZE, szBuff);
// 再向上查找一级即为HUBID
DEVINST hubDevInst = 0;
cr = CM_Get_Parent(&hubDevInst, DevInstParent, 0);
if (cr != CR_SUCCESS)
{
return 0;
}
char szHubBuff[512] = {0};
cr = CM_Get_Device_ID(hubDevInst, szHubBuff, 512, 0);
if (cr != CR_SUCCESS)
{
return 0;
}
strcpy_s(_ppHubID[dwUSBDeviceCnt++], DEVICE_ID_SIZE, szHubBuff);
}
}
}
}
free(pDetail);
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return dwUSBDeviceCnt;
}
int EnumAllDeviceBySetupEx()
{
//HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE)
return 1;
for (int nIdx = 0; ; nIdx++)
{
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
if (!SetupDiEnumDeviceInfo(DeviceInfoSet, nIdx, &DeviceInfoData))
break;
char szDeviceID[256] = {};
DWORD dwTemp = 0;
SetupDiGetDeviceInstanceId(DeviceInfoSet, &DeviceInfoData, szDeviceID, 256, &dwTemp);
DEVPROPKEY devicePropertyKey[256] = {0};
DWORD dwCount = 128;
if (!SetupDiGetDevicePropertyKeys(DeviceInfoSet, &DeviceInfoData, devicePropertyKey, dwCount, 0, 0))
continue;
DWORD RequiredSize = 0;
DEVPROPTYPE PropertyType = 0;
WCHAR PropertyBuffer[1024] = {0};
for (UINT uIdx = 0; uIdx < _countof(devicePropertyKey); uIdx++)
{
if (0 == devicePropertyKey[uIdx].pid)
continue;
if (SetupDiGetDevicePropertyW(DeviceInfoSet, &DeviceInfoData, &devicePropertyKey[uIdx], &PropertyType, reinterpret_cast<PBYTE>(PropertyBuffer), sizeof(PropertyBuffer), NULL, 0))
{
for (UINT uKeyIdx = 0; uKeyIdx < _countof(ARR_DEV_KEYS); uKeyIdx++)
{
if ((devicePropertyKey[uIdx].fmtid == ARR_DEV_KEYS[uKeyIdx].fmtid)
&& (devicePropertyKey[uIdx].pid == ARR_DEV_KEYS[uKeyIdx].pid))
{
CString strLog = ARR_STR_DEV_KEYS[uKeyIdx];
strLog += ":";
USES_CONVERSION;
strLog += W2A(PropertyBuffer);
strLog += "\r\n";
OutputDebugString(strLog);
std::cout<<strLog.GetString();
break;
}
}
}
}
}
return 0;
}
4. 使用DeviceIOControl枚举所有设备
4.1. 枚举基本流程
- 获取根Hub名字
打开根设备,并且通过DeviceIoControl(IOCTL_USB_GET_ROOT_HUB_NAME来获取HubName。
sprintf_s(hcdName, "\\\\.\\HCD%d", nHCDNo);
HANDLE hHCDev = CreateFile(hcdName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
std::string strRootHubName = GetRootHubName(hHCDev);
- 通过HubName获取Hub的节点信息
- 通过CreateFile(HubNmae…),然后再通过 DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_INFORMATION,获取设备节点信息。
- 设备节点信息中包括Hub有几个子设备。
- 遍历设备节点连接信息
通过DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,并且指定Hub中设备的索引,获取指定索引的设备连接信息。主要包括设备描述、速度、是否Hub等。 - 获取设备驱动名
通过DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME并且指定索引获取设备驱动名,可以作为设备的唯一标识,且与CM属性CM_DRP_DRIVER进行匹配。 - 获取设备的连接名(设备路径)
通过DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_NAME并且指定索引获取设备连接名,也即设备路径,可以作为设备唯一标识。子Hub设备路径,可以进行新一轮枚举。
4.2. 示例
const std::string GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex)
{
BOOL success;
ULONG nBytes;
USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName;
PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW = NULL;
// Get the length of the name of the driver key of the device attached to
// the specified port.
//
driverKeyName.ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
&driverKeyName,
sizeof(driverKeyName),
&driverKeyName,
sizeof(driverKeyName),
&nBytes,
NULL);
if (!success)
{
return "";
}
// Allocate space to hold the driver key name
//
nBytes = driverKeyName.ActualLength;
if (nBytes <= sizeof(driverKeyName))
{
return "";
}
driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)new BYTE[nBytes];
if (driverKeyNameW == NULL)
{
delete[] driverKeyNameW;
return "";
}
// Get the name of the driver key of the device attached to
// the specified port.
//
driverKeyNameW->ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
driverKeyNameW,
nBytes,
driverKeyNameW,
nBytes,
&nBytes,
NULL);
if (!success)
{
delete[] driverKeyNameW;
return "";
}
// Convert the driver key name
//
USES_CONVERSION;
std::string driverKeyNameA = W2A(driverKeyNameW->DriverKeyName);
delete[] driverKeyNameW;
return driverKeyNameA;
}
const std::string GetExternalHubName(HANDLE Hub, ULONG ConnectionIndex)
{
BOOL success;
ULONG nBytes;
USB_NODE_CONNECTION_NAME extHubName;
PUSB_NODE_CONNECTION_NAME extHubNameW = NULL;
std::string extHubNameA;
// Get the length of the name of the external hub attached to the
// specified port.
//
extHubName.ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_NAME,
&extHubName,
sizeof(extHubName),
&extHubName,
sizeof(extHubName),
&nBytes,
NULL);
if (!success)
{
goto GetExternalHubNameError;
}
// Allocate space to hold the external hub name
//
nBytes = extHubName.ActualLength;
if (nBytes <= sizeof(extHubName))
{
goto GetExternalHubNameError;
}
extHubNameW = (PUSB_NODE_CONNECTION_NAME) new BYTE[nBytes];
if (extHubNameW == NULL)
{
goto GetExternalHubNameError;
}
// Get the name of the external hub attached to the specified port
//
extHubNameW->ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_NAME,
extHubNameW,
nBytes,
extHubNameW,
nBytes,
&nBytes,
NULL);
if (!success)
{
goto GetExternalHubNameError;
}
// Convert the External Hub name
//
USES_CONVERSION;
extHubNameA = W2A(extHubNameW->NodeName);
// All done, free the uncoverted external hub name and return the
// converted external hub name
//
delete []extHubNameW;
return extHubNameA;
GetExternalHubNameError:
// There was an error, free anything that was allocated
//
if (extHubNameW != NULL)
{
delete [](extHubNameW);
extHubNameW = NULL;
}
return NULL;
}
void EnumerateHub(std::string rootHubName, bool bRoot = false);
void EnumerateHubPorts(LPCTSTR _lpcHubName, HANDLE hHubDevice, ULONG NumPorts, bool bFindAnc, bool bRoot)
{
UNREFERENCED_PARAMETER(bFindAnc);
UNREFERENCED_PARAMETER(bRoot);
ULONG index;
BOOL success;
std::string strDebug;
PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx;
std::string driverKeyName;
std::string deviceDesc;
BOOL bHaveOneHubPort = FALSE;
// Loop over all ports of the hub.
//
// Port indices are 1 based, not 0 based.
//
for (index=1; index <= NumPorts; index++)
{
ULONG nBytesEx;
// Allocate space to hold the connection info for this port.
// For now, allocate it big enough to hold info for 30 pipes.
//
// Endpoint numbers are 0-15. Endpoint number 0 is the standard
// control endpoint which is not explicitly listed in the Configuration
// Descriptor. There can be an IN endpoint and an OUT endpoint at
// endpoint numbers 1-15 so there can be a maximum of 30 endpoints
// per device configuration.
//
// Should probably size this dynamically at some point.
//
nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
sizeof(USB_PIPE_INFO) * 30;
connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)new BYTE[nBytesEx];
if (connectionInfoEx == NULL)
{
break;
}
//
// Now query USBHUB for the USB_NODE_CONNECTION_INFORMATION_EX structure
// for this port. This will tell us if a device is attached to this
// port, among other things.
//
connectionInfoEx->ConnectionIndex = index;
success = DeviceIoControl(hHubDevice,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
connectionInfoEx,
nBytesEx,
connectionInfoEx,
nBytesEx,
&nBytesEx,
NULL);
if (!success)
{
PUSB_NODE_CONNECTION_INFORMATION connectionInfo;
ULONG nBytes;
// Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION
// instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
//
nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + sizeof(USB_PIPE_INFO) * 30;
connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)new BYTE[nBytes];
connectionInfo->ConnectionIndex = index;
success = DeviceIoControl(hHubDevice,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
connectionInfo,
nBytes,
connectionInfo,
nBytes,
&nBytes,
NULL);
if (!success)
{
delete []connectionInfo;
delete []connectionInfoEx;
continue;
}
// Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into
// IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure.
//
connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex;
connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor;
connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue;
connectionInfoEx->Speed = connectionInfo->LowSpeed ? 0 : 1;
connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub;
connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress;
connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes;
connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus;
memcpy(&connectionInfoEx->PipeList[0],
&connectionInfo->PipeList[0],
sizeof(USB_PIPE_INFO) * 30);
delete []connectionInfo;
}
// If there is a device connected, get the Device Description
//
if (connectionInfoEx->ConnectionStatus != NoDeviceConnected)
{
driverKeyName = GetDriverKeyName(hHubDevice,index);
_strupr_s(const_cast<char*>(deviceDesc.c_str()), deviceDesc.length()+1);
if (connectionInfoEx->DeviceIsHub)
{
std::string extHubName = GetExternalHubName(hHubDevice, index);
EnumerateHub(extHubName);
bHaveOneHubPort = TRUE;
}
}
delete []connectionInfoEx;
}
}
std::string GetRootHubName(HANDLE HostController)
{
BOOL success;
ULONG nBytes;
USB_ROOT_HUB_NAME rootHubName;
PUSB_ROOT_HUB_NAME rootHubNameW= NULL;
std::string rootHubNameA;
// Get the length of the name of the Root Hub attached to the
// Host Controller
//
success = DeviceIoControl(HostController,
IOCTL_USB_GET_ROOT_HUB_NAME,
0,
0,
&rootHubName,
sizeof(rootHubName),
&nBytes,
NULL);
if (!success)
{
goto GetRootHubNameError;
}
// Allocate space to hold the Root Hub name
//
nBytes = rootHubName.ActualLength;
rootHubNameW = (PUSB_ROOT_HUB_NAME)new BYTE[nBytes];
if (rootHubNameW == NULL)
{
goto GetRootHubNameError;
}
// Get the name of the Root Hub attached to the Host Controller
//
success = DeviceIoControl(HostController,
IOCTL_USB_GET_ROOT_HUB_NAME,
NULL,
0,
rootHubNameW,
nBytes,
&nBytes,
NULL);
if (!success)
{
goto GetRootHubNameError;
}
// Convert the Root Hub name
//
USES_CONVERSION;
rootHubNameA = W2A(rootHubNameW->RootHubName);
// All done, free the uncoverted Root Hub name and return the
// converted Root Hub name
//
delete []rootHubNameW;
return rootHubNameA;
GetRootHubNameError:
// There was an error, free anything that was allocated
//
if (rootHubNameW != NULL)
{
delete []rootHubNameW;
rootHubNameW = NULL;
}
return "";
}
void EnumerateHub(std::string rootHubName, bool bRoot /*= false*/)
{
if (rootHubName.empty())
{
return;
}
_strupr_s(const_cast<char*>(rootHubName.c_str()), rootHubName.length()+1);
std::string DeviceName;
HANDLE hHubDevice;
USB_NODE_INFORMATION hubInfo;
ULONG nBytes;
DeviceName = "\\\\.\\";
DeviceName += rootHubName;
hHubDevice = CreateFile(DeviceName.c_str(),
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hHubDevice != INVALID_HANDLE_VALUE)
{
if (DeviceIoControl(hHubDevice,
IOCTL_USB_GET_NODE_INFORMATION,
&hubInfo,
sizeof(USB_NODE_INFORMATION),
&hubInfo,
sizeof(USB_NODE_INFORMATION),
&nBytes,
NULL))
{
EnumerateHubPorts(
rootHubName.c_str(),
hHubDevice,
hubInfo.u.HubInformation.HubDescriptor.bNumberOfPorts,
0,
bRoot);
CloseHandle(hHubDevice);
}
}
}
DWORD EnumeAllDeviceByDeviceIOControl()
{
const int MAX_HCD_COUNT = 10;
char hcdName[16] = {0};
for (int nHCDNo = 0; nHCDNo < MAX_HCD_COUNT; nHCDNo++)
{
sprintf_s(hcdName, "\\\\.\\HCD%d", nHCDNo);
HANDLE hHCDev = CreateFile(hcdName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hHCDev == INVALID_HANDLE_VALUE)
continue;
std::string strRootHubName = GetRootHubName(hHCDev);
if (strRootHubName.empty())
continue;
EnumerateHub(strRootHubName.c_str(), true);
}
return 0;
}
5. 几种方式的关系
5.1. SetupAPI与CM
- SetupDiEnumDeviceInfo和SetupDiGetDeviceInterfaceDetail都可以获取到设备实例句柄,供CM序列函数使用。
- SetupGet获取的属性与CM_Get获取的属性基本相同。
5.2. DeviceIoControl与SetupAPI及CM序列函数
- DeviceIoControl中的IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME可以获取设备驱动名,可以与设备信息集中的驱动名属性以及CM注册表的属性名相匹配。
- SetupDiGetDeviceInterfaceDetail可以获取设备路径,可以供CreateFile打开然后通过DeviceIoControl的IOCTL_STORAGE_GET_DEVICE_NUMBER获取物理设备名。