ドライブ名からデバイス情報を取得する(DEVINST系)

test106.gif
「C:」などのドライブレターと接続されているデバイスとを関連付ける方法にはいくつかある。ここではDEVINSTを返すCM_系APIを利用した。この方法を利用するとDeviceIoControlに渡すためのハンドルをCreateFileで取得できる。

依存環境:ATL
#include "winioctl.h"
#include "cfgmgr32.h"
#pragma	comment(lib,"setupapi.lib")

#include "atlstr.h"


//
//	使用中のドライブレター取得
//
//ドライブ名が文字列として列挙されて返る。例:AとC、Dドライブが使われているなら"ACD"
//
bool	GetUsedDriveLetter(TCHAR* pszLetter,int nSize)
{
	int		i;
	int		nIndex;
	TCHAR	cbDrive;
	DWORD	dwDrives;

	if(pszLetter == NULL || nSize <= 0)
		return	false;

	dwDrives = ::GetLogicalDrives();

	ZeroMemory(pszLetter,sizeof(TCHAR) * nSize);
	nIndex = 0;
	cbDrive = _T('A');
	for(i = 0; i <= 'Z' - 'A'; i++)
	{
		if(! ((1 << i) & dwDrives))
			continue;

		pszLetter[nIndex++] = cbDrive + i;
		if(nIndex < nSize)
			continue;

		return	(dwDrives << (i+1)) ? false : true;
	}

	return	true;
}





//
//	DEVINSTのプロパティ文字列取得
//
//CM_Get_DevNode_Registry_Propertyにより文字列データを取得する
//
bool	GetDevNodeRegistryProperty(DEVINST devInst,ULONG nProperty,CAtlString* pstrText)
{
	ULONG	nDataSize;
	BYTE*	pData;
	CONFIGRET	ret;

	if(pstrText == NULL)
		return	false;
	*pstrText = _T("");

	nDataSize = 0;
	ret = ::CM_Get_DevNode_Registry_Property(devInst,nProperty,NULL,NULL,&nDataSize,0);
	pData = new BYTE[nDataSize];
	ret = ::CM_Get_DevNode_Registry_Property(devInst,nProperty,NULL,pData,&nDataSize,0);
	if(ret == CR_SUCCESS)
		*pstrText = (TCHAR*)pData;
	if(pData)
		delete	pData;

	return	(ret == CR_SUCCESS) ? true : false;
}




//
//	DEVINSTデバイス検索例
//
//「C:」などのドライブレターからQueryDosDeviceで取得できる文字列と同じ場所を示すDEVINSTを探す
//
bool	SearchDEVINSTDevice(LPCTSTR pszPhysicalDeviceName)
{
	bool		ret;
	DEVINST     devInst;
	DEVINST     devInstNext;
	CONFIGRET   cRet;
	CAtlString	strText;

	cRet = ::CM_Locate_DevNode(&devInst,NULL,0);
	if(cRet != CR_SUCCESS)
		return	false;

	while(1)
	{
		ret = GetDevNodeRegistryProperty(devInst,CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,&strText);
		if(ret == false || strText != pszPhysicalDeviceName)
		{
			cRet = ::CM_Get_Child(&devInstNext,devInst,0);
			if(cRet == CR_SUCCESS)
			{
				devInst = devInstNext;
				continue;
			}

			while(1)
			{
				cRet = ::CM_Get_Sibling(&devInstNext,devInst,0);
				if(cRet == CR_SUCCESS)
				{
					devInst = devInstNext;
					break;
				}

				cRet = ::CM_Get_Parent(&devInstNext,devInst,0);
				if(cRet != CR_SUCCESS)
					return	false;

				devInst = devInstNext;
			}
			continue;
		}


		//デバイスが見つかったときの処理例(ここから)
		{
			CAtlString	strBuff;
			CAtlString	strMessage;

			//プロパティをいくつか取得してメッセージボックスに表示
			ret = GetDevNodeRegistryProperty(devInst,CM_DRP_DEVICEDESC,&strText);
			if(ret)
			{
				strBuff.Format(_T("CM_DRP_DEVICEDESC:%s\n"),strText);
				strMessage += strBuff;
			}
			ret = GetDevNodeRegistryProperty(devInst,CM_DRP_HARDWAREID,&strText);
			if(ret)
			{
				strBuff.Format(_T("CM_DRP_HARDWAREID:%s\n"),strText);
				strMessage += strBuff;
			}
			ret = GetDevNodeRegistryProperty(devInst,CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,&strText);
			if(ret)
			{
				strBuff.Format(_T("CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:%s\n"),strText);
				strMessage += strBuff;
			}

			{
				//デバイスIDを取得してCreateFileで開く
				TCHAR	pszDeviceID[2048];
				cRet = ::CM_Get_Device_ID(devInst,pszDeviceID,2048,0);
				if(cRet == CR_SUCCESS)
				{
					strBuff.Format(_T("CM_Get_Device_ID:%s\n"),pszDeviceID);
					strMessage += strBuff;
				}

				if(cRet == CR_SUCCESS)
				{
					int		nFind;
					HANDLE	hDevice;
					CAtlString	strDevice;

					//開けるのデバイスIDに_??_が含まれているもののみ?
					//_??_以降を取り出して先頭に\\\\?\\を付加してCreateFileで開く
					strDevice = pszDeviceID;
					nFind = strDevice.Find(_T("_??_"));
					if(nFind > 0)
					{
						strDevice = strDevice.Right(strDevice.GetLength() - nFind - 4);
						strDevice = _T("\\\\?\\") + strDevice;

						hDevice = CreateFile(strDevice,GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
						if(hDevice != INVALID_HANDLE_VALUE)
						{
							//ハンドルを取得できた(DeviceIoControlで利用可能)
							::CloseHandle(hDevice);
						}
					}
				}

			}

			::MessageBox(NULL,strMessage,_T(""),MB_OK);
		}
		//デバイスが見つかったときの処理例(ここまで)
		return	true;
	}

	return false;
}






bool	Test()
{
	bool	ret;
	size_t	i;
	size_t	nSize;
	TCHAR	pszDrives[256];

	//使われている全ドライブを取得
	ret = GetUsedDriveLetter(pszDrives,256);
	if(ret == false)
		return	false;

	//ドライブごとに処理
	nSize = ::_tcslen(pszDrives);
	for(i = 0; i < nSize; i++)
	{
		DWORD		dwRet;
		TCHAR		pszTargetPath[MAX_PATH];
		CAtlString	strDrive;

		strDrive.Format(_T("%c:"),pszDrives[i]);
		dwRet = ::QueryDosDevice(strDrive,pszTargetPath,MAX_PATH);
		if(dwRet == 0)
			continue;

		ret = SearchDEVINSTDevice(pszTargetPath);
	}

	return	true;
}

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


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