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