USBデバイスやUSBハブの詳細情報を取得する

test107.gif
USBメモリーでPCをロックするソフトなど、近頃USBデバイス情報を利用したソフトウエアが増えてきた。とは言うものの肝心の取得方法に関する情報はあまり見当たらない。

USBデバイスの情報を取得する一番の情報源はDDKに含まれるサンプルコード「USBView」だ。しかしこのソースコードは非常に読みずらく、ほかに流用しずらい。ということでここではUSBViewを流用しやすい形に成型しなおした。



ちなみに一番興味持たれる可能性が高いUSBデバイスのシリアル番号「iSerialNumber」情報についてだが...この情報はかなり信用できないようだ。

図の実行結果ではコンパクトフラッシュやSDカード、HDDドライブなどいくつかのいわゆる「USB 大容量記憶装置」を接続した。
まず、「USB スマート カード リーダー」に挿入したSDカードに関する情報はiSerialNumberを含め、まったく取得できていない。
次に、Express Cardスロットにアダプターを介して挿入したCFカードに関する情報はiSerialNumberをっ含めて取得できた。しかし取得できた値は利用したCFカードアダプターのものであり、コンパクトフラッシュメディアの情報ではない。
巷にはこのiSerialNumberを利用したデータの暗号化ソフトやPCロックソフトなどが出回っているが、その利用には注意しなければいけない場合もありそうだ。



最新のWindows Vistaに対応した最新のDDK(Windows Driver Kit)の入手先などの情報はこちらのページです。

依存環境:ATL
//
//USBデバイス情報の取得
//
//ここではDDK/WDKに含まれるサンプルソースコード「USBView」を
//そのまま利用しています。流用の際にはライセンスに気をつけて
//ください。
//
//■Windows Driver Kitの入手先などの情報
//http://www.usefullcode.net/2006/12/windows_driver_kit.html
//




#include "winioctl.h"
#include "cfgmgr32.h"
#include "setupapi.h"
#pragma	comment(lib,"setupapi.lib")



//////////////////////////////////////////
//DDKに含まれるヘッダーファイルを2つ使用
//
//「C:\WINDDK\6000\inc\wxp,C:\WINDDK\6000\inc\crt,C:\WINDDK\6000\inc\api」
//をVisual Studioのincludeパス設定へ追加すること!
//※DDKのインストール先に合わせてパスを修正する必要があります
//
//ここではWindows Vistaに対応したWindows Driver Kitを利用しました。
//
#include <usbioctl.h>
#include <usbiodef.h>



#include "atlstr.h"
#include "atlcoll.h"

#include "DnpTreeData.h"



const	TCHAR* ConnectionStatuses[] =
{
	_T("NoDeviceConnected"),
	_T("DeviceConnected"),
	_T("DeviceFailedEnumeration"),
	_T("DeviceGeneralFailure"),
	_T("DeviceCausedOvercurrent"),
	_T("DeviceNotEnoughPower")
};


class	CUsbInfo
{
protected:

	class	CStringDescriptor
	{
	public:
		CStringDescriptor()
		{
			_nDescriptorIndex = 0;
			_nLanguageID = 0;
		}

		UCHAR		_nDescriptorType;
		UCHAR		_nDescriptorIndex;
		USHORT		_nLanguageID;
		CAtlString	_strDescriptor;

		CAtlArray<BYTE>	_acbRawString;
	};








	bool	DriverNameToDeviceDesc(LPCTSTR pszDriverName, BOOLEAN DeviceId,CAtlString& strDesc)
	{
		DEVINST     devInst;
		DEVINST     devInstNext;
		CONFIGRET   cr;
		ULONG       len;
		TCHAR		buf[MAX_DEVICE_ID_LEN];

		strDesc = _T("");

		// Get Root DevNode
		//
		cr = ::CM_Locate_DevNode(&devInst,NULL,0);
		if (cr != CR_SUCCESS)
			return false;

		// Do a depth first search for the DevNode with a matching
		// DriverName value
		//
		while(1)
		{
			// Get the DriverName value
			//
			len = MAX_DEVICE_ID_LEN;
			cr = ::CM_Get_DevNode_Registry_Property(devInst,CM_DRP_DRIVER,NULL,buf,&len,0);

			if(cr != CR_SUCCESS || _tcsicmp (pszDriverName,buf) != 0)
			{
				// 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.
				//
				while(1)
				{
					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
						return	false;
				}
				continue;
			}


			// If the DriverName value matches, return the DeviceDescription
			//
			len = sizeof(buf);

			if (DeviceId)
				cr = ::CM_Get_Device_ID(devInst,buf,len,0);
			else
				cr = ::CM_Get_DevNode_Registry_Property(devInst,CM_DRP_DEVICEDESC,NULL,buf,&len,0);
			if (cr == CR_SUCCESS)
			{
				strDesc = buf;
				return true;
			}
			return false;
		}

		return false;
	}

