遍历Windows USB设备树的几种方法

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获取物理设备名。
  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值