Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

724 lines
25 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. devenum.c
  5. Abstract:
  6. Code for enum IDE ans SCSI controllers and attached to them storage devices
  7. and calculate for them SCSI Address.
  8. Author:
  9. Souren Aghajanyan (sourenag) 05-June-2001
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "devenum.h"
  14. typedef struct tagIDEController
  15. {
  16. PCTSTR pnpId;
  17. UINT defaultSCSIPort;
  18. }IDE_CONTROLLER, *PIDE_CONTROLLER;
  19. #define DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT TEXT("CurrentDriveLetterAssignment")
  20. IDE_CONTROLLER g_knownIDEControllers[] =
  21. {
  22. {TEXT("MF\\GOODPRIMARY"), 0},
  23. {TEXT("MF\\GOODSECONDARY"), 1},
  24. {TEXT("*PNP0600"), 1}
  25. };
  26. PCTSTR
  27. pRegQueryStringValue(
  28. IN HKEY hKey,
  29. IN PCTSTR ValueName,
  30. OUT PVOID Buffer,
  31. IN UINT BufferSize
  32. )
  33. {
  34. static TCHAR defaultBuffer[MAX_REG_SIZE];
  35. DWORD valueType;
  36. MYASSERT((hKey && ValueName) && ((Buffer && BufferSize) || (!Buffer)));
  37. if(!Buffer){
  38. Buffer = (PVOID)defaultBuffer;
  39. BufferSize = sizeof(defaultBuffer);
  40. }
  41. if(ERROR_SUCCESS != RegQueryValueEx(hKey,
  42. ValueName,
  43. 0,
  44. &valueType,
  45. (PBYTE)Buffer,
  46. (PULONG)&BufferSize) ||
  47. REG_SZ != valueType){
  48. return NULL;
  49. }
  50. return (PCTSTR)Buffer;
  51. }
  52. BOOL
  53. pDoesDriveExist(
  54. IN HKEY hDevice,
  55. OUT DWORD* DriveType
  56. )
  57. {
  58. DWORD driveType;
  59. PCTSTR pBufferKeyValue;
  60. TCHAR drivePath[] = TEXT("?:\\");
  61. BOOL bCDROMDevice = TRUE;
  62. if(!hDevice){
  63. return FALSE;
  64. }
  65. pBufferKeyValue = pRegQueryStringValue(hDevice, TEXT("Class"), NULL, 0);
  66. if(!pBufferKeyValue){
  67. return FALSE;
  68. }
  69. bCDROMDevice = !_tcsicmp(pBufferKeyValue, TEXT("CDROM"));
  70. pBufferKeyValue = pRegQueryStringValue(hDevice, DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT, NULL, 0);
  71. if(!pBufferKeyValue){
  72. return FALSE;
  73. }
  74. drivePath[0] = pBufferKeyValue[0];
  75. driveType = GetDriveType(drivePath);
  76. if(DriveType){
  77. *DriveType = driveType;
  78. }
  79. return bCDROMDevice? (DRIVE_CDROM == driveType):
  80. (DRIVE_NO_ROOT_DIR != driveType && DRIVE_UNKNOWN != driveType);
  81. }
  82. BOOL
  83. pGetDeviceType(
  84. IN HKEY hDevice,
  85. OUT DWORD* DriveType
  86. )
  87. {
  88. if(!DriveType){
  89. return FALSE;
  90. }
  91. return pDoesDriveExist(hDevice, DriveType);
  92. }
  93. VOID
  94. pPreparePNPIDName(
  95. IN PTSTR deviceInfoRegKey
  96. )
  97. {
  98. MYASSERT(deviceInfoRegKey);
  99. //
  100. // Replace '\\' with '&' in registry key to make PNPID
  101. //
  102. while(deviceInfoRegKey = _tcschr(deviceInfoRegKey, '\\')){
  103. *deviceInfoRegKey = '&';
  104. }
  105. }
  106. int __cdecl
  107. pControllerInfoCompare(
  108. IN const void * elem1,
  109. IN const void * elem2
  110. )
  111. {
  112. MYASSERT(elem1 && elem2);
  113. //
  114. // Sort controlers in next order: First IDE, after SCSI,
  115. // inside each group(IDE and SCSI) sort by preliminary defined SCSIPortNumber
  116. //
  117. #define PCONTROLLER_INFO_CAST(x) ((PCONTROLLER_INFO)x)
  118. if(PCONTROLLER_INFO_CAST(elem1)->ControllerType > PCONTROLLER_INFO_CAST(elem2)->ControllerType){
  119. return 1;
  120. }
  121. if(PCONTROLLER_INFO_CAST(elem1)->ControllerType < PCONTROLLER_INFO_CAST(elem2)->ControllerType){
  122. return -1;
  123. }
  124. if(PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber > PCONTROLLER_INFO_CAST(elem2)->SCSIPortNumber){
  125. return 1;
  126. }
  127. if(PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber < PCONTROLLER_INFO_CAST(elem2)->SCSIPortNumber){
  128. return -1;
  129. }
  130. MYASSERT(INVALID_SCSI_PORT == PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber);
  131. return 0;
  132. }
  133. BOOL
  134. pGatherControllersInfo(
  135. IN OUT PCONTROLLER_INFO ActiveControllersOut,
  136. IN OUT PUINT NumberOfActiveControllersOut
  137. )
  138. {
  139. TCHAR regkeyName[MAX_REG_SIZE];
  140. TCHAR deviceInfoRegKey[MAX_REG_SIZE];
  141. TCHAR deviceData[MAX_REG_SIZE];
  142. TCHAR ideHardwareID[MAX_PNPID_SIZE];
  143. HKEY hActiveDevicesRoot = NULL;
  144. HKEY hActiveDeviceRoot = NULL;
  145. HKEY hDevice = NULL;
  146. UINT itemIndexRoot;
  147. DWORD bufferLength;
  148. PTSTR pDelimeter;
  149. UINT indexAvailable = 0;
  150. UINT scsiPortNumber;
  151. UINT controllerStartIndex = 0;
  152. UINT controllersSubNumber;
  153. PCONTROLLER_INFO controllerInfo;
  154. UINT i;
  155. UINT j;
  156. CONTROLLER_TYPE deviceType;
  157. BOOL bROOTDevice;
  158. UINT ideCounter;
  159. DWORD rcResult;
  160. static CONTROLLER_TYPE controllerTypes[] = {CONTROLLER_ON_BOARD_IDE, CONTROLLER_EXTRA_IDE, CONTROLLER_SCSI};
  161. if(!NumberOfActiveControllersOut){
  162. SetLastError(ERROR_INVALID_PARAMETER);
  163. return FALSE;
  164. }
  165. __try{
  166. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
  167. return FALSE;
  168. }
  169. //
  170. // Looking for IDE and SCSI controllers in list of active hardware
  171. // under "HKDD\Config Manager\Enum"
  172. //
  173. for(itemIndexRoot = 0; ;itemIndexRoot++){
  174. bufferLength = ARRAYSIZE(regkeyName);
  175. rcResult = RegEnumKeyEx(hActiveDevicesRoot,
  176. itemIndexRoot,
  177. regkeyName,
  178. &bufferLength,
  179. 0,
  180. NULL,
  181. NULL,
  182. NULL);
  183. if(ERROR_SUCCESS != rcResult){
  184. break;
  185. }
  186. if(ERROR_SUCCESS != RegOpenKeyEx(hActiveDevicesRoot, regkeyName, 0, KEY_READ, &hActiveDeviceRoot)){
  187. continue;
  188. }
  189. do{
  190. //
  191. // "HardWareKey" consist key path to real device
  192. //
  193. if(pRegQueryStringValue(hActiveDeviceRoot,
  194. TEXT("HardWareKey"),
  195. regkeyName,
  196. sizeof(regkeyName))){
  197. if(!_tcsnicmp(regkeyName, TEXT("ROOT"), 4)){
  198. //
  199. // Sometime on board IDE controllers has preserved PNPID under ROOT,
  200. // and is not represented in MF\CHILD000x.
  201. //
  202. bROOTDevice = TRUE;
  203. deviceType = CONTROLLER_ON_BOARD_IDE;
  204. }else
  205. {
  206. if(!_tcsnicmp(regkeyName, TEXT("MF\\CHILD"), 8)){
  207. deviceType = CONTROLLER_ON_BOARD_IDE;
  208. }else if(!_tcsnicmp(regkeyName, TEXT("PCI"), 3)){
  209. deviceType = CONTROLLER_SCSI;
  210. }else{
  211. //deviceType = CONTROLLER_UNKNOWN;
  212. break;
  213. }
  214. bROOTDevice = FALSE;
  215. }
  216. _tcscpy(deviceInfoRegKey, TEXT("Enum\\"));
  217. _tcscat(deviceInfoRegKey, regkeyName);
  218. //
  219. // Open reg key where resides all device infomation
  220. //
  221. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, deviceInfoRegKey, 0, KEY_READ, &hDevice)){
  222. controllerInfo = ActiveControllersOut + indexAvailable;
  223. //
  224. // Replace '\\' with '&' in registry key to make PNPID
  225. //
  226. pPreparePNPIDName(regkeyName);
  227. switch(deviceType){
  228. case CONTROLLER_ON_BOARD_IDE:
  229. {
  230. if(pRegQueryStringValue(hDevice,
  231. TEXT("HardwareID"),
  232. ideHardwareID,
  233. sizeof(deviceData))){
  234. scsiPortNumber = INVALID_SCSI_PORT;
  235. //
  236. // "MF\\GOODPRIMARY" and "MF\\GOODSECONDARY" are pnpid for
  237. // on board IDE Primary and Secondary Channel controllers.
  238. // And they always has constant SCSIPortNumber 0 or 1 respectively
  239. // for NT enum and marked as CONTROLLER_ON_BOARD_IDE.
  240. // Leave INVALID_SCSI_PORT(SCSIPortNumber) for extra IDE controllers
  241. // and mark them as CONTROLLER_EXTRA_IDE.
  242. //
  243. for(ideCounter = 0; ideCounter < ARRAYSIZE(g_knownIDEControllers); ideCounter++){
  244. if(!_tcsnicmp(ideHardwareID,
  245. g_knownIDEControllers[ideCounter].pnpId,
  246. _tcslen(g_knownIDEControllers[ideCounter].pnpId))){
  247. scsiPortNumber = g_knownIDEControllers[ideCounter].defaultSCSIPort;
  248. break;
  249. }
  250. }
  251. if(bROOTDevice && INVALID_SCSI_PORT == scsiPortNumber){
  252. //
  253. // Ignore this case, devices is not IDE controller.
  254. //
  255. break;
  256. }
  257. if(ActiveControllersOut){
  258. MYASSERT(controllerInfo->SCSIPortNumber == INVALID_SCSI_PORT);
  259. _tcscpy(controllerInfo->PNPID, regkeyName);
  260. controllerInfo->SCSIPortNumber = scsiPortNumber;
  261. controllerInfo->ControllerType = scsiPortNumber != INVALID_SCSI_PORT?
  262. CONTROLLER_ON_BOARD_IDE: CONTROLLER_EXTRA_IDE;
  263. }
  264. indexAvailable++;
  265. }
  266. }
  267. break;
  268. case CONTROLLER_SCSI:
  269. {
  270. //
  271. // For SCSI controllers SCSIPortNumber calaculated from
  272. // "Driver" value and have "SCSIAdapter\000x" where x
  273. // is SCSIPortNumber. For SCSI controllers SCSIPortNumber
  274. // will be postprocessed after enum.
  275. // Mark as CONTROLLER_SCSI.
  276. //
  277. if(pRegQueryStringValue(hDevice,
  278. TEXT("Driver"),
  279. deviceData,
  280. sizeof(deviceData))){
  281. pDelimeter = _tcschr(deviceData, '\\');
  282. if(pDelimeter){
  283. *pDelimeter = '\0';
  284. if(!_tcsicmp(deviceData, TEXT("SCSIAdapter"))){
  285. scsiPortNumber = _ttoi(++pDelimeter);
  286. if(ActiveControllersOut){
  287. MYASSERT(controllerInfo->SCSIPortNumber == INVALID_SCSI_PORT);
  288. _tcscpy(controllerInfo->PNPID, regkeyName);
  289. controllerInfo->SCSIPortNumber = scsiPortNumber;
  290. controllerInfo->ControllerType = CONTROLLER_SCSI;
  291. }
  292. indexAvailable++;
  293. }
  294. }
  295. }
  296. }
  297. break;
  298. default:
  299. MYASSERT(FALSE);
  300. }
  301. RegCloseKey(hDevice);hDevice = NULL;
  302. }
  303. }
  304. }while(FALSE);
  305. RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
  306. }
  307. *NumberOfActiveControllersOut = indexAvailable;
  308. if(ActiveControllersOut){
  309. //
  310. // Sort controlers in next order: First IDE, after SCSI,
  311. // inside each group(IDE and SCSI) sort by preliminary defined SCSIPortNumber
  312. //
  313. qsort(ActiveControllersOut, indexAvailable, sizeof(ActiveControllersOut[0]), pControllerInfoCompare);
  314. //
  315. // Update port number for SCSI devices.
  316. // User could add new SCSIAdapter and after remove old SCSIAdapter,
  317. // it cause that SCSIAdapterNumber will be not effective,
  318. // because for NT it will be (SCSIAdapterNumber - 1)
  319. //
  320. for(i = 0, j = 0; j < indexAvailable; j++){
  321. if(CONTROLLER_SCSI != ActiveControllersOut[j].ControllerType){
  322. continue;
  323. }
  324. //
  325. // Now SCSI controllers sorted, reassign PortNumber
  326. // by right order, in order to recognize in NT.
  327. //
  328. ActiveControllersOut[j].SCSIPortNumber = i++;
  329. }
  330. //
  331. // Calculate effective SCSIPortNumber,
  332. // 0 - IDE Primary, 1 - IDE Secondary, 2 and ... - SCSI
  333. //
  334. for(controllerStartIndex = 0, i = 0;
  335. i < ARRAYSIZE(controllerTypes);
  336. i++, controllerStartIndex += controllersSubNumber){
  337. for(controllersSubNumber = 0, j = 0; j < indexAvailable; j++){
  338. if(controllerTypes[i] != ActiveControllersOut[j].ControllerType){
  339. continue;
  340. }
  341. if(INVALID_SCSI_PORT != ActiveControllersOut[j].SCSIPortNumber){
  342. ActiveControllersOut[j].SCSIPortNumber += controllerStartIndex;
  343. }
  344. controllersSubNumber++;
  345. }
  346. }
  347. }
  348. }
  349. __finally{
  350. if(hDevice){
  351. RegCloseKey(hDevice);
  352. }
  353. if(hActiveDeviceRoot){
  354. RegCloseKey(hActiveDeviceRoot);
  355. }
  356. if(hActiveDevicesRoot){
  357. RegCloseKey(hActiveDevicesRoot);
  358. }
  359. }
  360. return TRUE;
  361. }
  362. BOOL
  363. GatherControllersInfo(
  364. IN OUT PCONTROLLERS_COLLECTION * ControllersCollectionOut
  365. )
  366. {
  367. DWORD rcResult = ERROR_ACCESS_DENIED;
  368. UINT i;
  369. PCONTROLLERS_COLLECTION activeControllersCollection = NULL;
  370. BOOL bResult = FALSE;
  371. UINT activeControllersNumber;
  372. if(!ControllersCollectionOut){
  373. SetLastError(ERROR_INVALID_PARAMETER);
  374. return FALSE;
  375. }
  376. __try{
  377. activeControllersCollection = (PCONTROLLERS_COLLECTION)MALLOC(sizeof(CONTROLLERS_COLLECTION));
  378. if(!activeControllersCollection){
  379. rcResult = ERROR_NOT_ENOUGH_MEMORY;
  380. __leave;
  381. }
  382. //
  383. // Acquiring number of controllers in system
  384. //
  385. if(!pGatherControllersInfo(NULL, &activeControllersCollection->NumberOfControllers)){
  386. rcResult = ERROR_ACCESS_DENIED;
  387. __leave;
  388. }
  389. //
  390. // Proceed only if we have positive controllers number
  391. //
  392. if(activeControllersCollection->NumberOfControllers){
  393. activeControllersCollection->ControllersInfo = (PCONTROLLER_INFO)
  394. MALLOC(activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
  395. if(!activeControllersCollection->ControllersInfo){
  396. rcResult = ERROR_NOT_ENOUGH_MEMORY;
  397. __leave;
  398. }
  399. //
  400. // Initialize array
  401. //
  402. memset(activeControllersCollection->ControllersInfo,
  403. 0,
  404. activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
  405. for(i = 0; i < activeControllersCollection->NumberOfControllers; i++){
  406. activeControllersCollection->ControllersInfo[i].SCSIPortNumber = INVALID_SCSI_PORT;
  407. }
  408. //
  409. // fill out controllers info array
  410. //
  411. activeControllersNumber = activeControllersCollection->NumberOfControllers;
  412. if(!pGatherControllersInfo(activeControllersCollection->ControllersInfo,
  413. &activeControllersNumber)){
  414. rcResult = ERROR_ACCESS_DENIED;
  415. __leave;
  416. }
  417. }
  418. else{
  419. activeControllersCollection->ControllersInfo = NULL;
  420. }
  421. *ControllersCollectionOut = activeControllersCollection;
  422. rcResult = ERROR_SUCCESS;
  423. }
  424. __finally{
  425. if(ERROR_SUCCESS != rcResult){
  426. if(activeControllersCollection){
  427. ReleaseControllersInfo(activeControllersCollection);
  428. }
  429. }
  430. }
  431. SetLastError(rcResult);
  432. return ERROR_SUCCESS == rcResult;
  433. }
  434. BOOL
  435. ReleaseControllersInfo(
  436. IN PCONTROLLERS_COLLECTION ControllersCollection
  437. )
  438. {
  439. if(!ControllersCollection){
  440. SetLastError(ERROR_INVALID_PARAMETER);
  441. return FALSE;
  442. }
  443. if(ControllersCollection){
  444. if(ControllersCollection->ControllersInfo){
  445. FREE(ControllersCollection->ControllersInfo);
  446. }
  447. FREE(ControllersCollection);
  448. }
  449. return TRUE;
  450. }
  451. BOOL
  452. IsInControllerCollection(
  453. IN PCONTROLLERS_COLLECTION ControllersCollection,
  454. IN PCTSTR PnPIdString,
  455. OUT PUINT Index
  456. )
  457. {
  458. UINT i;
  459. if(!ControllersCollection || !PnPIdString || !Index){
  460. return FALSE;
  461. }
  462. for(i = 0; i < ControllersCollection->NumberOfControllers; i++){
  463. if(!_tcsnicmp(PnPIdString,
  464. ControllersCollection->ControllersInfo[i].PNPID,
  465. _tcslen(ControllersCollection->ControllersInfo[i].PNPID))){
  466. *Index = i;
  467. return TRUE;
  468. }
  469. }
  470. return FALSE;
  471. }
  472. BOOL
  473. GetSCSIAddressFromPnPId(
  474. IN PCONTROLLERS_COLLECTION ControllersCollection,
  475. IN HKEY hDeviceRegKey,
  476. IN PCTSTR PnPIdString,
  477. OUT DRIVE_SCSI_ADDRESS * ScsiAddressOut
  478. )
  479. {
  480. UINT i;
  481. PCTSTR pBufferKeyValue;
  482. BOOL bResult;
  483. if(!ControllersCollection || !hDeviceRegKey || !PnPIdString || !ScsiAddressOut){
  484. SetLastError(ERROR_INVALID_PARAMETER);
  485. return FALSE;
  486. }
  487. bResult = FALSE;
  488. do{
  489. //
  490. // Check for presence in controllers list controller PNPID of device
  491. // After complete SCSI_ADDRESS structure with
  492. // DriveLetter, DriveType, TargetID, Lun.
  493. //
  494. if(IsInControllerCollection(ControllersCollection, PnPIdString, &i)){
  495. memset(ScsiAddressOut, 0, sizeof(*ScsiAddressOut));
  496. ScsiAddressOut->PortNumber = (UCHAR)ControllersCollection->ControllersInfo[i].SCSIPortNumber;
  497. bResult = pGetDeviceType(hDeviceRegKey, &ScsiAddressOut->DriveType);
  498. MYASSERT(bResult);
  499. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey,
  500. DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT,
  501. NULL,
  502. 0);
  503. if(!pBufferKeyValue){
  504. break;
  505. }
  506. ScsiAddressOut->DriveLetter = pBufferKeyValue[0];
  507. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiTargetId"), NULL, 0);
  508. if(!pBufferKeyValue){
  509. break;
  510. }
  511. ScsiAddressOut->TargetId = (UCHAR)_ttoi(pBufferKeyValue);
  512. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiLun"), NULL, 0);
  513. if(pBufferKeyValue){
  514. //
  515. //For most cases ScsiLun is zero, so it is not fatal.
  516. //
  517. ScsiAddressOut->Lun = (UCHAR)_ttoi(pBufferKeyValue);
  518. }
  519. bResult = TRUE;
  520. }
  521. }while(FALSE);
  522. return bResult;
  523. }
  524. BOOL
  525. DeviceEnum(
  526. IN PCONTROLLERS_COLLECTION ControllersCollection,
  527. IN PCTSTR DeviceCategory,
  528. IN PDEVICE_ENUM_CALLBACK_FUNCTION DeviceEnumCallbackFunction,
  529. IN PVOID CallbackData
  530. )
  531. {
  532. TCHAR deviceType[MAX_REG_SIZE];
  533. TCHAR regkeyName[MAX_PNPID_SIZE];
  534. TCHAR deviceInfoRegKey[MAX_REG_SIZE];
  535. HKEY hActiveDevicesRoot = NULL;
  536. HKEY hActiveDeviceRoot = NULL;
  537. HKEY hDevice = NULL;
  538. UINT itemIndexRoot;
  539. DWORD bufferLength;
  540. UINT controllerIndex;
  541. PTSTR pDevicePNPIDName;
  542. UINT deviceTypeLen;
  543. DWORD rcResult;
  544. if(!ControllersCollection || !DeviceCategory || !DeviceEnumCallbackFunction){
  545. SetLastError(ERROR_INVALID_PARAMETER);
  546. return FALSE;
  547. }
  548. __try{
  549. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
  550. return FALSE;
  551. }
  552. _tcscpy(deviceType, DeviceCategory);
  553. _tcscat(deviceType, TEXT("\\"));
  554. deviceTypeLen = _tcslen(deviceType);
  555. //
  556. // Looking for devices that attached to controllers in our list
  557. //
  558. for(itemIndexRoot = 0; ;itemIndexRoot++){
  559. bufferLength = ARRAYSIZE(regkeyName);
  560. rcResult = RegEnumKeyEx(hActiveDevicesRoot,
  561. itemIndexRoot,
  562. regkeyName,
  563. &bufferLength,
  564. 0,
  565. NULL,
  566. NULL,
  567. NULL);
  568. if(ERROR_SUCCESS != rcResult){
  569. break;
  570. }
  571. if(ERROR_SUCCESS != RegOpenKeyEx(hActiveDevicesRoot, regkeyName, 0, KEY_READ, &hActiveDeviceRoot)){
  572. continue;
  573. }
  574. //
  575. // "HardWareKey" consist key path to real device
  576. //
  577. if(pRegQueryStringValue(hActiveDeviceRoot,
  578. TEXT("HardWareKey"),
  579. regkeyName,
  580. sizeof(regkeyName))){
  581. if(!_tcsnicmp(regkeyName, deviceType, deviceTypeLen)){
  582. _tcscpy(deviceInfoRegKey, TEXT("Enum\\"));
  583. _tcscat(deviceInfoRegKey, regkeyName);
  584. //
  585. // Make a Controller PNPID from device PNPID
  586. //
  587. pDevicePNPIDName = _tcsrchr(regkeyName, '\\');
  588. MYASSERT(pDevicePNPIDName);
  589. pDevicePNPIDName++;
  590. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, deviceInfoRegKey, 0, KEY_READ, &hDevice)){
  591. //
  592. // Check for presence Controller PNPID in controllers list and
  593. // for device availability.
  594. //
  595. if(IsInControllerCollection(ControllersCollection, pDevicePNPIDName, &controllerIndex) &&
  596. pDoesDriveExist(hDevice, NULL)){
  597. //
  598. // Call callback for every active device we found,
  599. // which controller in our list
  600. // Stop enum, if user does not want to.
  601. //
  602. if(!DeviceEnumCallbackFunction(hDevice, ControllersCollection, controllerIndex, CallbackData)){
  603. //
  604. // Stop enum, if user does not want to.
  605. //
  606. __leave;
  607. }
  608. }
  609. RegCloseKey(hDevice);hDevice = NULL;
  610. }
  611. }
  612. }
  613. RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
  614. }
  615. }
  616. __finally{
  617. if(hDevice){
  618. RegCloseKey(hDevice);
  619. }
  620. if(hActiveDeviceRoot){
  621. RegCloseKey(hActiveDeviceRoot);
  622. }
  623. if(hActiveDevicesRoot){
  624. RegCloseKey(hActiveDevicesRoot);
  625. }
  626. }
  627. return TRUE;
  628. }