	//*****************************************************************************
	//
	// GetHCDDriverKeyName()
	//
	//*****************************************************************************

	bool	GetHCDDriverKeyName (HANDLE HCD,CAtlString& strDriverKeyName)
	{
		BOOL	ret;
		ULONG	nBytes;
		USB_HCD_DRIVERKEY_NAME	sDriverKeyName;
		PUSB_HCD_DRIVERKEY_NAME	pDriverKeyName;

		strDriverKeyName = _T("");
		::ZeroMemory(&sDriverKeyName,sizeof(USB_HCD_DRIVERKEY_NAME));
		ret = ::DeviceIoControl(HCD,IOCTL_GET_HCD_DRIVERKEY_NAME,
								  &sDriverKeyName,sizeof(USB_HCD_DRIVERKEY_NAME),
								  &sDriverKeyName,sizeof(USB_HCD_DRIVERKEY_NAME),&nBytes,NULL);
		if(ret == FALSE)
			return	false;

		nBytes = sDriverKeyName.ActualLength;
		if (nBytes <= sizeof(USB_HCD_DRIVERKEY_NAME))
			return	false;

		pDriverKeyName = (PUSB_HCD_DRIVERKEY_NAME)new BYTE[nBytes];
		if (pDriverKeyName == NULL)
			return	false;

		::ZeroMemory(pDriverKeyName,nBytes);
		ret = ::DeviceIoControl(HCD,IOCTL_GET_HCD_DRIVERKEY_NAME,
								  pDriverKeyName,nBytes,
								  pDriverKeyName,nBytes,&nBytes,NULL);

		if(ret)
			strDriverKeyName = pDriverKeyName->DriverKeyName;

		delete	pDriverKeyName;

		return ret ? true : false;
	}






	//*****************************************************************************
	//
	// GetRootHubName()
	//
	//*****************************************************************************

	bool	GetRootHubName(HANDLE HostController,CAtlString& strRootHubName)
	{
		BOOL	ret;
		ULONG	nBytes;
		USB_ROOT_HUB_NAME	sRootHubName;
		PUSB_ROOT_HUB_NAME	pRootHubName;

		strRootHubName = _T("");
		ret = ::DeviceIoControl(HostController,IOCTL_USB_GET_ROOT_HUB_NAME,NULL,0,&sRootHubName,sizeof(USB_ROOT_HUB_NAME),&nBytes,NULL);
		if (!ret)
			return	false;

		nBytes = sRootHubName.ActualLength;
		pRootHubName = (PUSB_ROOT_HUB_NAME)new BYTE[nBytes];
		if (pRootHubName == NULL)
			return	false;

		ret = ::DeviceIoControl(HostController,IOCTL_USB_GET_ROOT_HUB_NAME,NULL,0,pRootHubName,nBytes,&nBytes,NULL);
		if(ret)
			strRootHubName = pRootHubName->RootHubName;

		delete	pRootHubName;

		return ret ? true : false;
	}




	//*****************************************************************************
	//
	// GetDriverKeyName()
	//
	//*****************************************************************************

