Leaked source code of windows server 2003
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.

738 lines
26 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. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
  166. return FALSE;
  167. }
  168. __try{
  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. if(_tcslen(regkeyName) >= ARRAYSIZE(controllerInfo->PNPID)){
  260. //
  261. // Prevent buffer overrun
  262. //
  263. MYASSERT(FALSE);
  264. break;
  265. }
  266. _tcscpy(controllerInfo->PNPID, regkeyName);
  267. controllerInfo->SCSIPortNumber = scsiPortNumber;
  268. controllerInfo->ControllerType = scsiPortNumber != INVALID_SCSI_PORT?
  269. CONTROLLER_ON_BOARD_IDE: CONTROLLER_EXTRA_IDE;
  270. }
  271. indexAvailable++;
  272. }
  273. }
  274. break;
  275. case CONTROLLER_SCSI:
  276. {
  277. //
  278. // For SCSI controllers SCSIPortNumber calaculated from
  279. // "Driver" value and have "SCSIAdapter\000x" where x
  280. // is SCSIPortNumber. For SCSI controllers SCSIPortNumber
  281. // will be postprocessed after enum.
  282. // Mark as CONTROLLER_SCSI.
  283. //
  284. if(pRegQueryStringValue(hDevice,
  285. TEXT("Driver"),
  286. deviceData,
  287. sizeof(deviceData))){
  288. pDelimeter = _tcschr(deviceData, '\\');
  289. if(pDelimeter){
  290. *pDelimeter = '\0';
  291. if(!_tcsicmp(deviceData, TEXT("SCSIAdapter"))){
  292. scsiPortNumber = _ttoi(++pDelimeter);
  293. if(ActiveControllersOut){
  294. MYASSERT(controllerInfo->SCSIPortNumber == INVALID_SCSI_PORT);
  295. if(_tcslen(regkeyName) >= ARRAYSIZE(controllerInfo->PNPID)){
  296. //
  297. // Prevent buffer overrun
  298. //
  299. MYASSERT(FALSE);
  300. break;
  301. }
  302. _tcscpy(controllerInfo->PNPID, regkeyName);
  303. controllerInfo->SCSIPortNumber = scsiPortNumber;
  304. controllerInfo->ControllerType = CONTROLLER_SCSI;
  305. }
  306. indexAvailable++;
  307. }
  308. }
  309. }
  310. }
  311. break;
  312. default:
  313. MYASSERT(FALSE);
  314. }
  315. RegCloseKey(hDevice);hDevice = NULL;
  316. }
  317. }
  318. }while(FALSE);
  319. RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
  320. }
  321. *NumberOfActiveControllersOut = indexAvailable;
  322. if(ActiveControllersOut){
  323. //
  324. // Sort controlers in next order: First IDE, after SCSI,
  325. // inside each group(IDE and SCSI) sort by preliminary defined SCSIPortNumber
  326. //
  327. qsort(ActiveControllersOut, indexAvailable, sizeof(ActiveControllersOut[0]), pControllerInfoCompare);
  328. //
  329. // Update port number for SCSI devices.
  330. // User could add new SCSIAdapter and after remove old SCSIAdapter,
  331. // it cause that SCSIAdapterNumber will be not effective,
  332. // because for NT it will be (SCSIAdapterNumber - 1)
  333. //
  334. for(i = 0, j = 0; j < indexAvailable; j++){
  335. if(CONTROLLER_SCSI != ActiveControllersOut[j].ControllerType){
  336. continue;
  337. }
  338. //
  339. // Now SCSI controllers sorted, reassign PortNumber
  340. // by right order, in order to recognize in NT.
  341. //
  342. ActiveControllersOut[j].SCSIPortNumber = i++;
  343. }
  344. //
  345. // Calculate effective SCSIPortNumber,
  346. // 0 - IDE Primary, 1 - IDE Secondary, 2 and ... - SCSI
  347. //
  348. for(controllerStartIndex = 0, i = 0;
  349. i < ARRAYSIZE(controllerTypes);
  350. i++, controllerStartIndex += controllersSubNumber){
  351. for(controllersSubNumber = 0, j = 0; j < indexAvailable; j++){
  352. if(controllerTypes[i] != ActiveControllersOut[j].ControllerType){
  353. continue;
  354. }
  355. if(INVALID_SCSI_PORT != ActiveControllersOut[j].SCSIPortNumber){
  356. ActiveControllersOut[j].SCSIPortNumber += controllerStartIndex;
  357. }
  358. controllersSubNumber++;
  359. }
  360. }
  361. }
  362. }
  363. __finally{
  364. if(hDevice){
  365. RegCloseKey(hDevice);
  366. }
  367. if(hActiveDeviceRoot){
  368. RegCloseKey(hActiveDeviceRoot);
  369. }
  370. if(hActiveDevicesRoot){
  371. RegCloseKey(hActiveDevicesRoot);
  372. }
  373. }
  374. return TRUE;
  375. }
  376. BOOL
  377. GatherControllersInfo(
  378. IN OUT PCONTROLLERS_COLLECTION * ControllersCollectionOut
  379. )
  380. {
  381. DWORD rcResult = ERROR_ACCESS_DENIED;
  382. UINT i;
  383. PCONTROLLERS_COLLECTION activeControllersCollection = NULL;
  384. BOOL bResult = FALSE;
  385. UINT activeControllersNumber;
  386. if(!ControllersCollectionOut){
  387. SetLastError(ERROR_INVALID_PARAMETER);
  388. return FALSE;
  389. }
  390. __try{
  391. activeControllersCollection = (PCONTROLLERS_COLLECTION)MALLOC(sizeof(CONTROLLERS_COLLECTION));
  392. if(!activeControllersCollection){
  393. rcResult = ERROR_NOT_ENOUGH_MEMORY;
  394. __leave;
  395. }
  396. //
  397. // Acquiring number of controllers in system
  398. //
  399. if(!pGatherControllersInfo(NULL, &activeControllersCollection->NumberOfControllers)){
  400. rcResult = ERROR_ACCESS_DENIED;
  401. __leave;
  402. }
  403. //
  404. // Proceed only if we have positive controllers number
  405. //
  406. if(activeControllersCollection->NumberOfControllers){
  407. activeControllersCollection->ControllersInfo = (PCONTROLLER_INFO)
  408. MALLOC(activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
  409. if(!activeControllersCollection->ControllersInfo){
  410. rcResult = ERROR_NOT_ENOUGH_MEMORY;
  411. __leave;
  412. }
  413. //
  414. // Initialize array
  415. //
  416. memset(activeControllersCollection->ControllersInfo,
  417. 0,
  418. activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
  419. for(i = 0; i < activeControllersCollection->NumberOfControllers; i++){
  420. activeControllersCollection->ControllersInfo[i].SCSIPortNumber = INVALID_SCSI_PORT;
  421. }
  422. //
  423. // fill out controllers info array
  424. //
  425. activeControllersNumber = activeControllersCollection->NumberOfControllers;
  426. if(!pGatherControllersInfo(activeControllersCollection->ControllersInfo,
  427. &activeControllersNumber)){
  428. rcResult = ERROR_ACCESS_DENIED;
  429. __leave;
  430. }
  431. }
  432. else{
  433. activeControllersCollection->ControllersInfo = NULL;
  434. }
  435. *ControllersCollectionOut = activeControllersCollection;
  436. rcResult = ERROR_SUCCESS;
  437. }
  438. __finally{
  439. if(ERROR_SUCCESS != rcResult){
  440. if(activeControllersCollection){
  441. ReleaseControllersInfo(activeControllersCollection);
  442. }
  443. }
  444. }
  445. SetLastError(rcResult);
  446. return ERROR_SUCCESS == rcResult;
  447. }
  448. BOOL
  449. ReleaseControllersInfo(
  450. IN PCONTROLLERS_COLLECTION ControllersCollection
  451. )
  452. {
  453. if(!ControllersCollection){
  454. SetLastError(ERROR_INVALID_PARAMETER);
  455. return FALSE;
  456. }
  457. if(ControllersCollection){
  458. if(ControllersCollection->ControllersInfo){
  459. FREE(ControllersCollection->ControllersInfo);
  460. }
  461. FREE(ControllersCollection);
  462. }
  463. return TRUE;
  464. }
  465. BOOL
  466. IsInControllerCollection(
  467. IN PCONTROLLERS_COLLECTION ControllersCollection,
  468. IN PCTSTR PnPIdString,
  469. OUT PUINT Index
  470. )
  471. {
  472. UINT i;
  473. if(!ControllersCollection || !PnPIdString || !Index){
  474. return FALSE;
  475. }
  476. for(i = 0; i < ControllersCollection->NumberOfControllers; i++){
  477. if(!_tcsnicmp(PnPIdString,
  478. ControllersCollection->ControllersInfo[i].PNPID,
  479. _tcslen(ControllersCollection->ControllersInfo[i].PNPID))){
  480. *Index = i;
  481. return TRUE;
  482. }
  483. }
  484. return FALSE;
  485. }
  486. BOOL
  487. GetSCSIAddressFromPnPId(
  488. IN PCONTROLLERS_COLLECTION ControllersCollection,
  489. IN HKEY hDeviceRegKey,
  490. IN PCTSTR PnPIdString,
  491. OUT DRIVE_SCSI_ADDRESS * ScsiAddressOut
  492. )
  493. {
  494. UINT i;
  495. PCTSTR pBufferKeyValue;
  496. BOOL bResult;
  497. if(!ControllersCollection || !hDeviceRegKey || !PnPIdString || !ScsiAddressOut){
  498. SetLastError(ERROR_INVALID_PARAMETER);
  499. return FALSE;
  500. }
  501. bResult = FALSE;
  502. do{
  503. //
  504. // Check for presence in controllers list controller PNPID of device
  505. // After complete SCSI_ADDRESS structure with
  506. // DriveLetter, DriveType, TargetID, Lun.
  507. //
  508. if(IsInControllerCollection(ControllersCollection, PnPIdString, &i)){
  509. memset(ScsiAddressOut, 0, sizeof(*ScsiAddressOut));
  510. ScsiAddressOut->PortNumber = (UCHAR)ControllersCollection->ControllersInfo[i].SCSIPortNumber;
  511. bResult = pGetDeviceType(hDeviceRegKey, &ScsiAddressOut->DriveType);
  512. MYASSERT(bResult);
  513. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey,
  514. DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT,
  515. NULL,
  516. 0);
  517. if(!pBufferKeyValue){
  518. break;
  519. }
  520. ScsiAddressOut->DriveLetter = pBufferKeyValue[0];
  521. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiTargetId"), NULL, 0);
  522. if(!pBufferKeyValue){
  523. break;
  524. }
  525. ScsiAddressOut->TargetId = (UCHAR)_ttoi(pBufferKeyValue);
  526. pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiLun"), NULL, 0);
  527. if(pBufferKeyValue){
  528. //
  529. //For most cases ScsiLun is zero, so it is not fatal.
  530. //
  531. ScsiAddressOut->Lun = (UCHAR)_ttoi(pBufferKeyValue);
  532. }
  533. bResult = TRUE;
  534. }
  535. }while(FALSE);
  536. return bResult;
  537. }
  538. BOOL
  539. DeviceEnum(
  540. IN PCONTROLLERS_COLLECTION ControllersCollection,
  541. IN PCTSTR DeviceCategory,
  542. IN PDEVICE_ENUM_CALLBACK_FUNCTION DeviceEnumCallbackFunction,
  543. IN PVOID CallbackData
  544. )
  545. {
  546. TCHAR deviceType[MAX_REG_SIZE];
  547. TCHAR regkeyName[MAX_PNPID_SIZE];
  548. TCHAR deviceInfoRegKey[MAX_REG_SIZE];
  549. HKEY hActiveDevicesRoot = NULL;
  550. HKEY hActiveDeviceRoot = NULL;
  551. HKEY hDevice = NULL;
  552. UINT itemIndexRoot;
  553. DWORD bufferLength;
  554. UINT controllerIndex;
  555. PTSTR pDevicePNPIDName;
  556. UINT deviceTypeLen;
  557. DWORD rcResult;
  558. if(!ControllersCollection || !DeviceCategory || !DeviceEnumCallbackFunction){
  559. SetLastError(ERROR_INVALID_PARAMETER);
  560. return FALSE;
  561. }
  562. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
  563. return FALSE;
  564. }
  565. __try{
  566. _tcscpy(deviceType, DeviceCategory);
  567. _tcscat(deviceType, TEXT("\\"));
  568. deviceTypeLen = _tcslen(deviceType);
  569. //
  570. // Looking for devices that attached to controllers in our list
  571. //
  572. for(itemIndexRoot = 0; ;itemIndexRoot++){
  573. bufferLength = ARRAYSIZE(regkeyName);
  574. rcResult = RegEnumKeyEx(hActiveDevicesRoot,
  575. itemIndexRoot,
  576. regkeyName,
  577. &bufferLength,
  578. 0,
  579. NULL,
  580. NULL,
  581. NULL);
  582. if(ERROR_SUCCESS != rcResult){
  583. break;
  584. }
  585. if(ERROR_SUCCESS != RegOpenKeyEx(hActiveDevicesRoot, regkeyName, 0, KEY_READ, &hActiveDeviceRoot)){
  586. continue;
  587. }
  588. //
  589. // "HardWareKey" consist key path to real device
  590. //
  591. if(pRegQueryStringValue(hActiveDeviceRoot,
  592. TEXT("HardWareKey"),
  593. regkeyName,
  594. sizeof(regkeyName))){
  595. if(!_tcsnicmp(regkeyName, deviceType, deviceTypeLen)){
  596. _tcscpy(deviceInfoRegKey, TEXT("Enum\\"));
  597. _tcscat(deviceInfoRegKey, regkeyName);
  598. //
  599. // Make a Controller PNPID from device PNPID
  600. //
  601. pDevicePNPIDName = _tcsrchr(regkeyName, '\\');
  602. MYASSERT(pDevicePNPIDName);
  603. pDevicePNPIDName++;
  604. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, deviceInfoRegKey, 0, KEY_READ, &hDevice)){
  605. //
  606. // Check for presence Controller PNPID in controllers list and
  607. // for device availability.
  608. //
  609. if(IsInControllerCollection(ControllersCollection, pDevicePNPIDName, &controllerIndex) &&
  610. pDoesDriveExist(hDevice, NULL)){
  611. //
  612. // Call callback for every active device we found,
  613. // which controller in our list
  614. // Stop enum, if user does not want to.
  615. //
  616. if(!DeviceEnumCallbackFunction(hDevice, ControllersCollection, controllerIndex, CallbackData)){
  617. //
  618. // Stop enum, if user does not want to.
  619. //
  620. __leave;
  621. }
  622. }
  623. RegCloseKey(hDevice);hDevice = NULL;
  624. }
  625. }
  626. }
  627. RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
  628. }
  629. }
  630. __finally{
  631. if(hDevice){
  632. RegCloseKey(hDevice);
  633. }
  634. if(hActiveDeviceRoot){
  635. RegCloseKey(hActiveDeviceRoot);
  636. }
  637. if(hActiveDevicesRoot){
  638. RegCloseKey(hActiveDevicesRoot);
  639. }
  640. }
  641. return TRUE;
  642. }