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.

1119 lines
25 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. /*++
  4. Copyright (c) 1990 Microsoft Corporation
  5. Module Name:
  6. hardware.c
  7. Abstract:
  8. Registry hardware detection
  9. Author:
  10. Sunil Pai (sunilp) April 1992
  11. --*/
  12. #define IDENTIFIER "Identifier"
  13. PCHAR AdaptersTable[] = {
  14. "EisaAdapter",
  15. "MultifunctionAdapter"
  16. };
  17. //=====================================================================
  18. // The following funtions detect information from the registry hardware
  19. // node
  20. //=====================================================================
  21. BOOL
  22. SearchControllerForPeripheral(
  23. IN LPSTR Controller,
  24. IN LPSTR Peripheral,
  25. OUT LPSTR PeripheralPath
  26. )
  27. {
  28. HKEY hKey, hSubKey;
  29. CHAR KeyName[ MAX_PATH ];
  30. CHAR SubKeyName[ MAX_PATH ];
  31. CHAR Class[ MAX_PATH ];
  32. DWORD cbSubKeyName;
  33. DWORD cbClass;
  34. FILETIME FileTime;
  35. UINT Index;
  36. LONG Status;
  37. //
  38. // Open the controller key
  39. //
  40. lstrcpy( KeyName, "Hardware\\Description\\System\\MultifunctionAdapter\\0\\");
  41. lstrcat( KeyName, Controller );
  42. Status = RegOpenKeyEx (
  43. HKEY_LOCAL_MACHINE,
  44. KeyName,
  45. 0,
  46. KEY_READ,
  47. &hKey
  48. );
  49. //
  50. // If failed to open it then check for an eisa adapter node
  51. //
  52. if (Status != ERROR_SUCCESS) {
  53. lstrcpy( KeyName, "Hardware\\Description\\System\\EisaAdapter\\0\\");
  54. lstrcat( KeyName, Controller );
  55. Status = RegOpenKeyEx (
  56. HKEY_LOCAL_MACHINE,
  57. KeyName,
  58. 0,
  59. KEY_READ,
  60. &hKey
  61. );
  62. }
  63. //
  64. // If the controller wasn't found at all then return FALSE
  65. if ( Status != ERROR_SUCCESS ) {
  66. return FALSE;
  67. }
  68. //
  69. // Enumerate the subkeys for the controller and search the subkeys
  70. // for the peripheral indicated
  71. //
  72. for ( Index = 0 ; ; Index++ ) {
  73. cbSubKeyName = MAX_PATH;
  74. cbClass = MAX_PATH;
  75. Status = RegEnumKeyEx(
  76. hKey,
  77. Index,
  78. SubKeyName,
  79. &cbSubKeyName,
  80. NULL,
  81. Class,
  82. &cbClass,
  83. &FileTime
  84. );
  85. if ( Status != ERROR_SUCCESS ) {
  86. break;
  87. }
  88. //
  89. // Combine the subkey name with the peripheral name and see if it
  90. // exists
  91. //
  92. lstrcat (SubKeyName, "\\");
  93. lstrcat (SubKeyName, Peripheral);
  94. lstrcat (SubKeyName, "\\0");
  95. Status = RegOpenKeyEx (
  96. hKey,
  97. SubKeyName,
  98. 0,
  99. KEY_READ,
  100. &hSubKey
  101. );
  102. if (Status == ERROR_SUCCESS) {
  103. RegCloseKey( hSubKey );
  104. RegCloseKey( hKey );
  105. //
  106. // path already has the controller\key entry
  107. lstrcpy (PeripheralPath, Controller);
  108. lstrcat (PeripheralPath, "\\" );
  109. lstrcat (PeripheralPath, SubKeyName);
  110. return( TRUE );
  111. }
  112. }
  113. RegCloseKey( hKey );
  114. return( FALSE );
  115. }
  116. BOOL
  117. GetTypeOfHardware(
  118. LPSTR HardwareAdapterEntry,
  119. LPSTR HardwareType
  120. )
  121. {
  122. BOOL bReturn = FALSE;
  123. PVOID ConfigurationData = NULL;
  124. LPSTR Type = NULL;
  125. CHAR SubKey[MAX_PATH];
  126. LONG Status;
  127. HKEY hKey;
  128. //
  129. // Open the controller key for a multifunction adapter
  130. //
  131. lstrcpy( SubKey, "Hardware\\Description\\System\\MultifunctionAdapter\\0\\");
  132. lstrcat( SubKey, HardwareAdapterEntry );
  133. Status = RegOpenKeyEx (
  134. HKEY_LOCAL_MACHINE,
  135. SubKey,
  136. 0,
  137. KEY_READ,
  138. &hKey
  139. );
  140. //
  141. // If failed to open it then check for an eisa adapter node
  142. //
  143. if (Status != ERROR_SUCCESS) {
  144. lstrcpy( SubKey, "Hardware\\Description\\System\\EisaAdapter\\0\\");
  145. lstrcat( SubKey, HardwareAdapterEntry );
  146. Status = RegOpenKeyEx (
  147. HKEY_LOCAL_MACHINE,
  148. SubKey,
  149. 0,
  150. KEY_READ,
  151. &hKey
  152. );
  153. }
  154. if ( Status == ERROR_SUCCESS ) {
  155. Type = GetValueEntry( hKey, "Identifier" );
  156. if(Type != NULL) {
  157. //
  158. // Parse the type field to return type
  159. //
  160. lstrcpy ( HardwareType, Type );
  161. SFree( Type );
  162. bReturn = TRUE;
  163. }
  164. RegCloseKey( hKey );
  165. }
  166. return (bReturn);
  167. }
  168. /*
  169. Computer type as a string
  170. */
  171. CB
  172. GetMyComputerType(
  173. IN RGSZ Args,
  174. IN USHORT cArgs,
  175. OUT SZ ReturnBuffer,
  176. IN CB cbReturnBuffer
  177. )
  178. {
  179. CB Length;
  180. HKEY hKey;
  181. LPSTR Type = NULL;
  182. LONG Status;
  183. Unused(Args);
  184. Unused(cArgs);
  185. Unused(cbReturnBuffer);
  186. #if i386
  187. #define TEMP_COMPUTER "AT/AT COMPATIBLE"
  188. #else
  189. #define TEMP_COMPUTER "JAZZ"
  190. #endif
  191. lstrcpy(ReturnBuffer,TEMP_COMPUTER);
  192. Length = lstrlen(TEMP_COMPUTER) + 1;
  193. //
  194. // Open hardware node
  195. //
  196. Status = RegOpenKeyEx (
  197. HKEY_LOCAL_MACHINE,
  198. "Hardware\\Description\\System",
  199. 0,
  200. KEY_READ,
  201. &hKey
  202. );
  203. if ( Status == ERROR_SUCCESS ) {
  204. Type = GetValueEntry( hKey, "Identifier" );
  205. if(Type != NULL) {
  206. //
  207. // Parse the type field to return computer type
  208. //
  209. lstrcpy ( ReturnBuffer, Type );
  210. Length = lstrlen( Type ) + 1;
  211. SFree( Type );
  212. }
  213. RegCloseKey( hKey );
  214. }
  215. return( Length );
  216. }
  217. /*
  218. Video type as a string
  219. */
  220. CB
  221. GetMyVideoType(
  222. IN RGSZ Args,
  223. IN USHORT cArgs,
  224. OUT SZ ReturnBuffer,
  225. IN CB cbReturnBuffer
  226. )
  227. {
  228. CHAR HardwareType[80];
  229. INT Length;
  230. Unused(Args);
  231. Unused(cArgs);
  232. Unused(cbReturnBuffer);
  233. #define TEMP_VIDEO "VGA"
  234. if ( GetTypeOfHardware(
  235. "DisplayController\\0",
  236. (LPSTR)HardwareType
  237. )
  238. ) {
  239. //
  240. // Parse the type field to return Video type
  241. //
  242. lstrcpy ( ReturnBuffer, HardwareType );
  243. Length = lstrlen ( HardwareType ) + 1;
  244. }
  245. else {
  246. //
  247. // In case we cannot detect
  248. //
  249. lstrcpy(ReturnBuffer,TEMP_VIDEO);
  250. Length = lstrlen(TEMP_VIDEO)+1;
  251. }
  252. return (Length);
  253. }
  254. /*
  255. Bus type as a string
  256. */
  257. CB
  258. GetMyBusType(
  259. IN RGSZ Args,
  260. IN USHORT cArgs,
  261. OUT SZ ReturnBuffer,
  262. IN CB cbReturnBuffer
  263. )
  264. {
  265. CHAR HardwareType[80];
  266. INT Length;
  267. Unused(Args);
  268. Unused(cArgs);
  269. Unused(cbReturnBuffer);
  270. #define TEMP_BUS "ISA"
  271. if ( GetTypeOfHardware(
  272. "",
  273. (LPSTR)HardwareType
  274. )
  275. ) {
  276. //
  277. // Parse the type field to return Video type
  278. //
  279. lstrcpy ( ReturnBuffer, HardwareType );
  280. Length = lstrlen ( HardwareType ) + 1;
  281. }
  282. else {
  283. //
  284. // In case we cannot detect
  285. //
  286. lstrcpy(ReturnBuffer,TEMP_BUS);
  287. Length = lstrlen(TEMP_BUS)+1;
  288. }
  289. return (Length);
  290. }
  291. /*
  292. Pointer type as a string
  293. */
  294. CB
  295. GetMyPointerType(
  296. IN RGSZ Args,
  297. IN USHORT cArgs,
  298. OUT SZ ReturnBuffer,
  299. IN CB cbReturnBuffer
  300. )
  301. {
  302. CHAR HardwareType[80];
  303. CHAR PeripheralPath[MAX_PATH];
  304. CHAR *Controller[] = {"PointerController", "KeyboardController", "SerialController", NULL};
  305. BOOL PointerNotFound = TRUE;
  306. INT Length, i;
  307. Unused(Args);
  308. Unused(cArgs);
  309. Unused(cbReturnBuffer);
  310. #define TEMP_POINTER "NONE"
  311. for (i = 0; Controller[i] != NULL && PointerNotFound; i++ ) {
  312. if ( SearchControllerForPeripheral(
  313. Controller[i],
  314. "PointerPeripheral",
  315. PeripheralPath
  316. )
  317. ) {
  318. PointerNotFound = FALSE;
  319. }
  320. }
  321. if ( (PointerNotFound) ||
  322. (!GetTypeOfHardware(
  323. PeripheralPath,
  324. (LPSTR)HardwareType
  325. ))
  326. ) {
  327. //
  328. // In case we cannot detect
  329. //
  330. lstrcpy(ReturnBuffer,TEMP_POINTER);
  331. Length = lstrlen( TEMP_POINTER )+1;
  332. }
  333. else {
  334. //
  335. // Parse the type field to return display type
  336. //
  337. lstrcpy ( ReturnBuffer, HardwareType );
  338. Length = lstrlen ( HardwareType ) + 1;
  339. }
  340. return (Length);
  341. }
  342. /*
  343. Keyboard type as a string
  344. */
  345. CB
  346. GetMyKeyboardType(
  347. IN RGSZ Args,
  348. IN USHORT cArgs,
  349. OUT SZ ReturnBuffer,
  350. IN CB cbReturnBuffer
  351. )
  352. {
  353. CHAR HardwareType[80];
  354. INT Length;
  355. Unused(Args);
  356. Unused(cArgs);
  357. Unused(cbReturnBuffer);
  358. #define TEMP_KEYBOARD "PCAT_ENHANCED"
  359. if ( GetTypeOfHardware(
  360. "KeyboardController\\0\\KeyboardPeripheral\\0",
  361. (LPSTR)HardwareType
  362. )
  363. ) {
  364. //
  365. // Parse the type field to return keyboard type
  366. //
  367. lstrcpy ( ReturnBuffer, HardwareType );
  368. Length = lstrlen ( HardwareType ) + 1;
  369. }
  370. else {
  371. //
  372. // In case we cannot detect
  373. //
  374. lstrcpy( ReturnBuffer, TEMP_KEYBOARD );
  375. Length = lstrlen( TEMP_KEYBOARD )+1;
  376. }
  377. return (Length);
  378. }
  379. BOOL
  380. GetSetupEntryForHardware(
  381. IN LPSTR Hardware,
  382. OUT LPSTR SelectedHardwareOption
  383. )
  384. {
  385. HKEY hKey;
  386. LONG Status;
  387. LPSTR ValueData;
  388. //
  389. // Open the setup key in the current control set
  390. //
  391. Status = RegOpenKeyEx(
  392. HKEY_LOCAL_MACHINE,
  393. "SYSTEM\\CurrentControlSet\\control\\setup",
  394. 0,
  395. KEY_READ,
  396. &hKey
  397. );
  398. if( Status != ERROR_SUCCESS ) {
  399. return( FALSE );
  400. }
  401. //
  402. // Get the value data of interest
  403. //
  404. if ( ValueData = GetValueEntry( hKey, Hardware ) ) {
  405. lstrcpy( SelectedHardwareOption, ValueData );
  406. SFree( ValueData );
  407. RegCloseKey( hKey );
  408. return( TRUE );
  409. }
  410. else {
  411. RegCloseKey( hKey );
  412. return( FALSE );
  413. }
  414. }
  415. CB
  416. GetSelectedVideo(
  417. IN RGSZ Args,
  418. IN USHORT cArgs,
  419. OUT SZ ReturnBuffer,
  420. IN CB cbReturnBuffer
  421. )
  422. {
  423. Unused(Args);
  424. Unused(cArgs);
  425. Unused(cbReturnBuffer);
  426. #define SELECTED_VIDEO ""
  427. if( GetSetupEntryForHardware( "Video", ReturnBuffer ) ) {
  428. return( lstrlen( ReturnBuffer ) + 1 );
  429. }
  430. else {
  431. lstrcpy( ReturnBuffer, SELECTED_VIDEO );
  432. return( lstrlen( SELECTED_VIDEO ) + 1 );
  433. }
  434. }
  435. CB
  436. GetSelectedPointer(
  437. IN RGSZ Args,
  438. IN USHORT cArgs,
  439. OUT SZ ReturnBuffer,
  440. IN CB cbReturnBuffer
  441. )
  442. {
  443. Unused(Args);
  444. Unused(cArgs);
  445. Unused(cbReturnBuffer);
  446. #define SELECTED_POINTER ""
  447. if( GetSetupEntryForHardware( "Pointer", ReturnBuffer ) ) {
  448. return( lstrlen( ReturnBuffer ) + 1 );
  449. }
  450. else {
  451. lstrcpy( ReturnBuffer, SELECTED_POINTER );
  452. return( lstrlen( SELECTED_POINTER ) + 1 );
  453. }
  454. }
  455. CB
  456. GetSelectedKeyboard(
  457. IN RGSZ Args,
  458. IN USHORT cArgs,
  459. OUT SZ ReturnBuffer,
  460. IN CB cbReturnBuffer
  461. )
  462. {
  463. Unused(Args);
  464. Unused(cArgs);
  465. Unused(cbReturnBuffer);
  466. #define SELECTED_KEYBOARD ""
  467. if( GetSetupEntryForHardware( "Keyboard", ReturnBuffer ) ) {
  468. return( lstrlen( ReturnBuffer ) + 1 );
  469. }
  470. else {
  471. lstrcpy( ReturnBuffer, SELECTED_KEYBOARD );
  472. return( lstrlen( SELECTED_KEYBOARD ) + 1 );
  473. }
  474. }
  475. CB
  476. GetDevicemapValue(
  477. IN RGSZ Args,
  478. IN USHORT cArgs,
  479. OUT SZ ReturnBuffer,
  480. IN CB cbReturnBuffer
  481. )
  482. {
  483. CB rc = 0;
  484. CHAR DeviceEntry[ MAX_PATH ];
  485. HKEY hKey;
  486. LONG Status;
  487. LPSTR ServicesEntry;
  488. Unused( cbReturnBuffer );
  489. #define DEFAULT_ENTRY ""
  490. if (cArgs != 2) {
  491. return( rc );
  492. }
  493. lstrcpy (ReturnBuffer, DEFAULT_ENTRY);
  494. rc = lstrlen( DEFAULT_ENTRY ) + 1;
  495. //
  496. // HACK FOR VIDEO
  497. // To make inf files from release 1.0 work properly, always return VGA
  498. // so that the old driver is not disabled by the inf file.
  499. //
  500. if (!lstrcmp( Args[ 0 ], "Video" )) {
  501. return rc;
  502. }
  503. //
  504. // Open the devicemap key for the hardware indicated
  505. //
  506. lstrcpy( DeviceEntry, "hardware\\devicemap\\" );
  507. lstrcat( DeviceEntry, Args[ 0 ] );
  508. Status = RegOpenKeyEx(
  509. HKEY_LOCAL_MACHINE,
  510. DeviceEntry,
  511. 0,
  512. KEY_READ,
  513. &hKey
  514. );
  515. if( Status != ERROR_SUCCESS ) {
  516. return( rc );
  517. }
  518. //
  519. // Read the value entry associated with the hardware
  520. //
  521. lstrcpy( DeviceEntry, Args[1] );
  522. //
  523. // Get the value data associated with this entry
  524. //
  525. if (ServicesEntry = GetValueEntry (hKey, DeviceEntry)) {
  526. LPSTR Entry;
  527. if( (Entry = strstr( ServicesEntry, "Services\\")) != NULL &&
  528. (Entry = strchr( Entry, '\\' )) != NULL &&
  529. *++Entry != '\0'
  530. ) {
  531. LPSTR EndOfEntry;
  532. if( (EndOfEntry = strchr( Entry, '\\' )) != NULL ) {
  533. *EndOfEntry = '\0';
  534. }
  535. }
  536. else {
  537. Entry = ServicesEntry;
  538. }
  539. lstrcpy( ReturnBuffer, Entry );
  540. rc = lstrlen( Entry ) + 1;
  541. SFree( ServicesEntry );
  542. }
  543. RegCloseKey( hKey );
  544. return( rc );
  545. }
  546. /*
  547. Bus type as a string
  548. */
  549. BOOLEAN
  550. IsKeyNameInAdaptersTable(
  551. IN PSTR KeyName
  552. )
  553. {
  554. ULONG Index;
  555. for( Index = 0;
  556. Index < sizeof( AdaptersTable ) / sizeof( PCHAR );
  557. Index++ ) {
  558. if( _stricmp( KeyName, AdaptersTable[ Index ] ) == 0 ) {
  559. return( TRUE );
  560. }
  561. }
  562. return( FALSE );
  563. }
  564. LONG
  565. QueryMyBusTypeListWorker(
  566. IN HKEY ParentKey,
  567. IN PSTR CompleteParentKeyName,
  568. IN BOOLEAN FirstTimeCalled,
  569. IN BOOLEAN GetIdentifierFromParentKey,
  570. OUT PSTR* pReturnBuffer
  571. )
  572. {
  573. ULONG Index;
  574. LONG Status;
  575. PSTR BusTypeList;
  576. *pReturnBuffer = NULL;
  577. BusTypeList = NULL;
  578. if( !GetIdentifierFromParentKey && !IsKeyNameInAdaptersTable( strrchr( CompleteParentKeyName, '\\' ) + 1 ) ) {
  579. return( ERROR_SUCCESS );
  580. }
  581. if( GetIdentifierFromParentKey && !FirstTimeCalled ) {
  582. PSTR TmpString;
  583. ULONG TmpStringSize;
  584. TmpString = GetValueEntry( ParentKey, IDENTIFIER );
  585. if( ( TmpString != NULL ) &&
  586. ( ( TmpStringSize = strlen( TmpString ) ) != 0 ) ) {
  587. BusTypeList = SAlloc( TmpStringSize + 3 );
  588. if( BusTypeList == NULL ) {
  589. SFree( TmpString );
  590. return( ERROR_OUTOFMEMORY );
  591. }
  592. lstrcpy( BusTypeList, "\"" );
  593. lstrcat( BusTypeList, TmpString );
  594. lstrcat( BusTypeList, "\"" );
  595. SFree( TmpString );
  596. }
  597. }
  598. //
  599. // Find out whether or not this key has subkeys
  600. //
  601. {
  602. CHAR szClass[ MAX_PATH + 1 ];
  603. ULONG cchClass;
  604. ULONG cSubKeys;
  605. ULONG cchMaxSubkey;
  606. ULONG cchMaxClass;
  607. ULONG cValues;
  608. ULONG cchMaxValueName;
  609. ULONG cbMaxValueData;
  610. ULONG cbSecurityDescriptor;
  611. FILETIME ftLastWriteTime;
  612. cchClass = sizeof( szClass );
  613. Status = RegQueryInfoKey( ParentKey,
  614. szClass,
  615. &cchClass,
  616. NULL,
  617. &cSubKeys,
  618. &cchMaxSubkey,
  619. &cchMaxClass,
  620. &cValues,
  621. &cchMaxValueName,
  622. &cbMaxValueData,
  623. &cbSecurityDescriptor,
  624. &ftLastWriteTime );
  625. if( Status != ERROR_SUCCESS ) {
  626. if( BusTypeList != NULL ) {
  627. SFree( BusTypeList );
  628. }
  629. return( Status );
  630. }
  631. // check for PCMCIA bus first
  632. {
  633. SC_HANDLE hSCManager = OpenSCManager( NULL, SERVICES_ACTIVE_DATABASEA, GENERIC_READ );
  634. if ( hSCManager != NULL )
  635. {
  636. SC_HANDLE hService = OpenService( hSCManager, "Pcmcia", GENERIC_READ );
  637. if ( hService != NULL )
  638. {
  639. SERVICE_STATUS sStatus;
  640. if (QueryServiceStatus( hService, &sStatus ))
  641. {
  642. if ( sStatus.dwCurrentState == SERVICE_RUNNING )
  643. {
  644. PSTR TmpBuffer;
  645. ULONG TmpStringSize;
  646. TmpBuffer = SAlloc( lstrlen("PCMCIA") + 3 );
  647. lstrcpy( TmpBuffer, "\"" );
  648. lstrcat( TmpBuffer, "PCMCIA" );
  649. lstrcat( TmpBuffer, "\"" );
  650. TmpStringSize = strlen( TmpBuffer );
  651. if( BusTypeList == NULL ) {
  652. BusTypeList = TmpBuffer;
  653. } else if( strlen( BusTypeList ) == 0 ) {
  654. SFree( BusTypeList );
  655. BusTypeList = TmpBuffer;
  656. } else {
  657. BusTypeList = SRealloc( BusTypeList, strlen( BusTypeList ) + TmpStringSize + 2 );
  658. strcat( BusTypeList, "," );
  659. strcat( BusTypeList, TmpBuffer );
  660. SFree( TmpBuffer );
  661. }
  662. }
  663. }
  664. CloseServiceHandle(hService);
  665. }
  666. CloseServiceHandle(hSCManager);
  667. }
  668. }
  669. for( Index = 0; Index < cSubKeys; Index++ ) {
  670. HKEY ChildKey;
  671. CHAR ChildKeyName[ MAX_PATH + 1];
  672. CHAR CompleteChildKeyName[ 2*MAX_PATH + 1 ];
  673. PSTR TmpBuffer;
  674. ULONG TmpStringSize;
  675. Status = RegEnumKey( ParentKey,
  676. Index,
  677. ChildKeyName,
  678. sizeof( ChildKeyName ) );
  679. if( Status != ERROR_SUCCESS ) {
  680. continue;
  681. }
  682. //
  683. // Open the child key
  684. //
  685. Status = RegOpenKeyEx( ParentKey,
  686. ChildKeyName,
  687. 0,
  688. KEY_READ,
  689. &ChildKey );
  690. if( Status != ERROR_SUCCESS ) {
  691. continue;
  692. }
  693. lstrcpy( CompleteChildKeyName, CompleteParentKeyName );
  694. lstrcat( CompleteChildKeyName, "\\" );
  695. lstrcat( CompleteChildKeyName, ChildKeyName );
  696. //
  697. // Get the identifier from all subkeys, and traverse the subkeys if necessary
  698. //
  699. TmpBuffer = NULL;
  700. Status = QueryMyBusTypeListWorker( ChildKey,
  701. CompleteChildKeyName,
  702. FALSE,
  703. ( BOOLEAN )!GetIdentifierFromParentKey,
  704. &TmpBuffer );
  705. if( ( Status == ERROR_SUCCESS ) &&
  706. ( TmpBuffer != NULL ) &&
  707. ( ( TmpStringSize = strlen( TmpBuffer ) )!= 0 ) ) {
  708. if( BusTypeList == NULL ) {
  709. BusTypeList = TmpBuffer;
  710. } else if( strlen( BusTypeList ) == 0 ) {
  711. SFree( BusTypeList );
  712. BusTypeList = TmpBuffer;
  713. } else {
  714. BusTypeList = SRealloc( BusTypeList, strlen( BusTypeList ) + TmpStringSize + 2 );
  715. strcat( BusTypeList, "," );
  716. strcat( BusTypeList, TmpBuffer );
  717. SFree( TmpBuffer );
  718. }
  719. }
  720. RegCloseKey( ChildKey );
  721. }
  722. }
  723. *pReturnBuffer = BusTypeList;
  724. return( Status );
  725. }
  726. int __cdecl
  727. CompareFunction( const void * String1,
  728. const void * String2
  729. )
  730. {
  731. return( lstrcmpi( *( PSTR * )String1, *( PSTR * )String2 ) );
  732. }
  733. LONG
  734. RemoveDuplicateNamesFromList(
  735. IN PCSTR List,
  736. OUT PSTR* TrimmedList
  737. )
  738. {
  739. PSTR TmpList;
  740. ULONG ElementsInList;
  741. PSTR Pointer;
  742. PSTR* TmpBuffer;
  743. ULONG i;
  744. PSTR p1;
  745. //
  746. // Make a duplicate of the original list.
  747. // This is necessary, since strtok() modifies
  748. // the contents of the buffer that is passed
  749. // as parameter.
  750. //
  751. TmpList = SzDup( (SZ)List );
  752. if( TmpList == NULL ) {
  753. return( ERROR_OUTOFMEMORY );
  754. }
  755. //
  756. // Find out how many items the list contains
  757. //
  758. ElementsInList = 0;
  759. for( Pointer = strtok( TmpList, "," );
  760. Pointer != NULL;
  761. ElementsInList++, Pointer = strtok( NULL, "," ) );
  762. if( ElementsInList < 2 ) {
  763. //
  764. // If list contains less than two items, than there is
  765. // no duplicate item to remove. In this case, just return
  766. // a copy of the original list.
  767. //
  768. *TrimmedList = SzDup( (SZ)List );
  769. if( *TrimmedList == NULL ) {
  770. SFree( TmpList );
  771. return( ERROR_OUTOFMEMORY );
  772. }
  773. return( ERROR_SUCCESS );
  774. }
  775. //
  776. // If the list has more than one item, then it may have duplicates.
  777. // To remove the duplicates, we first need to sort the items in the
  778. // list. The items are sorted using the C runtime qsort().
  779. //
  780. TmpBuffer = SAlloc( ElementsInList*sizeof( PSTR ) );
  781. if( TmpBuffer == NULL ) {
  782. SFree( TmpList );
  783. return( ERROR_OUTOFMEMORY );
  784. }
  785. Pointer = TmpList;
  786. for( i = 0; i < ElementsInList; i++ ) {
  787. TmpBuffer[ i ] = Pointer;
  788. Pointer += strlen( Pointer ) + 1;
  789. }
  790. qsort( TmpBuffer, ElementsInList, sizeof( PSTR ), CompareFunction );
  791. //
  792. // TmpBuffer is now a sorted array of pointers to the items
  793. // in the list.
  794. // Using this array, we build a sorted list of items.
  795. // Since we now that this list's size will allways be less or
  796. // of the original list's size, we allocate a buffer assuming
  797. // maximum size.
  798. //
  799. p1 = SAlloc( lstrlen( List ) + 1 );
  800. if( p1 == NULL ) {
  801. SFree( TmpList );
  802. SFree( TmpBuffer );
  803. return( ERROR_OUTOFMEMORY );
  804. }
  805. //
  806. // Remove the duplicates from the array
  807. //
  808. for( i = 0; i < ElementsInList - 1; i++ ) {
  809. if( lstrcmpi( TmpBuffer[ i ], TmpBuffer[ i + 1] ) == 0 ) {
  810. TmpBuffer[ i ] = NULL;
  811. }
  812. }
  813. //
  814. // Copy the remaining items to the new list
  815. //
  816. *p1 = '\0';
  817. for( i = 0; i < ElementsInList; i++ ) {
  818. if( TmpBuffer[ i ] != NULL ) {
  819. if( lstrlen( p1 ) != 0 ) {
  820. lstrcat( p1, "," );
  821. }
  822. lstrcat( p1, TmpBuffer[i] );
  823. }
  824. }
  825. SFree( TmpList );
  826. SFree( TmpBuffer );
  827. *TrimmedList = p1;
  828. return( ERROR_SUCCESS );
  829. }
  830. CB
  831. GetMyBusTypeList(
  832. IN RGSZ Args,
  833. IN USHORT cArgs,
  834. OUT SZ ReturnBuffer,
  835. IN CB cbReturnBuffer
  836. )
  837. {
  838. ULONG Status;
  839. HKEY Key;
  840. PSTR KeyName = "HARDWARE\\DESCRIPTION\\System";
  841. PSTR Pointer = NULL;
  842. ULONG ListSize;
  843. PSTR TrimmedList;
  844. Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  845. KeyName,
  846. 0,
  847. KEY_READ,
  848. &Key );
  849. if( Status == ERROR_SUCCESS ) {
  850. Pointer = NULL;
  851. Status = QueryMyBusTypeListWorker( Key,
  852. KeyName,
  853. TRUE,
  854. TRUE,
  855. &Pointer );
  856. }
  857. if((Status != ERROR_SUCCESS) || !Pointer
  858. || (RemoveDuplicateNamesFromList(Pointer,&TrimmedList) != ERROR_SUCCESS)) {
  859. //
  860. // Failure case.
  861. //
  862. if(cbReturnBuffer >= 3) {
  863. lstrcpy(ReturnBuffer,"{}");
  864. ListSize = 3;
  865. } else {
  866. if(cbReturnBuffer) {
  867. ListSize = 1;
  868. *ReturnBuffer = 0;
  869. } else {
  870. ListSize = 0;
  871. }
  872. }
  873. if(Pointer) {
  874. SFree(Pointer);
  875. }
  876. return(ListSize);
  877. }
  878. SFree(Pointer);
  879. ListSize = lstrlen(TrimmedList) + 3;
  880. if(ListSize <= cbReturnBuffer) {
  881. ReturnBuffer[0] = '{';
  882. lstrcpy(&ReturnBuffer[1],TrimmedList);
  883. ReturnBuffer[ListSize-2] = '}';
  884. ReturnBuffer[ListSize-1] = 0;
  885. }
  886. SFree(TrimmedList);
  887. return(ListSize);
  888. }