	bool	GetDriverKeyName (HANDLE Hub,ULONG ConnectionIndex,CAtlString& strDriverKeyName)
	{
		BOOL	ret;
		ULONG	nBytes;
		USB_NODE_CONNECTION_DRIVERKEY_NAME	sDriverKeyName;
		PUSB_NODE_CONNECTION_DRIVERKEY_NAME	pDriverKeyName;

		strDriverKeyName = _T("");

		::ZeroMemory(&sDriverKeyName,sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME));
		sDriverKeyName.ConnectionIndex = ConnectionIndex;
		ret = ::DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
								  &sDriverKeyName,sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
								  &sDriverKeyName,sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
								  &nBytes,NULL);
		if (!ret)
			return	false;

		nBytes = sDriverKeyName.ActualLength;
		if (nBytes <= sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME))
			return	false;

		pDriverKeyName = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)new BYTE[nBytes];
		if(pDriverKeyName == NULL)
			return	false;

		::ZeroMemory(pDriverKeyName,nBytes);
		pDriverKeyName->ConnectionIndex = ConnectionIndex;
		ret = ::DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
								  pDriverKeyName,nBytes,
								  pDriverKeyName,nBytes,
								  &nBytes,NULL);
		if(ret)
			strDriverKeyName = pDriverKeyName->DriverKeyName;

		delete	pDriverKeyName;

		return ret ? true : false;
	}





	//*****************************************************************************
	//
	// GetConfigDescriptor()
	//
	// hHubDevice - Handle of the hub device containing the port from which the
	// Configuration Descriptor will be requested.
	//
	// ConnectionIndex - Identifies the port on the hub to which a device is
	// attached from which the Configuration Descriptor will be requested.
	//
	// DescriptorIndex - Configuration Descriptor index, zero based.
	//
	//*****************************************************************************

	PUSB_DESCRIPTOR_REQUEST
	GetConfigDescriptor (
		HANDLE  hHubDevice,
		ULONG   ConnectionIndex,
		UCHAR   DescriptorIndex
	)
	{
		BOOL    success;
		ULONG   nBytes;
		ULONG   nBytesReturned;

		UCHAR   configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_CONFIGURATION_DESCRIPTOR)];

		PUSB_DESCRIPTOR_REQUEST         configDescReq;
		PUSB_CONFIGURATION_DESCRIPTOR   configDesc;


		// Request the Configuration Descriptor the first time using our
		// local buffer, which is just big enough for the Cofiguration
		// Descriptor itself.
		//
		nBytes = sizeof(configDescReqBuf);

		configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf;
		configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);

		::ZeroMemory(configDescReq,nBytes);

		// Indicate the port from which the descriptor will be requested
		//
		configDescReq->ConnectionIndex = ConnectionIndex;

		//
		// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
		// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
		//
		// USBD will automatically initialize these fields:
		//     bmRequest = 0x80
		//     bRequest  = 0x06
		//
		// We must inititialize these fields:
		//     wValue    = Descriptor Type (high) and Descriptor Index (low byte)
		//     wIndex    = Zero (or Language ID for String Descriptors)
		//     wLength   = Length of descriptor buffer
		//
		configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | DescriptorIndex;
		configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

		success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
								  configDescReq,nBytes,
								  configDescReq,nBytes,
								  &nBytesReturned,NULL);

		if(success == FALSE || nBytes != nBytesReturned)
			return	NULL;

		if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
			return NULL;

		// Now request the entire Configuration Descriptor using a dynamically
		// allocated buffer which is sized big enough to hold the entire descriptor
		//
		nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength;

		configDescReq = (PUSB_DESCRIPTOR_REQUEST)new BYTE[nBytes];
		if (configDescReq == NULL)
			return NULL;
		::ZeroMemory(configDescReq,nBytes);

		configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);

		// Indicate the port from which the descriptor will be requested
		//
		configDescReq->ConnectionIndex = ConnectionIndex;

		//
		// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
		// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
		//
		// USBD will automatically initialize these fields:
		//     bmRequest = 0x80
		//     bRequest  = 0x06
		//
		// We must inititialize these fields:
		//     wValue    = Descriptor Type (high) and Descriptor Index (low byte)
		//     wIndex    = Zero (or Language ID for String Descriptors)
		//     wLength   = Length of descriptor buffer
		//
		configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | DescriptorIndex;
		configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

		success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
								  configDescReq,nBytes,
								  configDescReq,nBytes,
								  &nBytesReturned,NULL);

		if(success == FALSE || nBytes != nBytesReturned)
		{
			//OOPS();
			delete	(configDescReq);
			return NULL;
		}

		if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)))
		{
			//OOPS();
			delete	(configDescReq);
			return NULL;
		}

		return configDescReq;
	}




	//*****************************************************************************
	//
	// GetStringDescriptor()
	//
	// hHubDevice - Handle of the hub device containing the port from which the
	// String Descriptor will be requested.
	//
	// ConnectionIndex - Identifies the port on the hub to which a device is
	// attached from which the String Descriptor will be requested.
	//
	// DescriptorIndex - String Descriptor index.
	//
	// LanguageID - Language in which the string should be requested.
	//
	//*****************************************************************************

	bool	GetStringDescriptor (
		HANDLE  hHubDevice,
		ULONG   ConnectionIndex,
		UCHAR   DescriptorIndex,
		USHORT  LanguageID,
		CAtlArray<CStringDescriptor>& acDescriptor
	)
	{
		BOOL    success;
		ULONG   nBytes;
		ULONG   nBytesReturned;

		UCHAR   stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];

		PUSB_DESCRIPTOR_REQUEST stringDescReq;
		PUSB_STRING_DESCRIPTOR  stringDesc;

		nBytes = sizeof(stringDescReqBuf);

		stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;
		stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);

		//
		// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
		// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
		//
		// USBD will automatically initialize these fields:
		//     bmRequest = 0x80
		//     bRequest  = 0x06
		//
		// We must inititialize these fields:
		//     wValue    = Descriptor Type (high) and Descriptor Index (low byte)
		//     wIndex    = Zero (or Language ID for String Descriptors)
		//     wLength   = Length of descriptor buffer
		//
		::ZeroMemory(stringDescReq,nBytes);
		stringDescReq->ConnectionIndex = ConnectionIndex;
		stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | DescriptorIndex;
		stringDescReq->SetupPacket.wIndex = LanguageID;
		stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

		success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
								  stringDescReq,nBytes,
								  stringDescReq,nBytes,
								  &nBytesReturned,NULL);

		if (!success || nBytesReturned < 2)
			return false;

		if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
			return false;

		if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))
			return false;

		if (stringDesc->bLength % 2 != 0)
			return false;


		size_t	nIndex;

		nIndex = acDescriptor.GetCount();
		acDescriptor.SetCount(nIndex + 1);

		acDescriptor[nIndex]._nDescriptorType	= stringDesc->bDescriptorType;
		acDescriptor[nIndex]._nDescriptorIndex	= DescriptorIndex;
		acDescriptor[nIndex]._nLanguageID		= LanguageID;
		acDescriptor[nIndex]._strDescriptor		= stringDesc->bString;

		acDescriptor[nIndex]._acbRawString.SetCount(stringDesc->bLength);
		memcpy(acDescriptor[nIndex]._acbRawString.GetData(),stringDesc->bString,acDescriptor[nIndex]._acbRawString.GetCount());

		return true;
	}

	//*****************************************************************************
	//
	// GetStringDescriptors()
	//
	// hHubDevice - Handle of the hub device containing the port from which the
	// String Descriptor will be requested.
	//
	// ConnectionIndex - Identifies the port on the hub to which a device is
	// attached from which the String Descriptor will be requested.
	//
	// DescriptorIndex - String Descriptor index.
	//
	// NumLanguageIDs -  Number of languages in which the string should be
	// requested.
	//
	// LanguageIDs - Languages in which the string should be requested.
	//
	//*****************************************************************************

	bool	GetStringDescriptors (
		HANDLE  hHubDevice,
		ULONG   ConnectionIndex,
		UCHAR   DescriptorIndex,
		ULONG   NumLanguageIDs,
		USHORT  *LanguageIDs,
		CAtlArray<CStringDescriptor>& acDescriptor
	)
	{
		ULONG	i;
		bool	ret;

		for (i=0; i<NumLanguageIDs; i++)
		{
			ret = GetStringDescriptor(hHubDevice,ConnectionIndex,DescriptorIndex,*LanguageIDs,acDescriptor);
			LanguageIDs++;
		}

		return true;
	}


	//*****************************************************************************
	//
	// GetAllStringDescriptors()
	//
	// hHubDevice - Handle of the hub device containing the port from which the
	// String Descriptors will be requested.
	//
	// ConnectionIndex - Identifies the port on the hub to which a device is
	// attached from which the String Descriptors will be requested.
	//
	// DeviceDesc - Device Descriptor for which String Descriptors should be
	// requested.
	//
	// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
	// for which String Descriptors should be requested.
	//
	//*****************************************************************************

	bool
	GetAllStringDescriptors (
		HANDLE                          hHubDevice,
		ULONG                           ConnectionIndex,
		PUSB_DEVICE_DESCRIPTOR          DeviceDesc,
		CAtlArray<CStringDescriptor>& acDescriptor
	)
	{
		bool	ret;

		ULONG	numLanguageIDs;
		USHORT*	languageIDs;
		PUCHAR	descEnd;

		PUSB_COMMON_DESCRIPTOR			commonDesc;
		PUSB_CONFIGURATION_DESCRIPTOR	ConfigDesc;

		CAtlArray<CStringDescriptor>	acLanguageIDDescriptor;

		////////////////////////////////
		//文字列情報が存在するかチェック
		//
		ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)GetConfigDescriptor(hHubDevice,ConnectionIndex,0);
		if(ConfigDesc == NULL)
		{
			//取得できるString Descriptorsがない
			delete	ConfigDesc;
			return	true;
		}
		//注意:上の処理を通っても確実に文字列情報があるとは限らない



		////////////////////////////////
		//文字列の言語種と言語数を取得
		//
		ret = GetStringDescriptor(hHubDevice,ConnectionIndex,0,0,acLanguageIDDescriptor);
		if (ret == false)
		{
			delete	ConfigDesc;
			return false;
		}

		numLanguageIDs = ((ULONG)acLanguageIDDescriptor[0]._acbRawString.GetCount() - 2) / 2;
		languageIDs = (USHORT*)new BYTE[acLanguageIDDescriptor[0]._acbRawString.GetCount()];
		if(languageIDs == NULL)
		{
			delete	ConfigDesc;
			return false;
		}
		memcpy(languageIDs,acLanguageIDDescriptor[0]._acbRawString.GetData(),acLanguageIDDescriptor[0]._acbRawString.GetCount());



		////////////////////////////////
		//文字列を取得
		//

		if (DeviceDesc->iManufacturer)
			ret = GetStringDescriptors(hHubDevice,ConnectionIndex,DeviceDesc->iManufacturer,numLanguageIDs,languageIDs,acDescriptor);

		if (DeviceDesc->iProduct)
			ret = GetStringDescriptors(hHubDevice,ConnectionIndex,DeviceDesc->iProduct,numLanguageIDs,languageIDs,acDescriptor);

		if (DeviceDesc->iSerialNumber)
			ret = GetStringDescriptors(hHubDevice,ConnectionIndex,DeviceDesc->iSerialNumber,numLanguageIDs,languageIDs,acDescriptor);


		descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;

		commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;
		while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)
		{
			switch (commonDesc->bDescriptorType)
			{
				case USB_CONFIGURATION_DESCRIPTOR_TYPE:
				case USB_INTERFACE_DESCRIPTOR_TYPE:
					if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))
					{
						//OOPS();
						break;
					}
					if(commonDesc->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE && ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)
					{
						ret = GetStringDescriptors(hHubDevice,ConnectionIndex,
												 ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration,
												 numLanguageIDs,languageIDs,acDescriptor);
					}
					else if(commonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE && ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)
					{
						ret = GetStringDescriptors(hHubDevice,ConnectionIndex,
												 ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface,
												 numLanguageIDs,languageIDs,acDescriptor);
					}
					//ここにbreak;を配置しないこと!
				default:
					commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
					continue;
			}
			break;
		}

		delete	languageIDs;
		delete	ConfigDesc;

		return true;
	}



	//*****************************************************************************
	//
	// GetExternalHubName()
	//
	//*****************************************************************************

	bool	GetExternalHubName (HANDLE Hub,ULONG ConnectionIndex,CAtlString& strExternalHubName)
	{
		BOOL	ret;
		ULONG	nBytes;
		USB_NODE_CONNECTION_NAME	extHubName;
		PUSB_NODE_CONNECTION_NAME	extHubNameW;

		strExternalHubName = _T("");

		::ZeroMemory(&extHubName,sizeof(USB_NODE_CONNECTION_NAME));
		extHubName.ConnectionIndex = ConnectionIndex;
		ret = ::DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_NAME,
								  &extHubName,sizeof(USB_NODE_CONNECTION_NAME),
								  &extHubName,sizeof(USB_NODE_CONNECTION_NAME),
								  &nBytes,NULL);
		if(ret == FALSE)
			return	false;

		nBytes = extHubName.ActualLength;
		if (nBytes <= sizeof(USB_NODE_CONNECTION_NAME))
			return	false;

		extHubNameW = (PUSB_NODE_CONNECTION_NAME)new BYTE[nBytes];
		if(extHubNameW == NULL)
			return	false;

		::ZeroMemory(extHubNameW,nBytes);
		extHubNameW->ConnectionIndex = ConnectionIndex;
		ret = ::DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_NAME,
								  extHubNameW,nBytes,
								  extHubNameW,nBytes,
								  &nBytes,NULL);

		if(ret)
			strExternalHubName = extHubNameW->NodeName;

		delete	extHubNameW;

		return ret ? true : false;
	}

















































	class	CInfo
	{
	public:
		CInfo()
		{
			_bNodeInfo = false;
			::ZeroMemory(&_sNodeInfo,sizeof(USB_NODE_INFORMATION));

			_bNodeConnectionInfoEx = false;
			//_pNodeConnectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)_pNodeConnectionInfoEx_buffer;
			::ZeroMemory(_pNodeConnectionInfoEx_buffer,sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + sizeof(USB_PIPE_INFO) * 30);

			_nPort = 0;
		}

		int			_nPort;
		CAtlString	_strName;

		CAtlArray<CStringDescriptor>	acDescriptor;

		bool	_bNodeInfo;
		USB_NODE_INFORMATION	_sNodeInfo;

		bool	_bNodeConnectionInfoEx;
		PUSB_NODE_CONNECTION_INFORMATION_EX	Get_pNodeConnectionInfoEx()
		{
			return	(PUSB_NODE_CONNECTION_INFORMATION_EX)_pNodeConnectionInfoEx_buffer;
		}
		//PUSB_NODE_CONNECTION_INFORMATION_EX	_pNodeConnectionInfoEx;

	private:
		BYTE	_pNodeConnectionInfoEx_buffer[sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + sizeof(USB_PIPE_INFO) * 30];

	};

	CAtlArray<CInfo>		_acDeviceInfo;

	CDnpTreeData<UINT>	_treeDeviceInfoIndex;







	//*****************************************************************************
	//
	// EnumerateHubPorts()
	//
	// hTreeParent - Handle of the TreeView item under which the hub port should
	// be added.
	//
	// hHubDevice - Handle of the hub device to enumerate.
	//
	// NumPorts - Number of ports on the hub.
	//
	//*****************************************************************************

	void EnumerateHubPorts(UINT nTreeIndex,HANDLE hHubDevice,ULONG NumPorts)
	{
		ULONG       index;
		BOOL        success;

		PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx;

		CAtlString	strDeviceDesc;

		// Loop over all ports of the hub.
		//
		// Port indices are 1 based, not 0 based.
		//
		for (index=1; index <= NumPorts; index++)
		{
			ULONG	nBytesEx;
			BYTE	pBuff[sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + sizeof(USB_PIPE_INFO) * 30];

			nBytesEx = sizeof(pBuff);
			connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)pBuff;
			::ZeroMemory(connectionInfoEx,nBytesEx);


			//IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EXを取得
			connectionInfoEx->ConnectionIndex = index;
			success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
									  connectionInfoEx,nBytesEx,
									  connectionInfoEx,nBytesEx,
									  &nBytesEx,NULL);

			//IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EXの代わりにIOCTL_USB_GET_NODE_CONNECTION_INFORMATIONを取得
			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];

				::ZeroMemory(connectionInfo,nBytes);
				connectionInfo->ConnectionIndex = index;
				success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
										  connectionInfo,nBytes,
										  connectionInfo,nBytes,
										  &nBytes,NULL);

				if (!success)
				{
					delete	(connectionInfo);
					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 ? UsbLowSpeed : UsbFullSpeed;
				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);
			}


			bool	ret;
			UINT	nChildTreeIndex;
			UINT	nIndex;


			//ツリーへUSBハブ/デバイスの情報を追加
			nIndex = (UINT)_acDeviceInfo.GetCount();
			_acDeviceInfo.SetCount(nIndex + 1);
			ret = _treeDeviceInfoIndex.AddData(nTreeIndex,&nChildTreeIndex,nIndex);		//子として追加
			if(ret == false)
				continue;

			_acDeviceInfo[nIndex]._bNodeConnectionInfoEx = true;
			::memcpy(_acDeviceInfo[nIndex].Get_pNodeConnectionInfoEx(),connectionInfoEx,nBytesEx);
			_acDeviceInfo[nIndex]._nPort = index;





			if(connectionInfoEx->ConnectionStatus == DeviceConnected)
				GetAllStringDescriptors(hHubDevice,index,&connectionInfoEx->DeviceDescriptor,_acDeviceInfo[nIndex].acDescriptor);




			strDeviceDesc = _T("");
			if(connectionInfoEx->ConnectionStatus != NoDeviceConnected)
			{
				bool		ret;
				CAtlString	strDriverKeyName;

				ret = GetDriverKeyName(hHubDevice,index,strDriverKeyName);
				if(ret)
					ret = DriverNameToDeviceDesc(strDriverKeyName,FALSE,strDeviceDesc);
				if(ret)
					_acDeviceInfo[nIndex]._strName = strDeviceDesc;

				//ATLTRACE(_T("%s\n"),strDeviceDesc);
			}




			if (connectionInfoEx->DeviceIsHub)
			{
				CAtlString	strExtHubName;

				ret = GetExternalHubName(hHubDevice,index,strExtHubName);
				if(ret && _acDeviceInfo[nIndex]._strName == _T(""))
					_acDeviceInfo[nIndex]._strName = strExtHubName;

				//次のUSBハブを列挙
				if(ret)
					EnumerateHub(nChildTreeIndex,strExtHubName);
			}
		}
	}








	bool	EnumerateHub(UINT nTreeIndex,LPCTSTR HubName)
	{
		HANDLE                  hHubDevice;
		BOOL                    ret;
		ULONG                   nBytes;
		USB_NODE_INFORMATION	sHubInfo;
		CAtlString	strHubName;
		CAtlString	strDeviceName;

		strDeviceName = _T("\\\\.\\");
		strDeviceName += HubName;
		hHubDevice = ::CreateFile(strDeviceName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
		if (hHubDevice == INVALID_HANDLE_VALUE)
			return	false;

		//ハブの持つポート数取得
		::ZeroMemory(&sHubInfo,sizeof(USB_NODE_INFORMATION));
		ret = ::DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_INFORMATION,
								  &sHubInfo,sizeof(USB_NODE_INFORMATION),
								  &sHubInfo,sizeof(USB_NODE_INFORMATION),&nBytes,NULL);

		if(ret && nTreeIndex < _acDeviceInfo.GetCount())
		{
			//USBハブ詳細情報の追加保存
			_acDeviceInfo[nTreeIndex]._bNodeInfo = true;
			::memcpy(&_acDeviceInfo[nTreeIndex]._sNodeInfo,&sHubInfo,sizeof(USB_NODE_INFORMATION));
		}

		if(ret)
			EnumerateHubPorts(nTreeIndex,hHubDevice,sHubInfo.u.HubInformation.HubDescriptor.bNumberOfPorts);

		::CloseHandle(hHubDevice);

		return	ret ? true : false;
	}



public:



	bool	Test()
	{
		BOOL		ret;
		HANDLE		hHCDev;
		ULONG		index;
		ULONG		nLen;
		HDEVINFO	hDevInfo;
		IID			iidUSBHostController;
		SP_DEVICE_INTERFACE_DATA			sDeviceInterfaceData;
		PSP_DEVICE_INTERFACE_DETAIL_DATA	pDeviceDetailData;


		//USBコントローラークラス用GUIDを文字列から取得
		::IIDFromString(L"{3ABF6F2D-71C4-462a-8A92-1E6861E6AF27}",&iidUSBHostController);

		//USBホストコントローラーの列挙開始
		hDevInfo = ::SetupDiGetClassDevs(&iidUSBHostController,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
		if(hDevInfo == INVALID_HANDLE_VALUE)
			return	false;

		sDeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

		index = 0;
		while(1)
		{
			//ホストコントローラーを開く
			ret = ::SetupDiEnumDeviceInterfaces(hDevInfo,0,&iidUSBHostController,index,&sDeviceInterfaceData);
			if(ret == FALSE)
				break;
			index++;

			//詳細情報サイズを取得
			ret = ::SetupDiGetDeviceInterfaceDetail(hDevInfo,&sDeviceInterfaceData,NULL,0,&nLen,NULL);

			pDeviceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) new BYTE[nLen];
			if(pDeviceDetailData == NULL)
				return	false;

			::ZeroMemory(pDeviceDetailData,nLen);
			pDeviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

			//詳細情報を取得
			ret = ::SetupDiGetDeviceInterfaceDetail(hDevInfo,&sDeviceInterfaceData,pDeviceDetailData,nLen,&nLen,NULL);
			if(ret == FALSE)
			{
				delete	pDeviceDetailData;
				continue;
			}

			//ホストコントローラーをCreateFileで開く
			hHCDev = ::CreateFile(pDeviceDetailData->DevicePath,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
			if(hHCDev == INVALID_HANDLE_VALUE)
			{
				delete	pDeviceDetailData;
				continue;
			}


			bool		bRet;
			CAtlString	strRootHubName;
			CAtlString	strDeviceDesc;
			CAtlString	strDriverKeyName;

			bRet = GetHCDDriverKeyName(hHCDev,strDriverKeyName);
			if(bRet)
				bRet = GetRootHubName(hHCDev,strRootHubName);
			::CloseHandle(hHCDev);


			UINT	nTreeIndex;

			if(bRet)
				bRet = DriverNameToDeviceDesc(strDriverKeyName,FALSE,strDeviceDesc);
			if(bRet)
			{
				//ATLTRACE(_T("%s\n"),strDeviceDesc);

				//ツリーへホストコントローラーの情報を追加
				UINT	nIndex;

				nIndex = (UINT)_acDeviceInfo.GetCount();
				_acDeviceInfo.SetCount(nIndex + 1);
				_acDeviceInfo[nIndex]._strName = strDeviceDesc;

				bRet = _treeDeviceInfoIndex.AddData(-1,&nTreeIndex,nIndex);		//ルートへ追加
			}

			//USBハブの列挙開始
			if(bRet)
				EnumerateHub(nTreeIndex,strRootHubName);

			delete	pDeviceDetailData;
		}

		::SetupDiDestroyDeviceInfoList(hDevInfo);

		return	true;
	}



	bool	PrintTreeData(CAtlArray<UINT>* panIndex=NULL,CAtlString strPrefix=_T(""))
	{
		bool	ret;
		CAtlArray<UINT>	anRootIndex;

		if(panIndex == NULL)
		{
			ret = _treeDeviceInfoIndex.GetRootItemIndex(anRootIndex);
			if(ret == false)
				return	false;
			panIndex = &anRootIndex;
		}

		size_t	i;
		size_t	nSize;

		nSize = panIndex->GetCount();
		for(i = nSize - 1; i != -1; i--)
		{
			CInfo*	pInfo;

			if((*panIndex)[i] >= _acDeviceInfo.GetCount())
				continue;

			CAtlArray<UINT>	anNextIndex;

			pInfo = &_acDeviceInfo[(*panIndex)[i]];

			//デバイス名の表示
			{
				CAtlString	strName;

				if(pInfo->_nPort && pInfo->_bNodeConnectionInfoEx)
					strName.Format(_T("[Port%d] %s "),pInfo->_nPort,ConnectionStatuses[pInfo->Get_pNodeConnectionInfoEx()->ConnectionStatus]);

				if(pInfo->_strName != _T(""))
					strName += pInfo->_strName;

				ATLTRACE("%s %s\n",strPrefix,strName);
			}

			//USBハブ情報の表示
			if(pInfo->_bNodeInfo)
			{
				CAtlString	strMessage;
				CAtlString	strBuff;

				strBuff.Format(_T("%s    bNumberOfPorts: %d\n"),strPrefix,pInfo->_sNodeInfo.u.HubInformation.HubDescriptor.bNumberOfPorts);
				strMessage += strBuff;
				//strBuff.Format(_T("%s    bPowerOnToPowerGood: 0x%02X\n"),strPrefix,pInfo->_sNodeInfo.u.HubInformation.HubDescriptor.bPowerOnToPowerGood);
				//strMessage += strBuff;
				strBuff.Format(_T("%s    bHubControlCurrent: 0x%02X\n"),strPrefix,pInfo->_sNodeInfo.u.HubInformation.HubDescriptor.bHubControlCurrent);
				strMessage += strBuff;
				//strBuff.Format(_T("%s    bRemoveAndPowerMask: 0x%02X\n"),strPrefix,pInfo->_sNodeInfo.u.HubInformation.HubDescriptor.bRemoveAndPowerMask);
				//strMessage += strBuff;

				ATLTRACE(_T("%s"),strMessage);
			}


			//デバイス/ハブ詳細情報の表示
			if(pInfo->_bNodeConnectionInfoEx && pInfo->Get_pNodeConnectionInfoEx()->ConnectionStatus == DeviceConnected)
			{
				CAtlString	strMessage;
				CAtlString	strBuff;

				strBuff.Format(_T("%s    idVendor: 0x%04X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.idVendor);
				strMessage += strBuff;

				BYTE	iData;

				iData = pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.iProduct;
				if(iData)
				{
					CAtlString	strDescriptor;
					{
						size_t	j;
						size_t	nSize;

						nSize = pInfo->acDescriptor.GetCount();
						for(j = 0; j < nSize; j++)
						{
							if(pInfo->acDescriptor[j]._nDescriptorIndex != iData)
								continue;

							strDescriptor = pInfo->acDescriptor[j]._strDescriptor;
							break;
						}
					}
					strBuff.Format(_T("%s    iProduct: 0x%02X(%s)\n"),strPrefix,iData,strDescriptor);
					strMessage += strBuff;
				}
				iData = pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.iManufacturer;
				if(iData)
				{
					CAtlString	strDescriptor;
					{
						size_t	j;
						size_t	nSize;

						nSize = pInfo->acDescriptor.GetCount();
						for(j = 0; j < nSize; j++)
						{
							if(pInfo->acDescriptor[j]._nDescriptorIndex != iData)
								continue;

							strDescriptor = pInfo->acDescriptor[j]._strDescriptor;
							break;
						}
					}
					strBuff.Format(_T("%s    iManufacturer: 0x%02X(%s)\n"),strPrefix,iData,strDescriptor);
					strMessage += strBuff;
				}
				iData = pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.iSerialNumber;
				if(iData)
				{
					CAtlString	strDescriptor;
					{
						size_t	j;
						size_t	nSize;

						nSize = pInfo->acDescriptor.GetCount();
						for(j = 0; j < nSize; j++)
						{
							if(pInfo->acDescriptor[j]._nDescriptorIndex != iData)
								continue;

							strDescriptor = pInfo->acDescriptor[j]._strDescriptor;
							break;
						}
					}
					strBuff.Format(_T("%s    iSerialNumber: 0x%02X(%s)\n"),strPrefix,iData,strDescriptor);
					strMessage += strBuff;
				}

				//strBuff.Format(_T("%s    bcdUSB: 0x%04X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.bcdUSB);
				//strMessage += strBuff;
				//strBuff.Format(_T("%s    bcdDevice: 0x%04X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.bcdDevice);
				//strMessage += strBuff;
				//strBuff.Format(_T("%s    bDeviceClass: 0x%02X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.bDeviceClass);
				//strMessage += strBuff;
				//strBuff.Format(_T("%s    bDeviceProtocol: 0x%02X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.bDeviceProtocol);
				//strMessage += strBuff;
				//strBuff.Format(_T("%s    bDeviceSubClass: 0x%02X\n"),strPrefix,pInfo->Get_pNodeConnectionInfoEx()->DeviceDescriptor.bDeviceSubClass);
				//strMessage += strBuff;

				ATLTRACE(_T("%s"),strMessage);
			}
			//else
			//{
			//	ATLTRACE(_T("\n"));
			//}





			ret = _treeDeviceInfoIndex.GetChildItemIndex((*panIndex)[i],anNextIndex);
			if(ret)
				PrintTreeData(&anNextIndex,strPrefix + _T("   "));
		}

		return	true;
	}


};


void	Test()
{
	CUsbInfo	cInfo;

	cInfo.Test();
	cInfo.PrintTreeData();
}

プロジェクトファイルをダウンロード


カテゴリー「システム情報」 のエントリー