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.

1623 lines
44 KiB

  1. /*++
  2. Copyright (c) 1993-1998 Microsoft Corporation
  3. Module Name:
  4. devclass.c
  5. Abstract:
  6. Device Installer routines dealing with class installation
  7. Author:
  8. Lonny McMichael (lonnym) 1-May-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef UNICODE
  14. //
  15. // ANSI version
  16. //
  17. BOOL
  18. WINAPI
  19. SetupDiGetINFClassA(
  20. IN PCSTR InfName,
  21. OUT LPGUID ClassGuid,
  22. OUT PSTR ClassName,
  23. IN DWORD ClassNameSize,
  24. OUT PDWORD RequiredSize OPTIONAL
  25. )
  26. {
  27. PWSTR infname;
  28. WCHAR classname[MAX_CLASS_NAME_LEN];
  29. PSTR ansiclassname;
  30. DWORD requiredsize;
  31. DWORD rc;
  32. BOOL b;
  33. rc = pSetupCaptureAndConvertAnsiArg(InfName,&infname);
  34. if(rc != NO_ERROR) {
  35. SetLastError(rc);
  36. return(FALSE);
  37. }
  38. b = SetupDiGetINFClassW(infname,ClassGuid,classname,MAX_CLASS_NAME_LEN,&requiredsize);
  39. rc = GetLastError();
  40. if(b) {
  41. if(ansiclassname = pSetupUnicodeToAnsi(classname)) {
  42. requiredsize = lstrlenA(ansiclassname) + 1;
  43. if(RequiredSize) {
  44. try {
  45. *RequiredSize = requiredsize;
  46. } except(EXCEPTION_EXECUTE_HANDLER) {
  47. b = FALSE;
  48. rc = ERROR_INVALID_PARAMETER;
  49. }
  50. }
  51. if(b) {
  52. if(requiredsize <= ClassNameSize) {
  53. if(!lstrcpyA(ClassName,ansiclassname)) {
  54. //
  55. // lstrcpy faulted; ClassName must be bad
  56. //
  57. b = FALSE;
  58. rc = ERROR_INVALID_PARAMETER;
  59. }
  60. } else {
  61. rc = ERROR_INSUFFICIENT_BUFFER;
  62. b = FALSE;
  63. }
  64. }
  65. MyFree(ansiclassname);
  66. } else {
  67. b = FALSE;
  68. rc = ERROR_NOT_ENOUGH_MEMORY;
  69. }
  70. }
  71. MyFree(infname);
  72. SetLastError(rc);
  73. return(b);
  74. }
  75. #else
  76. //
  77. // Unicode stub
  78. //
  79. BOOL
  80. WINAPI
  81. SetupDiGetINFClassW(
  82. IN PCWSTR InfName,
  83. OUT LPGUID ClassGuid,
  84. OUT PWSTR ClassName,
  85. IN DWORD ClassNameSize,
  86. OUT PDWORD RequiredSize OPTIONAL
  87. )
  88. {
  89. UNREFERENCED_PARAMETER(InfName);
  90. UNREFERENCED_PARAMETER(ClassGuid);
  91. UNREFERENCED_PARAMETER(ClassName);
  92. UNREFERENCED_PARAMETER(ClassNameSize);
  93. UNREFERENCED_PARAMETER(RequiredSize);
  94. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  95. return(FALSE);
  96. }
  97. #endif
  98. BOOL
  99. WINAPI
  100. SetupDiGetINFClass(
  101. IN PCTSTR InfName,
  102. OUT LPGUID ClassGuid,
  103. OUT PTSTR ClassName,
  104. IN DWORD ClassNameSize,
  105. OUT PDWORD RequiredSize OPTIONAL
  106. )
  107. /*++
  108. Routine Description:
  109. This API will return the class of the specified (Windows 4.0) INF. If just the
  110. filename was specified, then the file will be searched for in each of the
  111. directories listed in the DevicePath value entry under:
  112. HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion
  113. Otherwise, the filename will be used as-is.
  114. Arguments:
  115. InfName - Supplies the name of the INF file for which to retrieve class information.
  116. This name may include a path.
  117. ClassGuid - Receives the class GUID for the specified INF file. If the INF
  118. does not specify a class GUID, this variable will be set to GUID_NULL.
  119. (SetupDiClassGuidsFromName may then be used to determine if one or more
  120. classes of this name have already been installed.)
  121. ClassName - Receives the name of the class for the specified INF file. If the
  122. INF does not specify a class name, but does specify a GUID, then this buffer
  123. receives the name retrieved by calling SetupDiClassNameFromGuid. If
  124. SetupDiClassNameFromGuid can't retrieve a class name (e.g., the class hasn't
  125. yet been installed), then an empty string will be returned.
  126. ClassNameSize - Supplies the size, in characters, of the ClassName buffer.
  127. RequiredSize - Optionally, receives the number of characters required to store
  128. the class name (including terminating NULL). This will always be less
  129. than MAX_CLASS_NAME_LEN.
  130. Return Value:
  131. If the function succeeds, the return value is TRUE.
  132. If the function fails, the return value is FALSE. To get extended error
  133. information, call GetLastError.
  134. --*/
  135. {
  136. TCHAR PathBuffer[MAX_PATH];
  137. PLOADED_INF Inf = NULL;
  138. PCTSTR GuidString, ClassNameString;
  139. DWORD ErrorLineNumber, ClassNameStringLen;
  140. DWORD Err;
  141. BOOL TryPnf;
  142. WIN32_FIND_DATA FindData;
  143. PTSTR DontCare;
  144. DWORD TempRequiredSize;
  145. try {
  146. if(InfName == pSetupGetFileTitle(InfName)) {
  147. //
  148. // The specified INF name is a simple filename. Search for it in
  149. // the DevicePath search path list.
  150. //
  151. Err = SearchForInfFile(InfName,
  152. &FindData,
  153. INFINFO_INF_PATH_LIST_SEARCH,
  154. PathBuffer,
  155. SIZECHARS(PathBuffer),
  156. NULL
  157. );
  158. if(Err == NO_ERROR) {
  159. TryPnf = TRUE;
  160. } else {
  161. goto clean0;
  162. }
  163. } else {
  164. //
  165. // The specified INF filename contains more than just a filename.
  166. // Assume it's an absolute path. (We need to make sure it's
  167. // fully-qualified, because that's what LoadInfFile expects.)
  168. //
  169. TempRequiredSize = GetFullPathName(InfName,
  170. SIZECHARS(PathBuffer),
  171. PathBuffer,
  172. &DontCare
  173. );
  174. if(!TempRequiredSize) {
  175. Err = GetLastError();
  176. goto clean0;
  177. } else if(TempRequiredSize >= SIZECHARS(PathBuffer)) {
  178. MYASSERT(0);
  179. Err = ERROR_BUFFER_OVERFLOW;
  180. goto clean0;
  181. }
  182. if(FileExists(PathBuffer, &FindData)) {
  183. //
  184. // We have a valid file path, and we're ready to load this INF.
  185. //
  186. InfSourcePathFromFileName(PathBuffer, NULL, &TryPnf);
  187. } else {
  188. Err = GetLastError();
  189. goto clean0;
  190. }
  191. }
  192. //
  193. // Load the INF.
  194. //
  195. Err = LoadInfFile(PathBuffer,
  196. &FindData,
  197. INF_STYLE_WIN4,
  198. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0),
  199. NULL,
  200. NULL,
  201. NULL,
  202. NULL,
  203. NULL, // LogContext
  204. &Inf,
  205. &ErrorLineNumber,
  206. NULL
  207. );
  208. if(Err != NO_ERROR) {
  209. goto clean0;
  210. }
  211. //
  212. // Retrieve the Class name from the version section of the INF, if
  213. // supplied.
  214. //
  215. ClassNameString = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass);
  216. if(ClassNameString) {
  217. ClassNameStringLen = lstrlen(ClassNameString) + 1;
  218. if(RequiredSize) {
  219. *RequiredSize = ClassNameStringLen;
  220. }
  221. if(ClassNameStringLen > ClassNameSize) {
  222. Err = ERROR_INSUFFICIENT_BUFFER;
  223. goto clean1;
  224. }
  225. CopyMemory(ClassName,
  226. ClassNameString,
  227. ClassNameStringLen * sizeof(TCHAR)
  228. );
  229. }
  230. //
  231. // Retrieve the ClassGUID string from the version section,
  232. // if supplied
  233. //
  234. GuidString = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClassGuid);
  235. if(GuidString) {
  236. if((Err = pSetupGuidFromString(GuidString, ClassGuid)) != NO_ERROR) {
  237. goto clean1;
  238. }
  239. if(!ClassNameString) {
  240. //
  241. // Call SetupDiClassNameFromGuid to retrieve the class name
  242. // corresponding to this class GUID.
  243. //
  244. if(!SetupDiClassNameFromGuid(ClassGuid,
  245. ClassName,
  246. ClassNameSize,
  247. RequiredSize)) {
  248. Err = GetLastError();
  249. if(Err == ERROR_INVALID_CLASS) {
  250. //
  251. // Then this GUID represents a class that hasn't been
  252. // installed yet, so simply set the ClassName to be an
  253. // empty string.
  254. //
  255. if(RequiredSize) {
  256. *RequiredSize = 1;
  257. }
  258. if(ClassNameSize < 1) {
  259. Err = ERROR_INSUFFICIENT_BUFFER;
  260. goto clean1;
  261. }
  262. *ClassName = TEXT('\0');
  263. Err = NO_ERROR;
  264. } else {
  265. goto clean1;
  266. }
  267. }
  268. }
  269. } else if(ClassNameString) {
  270. //
  271. // Since no ClassGUID was given, set the supplied GUID buffer to GUID_NULL.
  272. //
  273. CopyMemory(ClassGuid,
  274. &GUID_NULL,
  275. sizeof(GUID)
  276. );
  277. } else {
  278. //
  279. // Neither the ClassGUID nor the Class version entries were provided,
  280. // so return an error.
  281. //
  282. Err = ERROR_NO_ASSOCIATED_CLASS;
  283. goto clean1;
  284. }
  285. clean1:
  286. FreeInfFile(Inf);
  287. Inf = NULL;
  288. clean0:
  289. ; // Nothing to do.
  290. } except(EXCEPTION_EXECUTE_HANDLER) {
  291. Err = ERROR_INVALID_PARAMETER;
  292. if(Inf) {
  293. FreeInfFile(Inf);
  294. }
  295. }
  296. SetLastError(Err);
  297. return (Err == NO_ERROR);
  298. }
  299. #ifdef UNICODE
  300. //
  301. // ANSI version
  302. //
  303. BOOL
  304. WINAPI
  305. SetupDiClassNameFromGuidA(
  306. IN CONST GUID *ClassGuid,
  307. OUT PSTR ClassName,
  308. IN DWORD ClassNameSize,
  309. OUT PDWORD RequiredSize OPTIONAL
  310. )
  311. {
  312. return SetupDiClassNameFromGuidExA(ClassGuid, ClassName, ClassNameSize, RequiredSize, NULL, NULL);
  313. }
  314. #else
  315. //
  316. // Unicode stub
  317. //
  318. BOOL
  319. WINAPI
  320. SetupDiClassNameFromGuidW(
  321. IN CONST GUID *ClassGuid,
  322. OUT PWSTR ClassName,
  323. IN DWORD ClassNameSize,
  324. OUT PDWORD RequiredSize OPTIONAL
  325. )
  326. {
  327. UNREFERENCED_PARAMETER(ClassGuid);
  328. UNREFERENCED_PARAMETER(ClassName);
  329. UNREFERENCED_PARAMETER(ClassNameSize);
  330. UNREFERENCED_PARAMETER(RequiredSize);
  331. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  332. return(FALSE);
  333. }
  334. #endif
  335. BOOL
  336. WINAPI
  337. SetupDiClassNameFromGuid(
  338. IN CONST GUID *ClassGuid,
  339. OUT PTSTR ClassName,
  340. IN DWORD ClassNameSize,
  341. OUT PDWORD RequiredSize OPTIONAL
  342. )
  343. /*++
  344. Routine Description:
  345. See SetupDiClassNameFromGuidEx for details.
  346. --*/
  347. {
  348. return SetupDiClassNameFromGuidEx(ClassGuid, ClassName, ClassNameSize, RequiredSize, NULL, NULL);
  349. }
  350. #ifdef UNICODE
  351. //
  352. // ANSI version
  353. //
  354. BOOL
  355. WINAPI
  356. SetupDiClassNameFromGuidExA(
  357. IN CONST GUID *ClassGuid,
  358. OUT PSTR ClassName,
  359. IN DWORD ClassNameSize,
  360. OUT PDWORD RequiredSize, OPTIONAL
  361. IN PCSTR MachineName, OPTIONAL
  362. IN PVOID Reserved
  363. )
  364. {
  365. WCHAR UnicodeClassName[MAX_CLASS_NAME_LEN];
  366. DWORD requiredsize;
  367. PSTR ansiclassname;
  368. DWORD rc;
  369. BOOL b;
  370. PCWSTR UnicodeMachineName;
  371. if(MachineName) {
  372. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  373. if(rc != NO_ERROR) {
  374. SetLastError(rc);
  375. return FALSE;
  376. }
  377. } else {
  378. UnicodeMachineName = NULL;
  379. }
  380. b = SetupDiClassNameFromGuidExW(ClassGuid,
  381. UnicodeClassName,
  382. SIZECHARS(UnicodeClassName),
  383. &requiredsize,
  384. UnicodeMachineName,
  385. Reserved
  386. );
  387. rc = GetLastError();
  388. if(b) {
  389. if(ansiclassname = pSetupUnicodeToAnsi(UnicodeClassName)) {
  390. requiredsize = lstrlenA(ansiclassname)+1;
  391. if(RequiredSize) {
  392. try {
  393. *RequiredSize = requiredsize;
  394. } except(EXCEPTION_EXECUTE_HANDLER) {
  395. b = FALSE;
  396. rc = ERROR_INVALID_PARAMETER;
  397. }
  398. }
  399. if(b) {
  400. if(requiredsize <= ClassNameSize) {
  401. if(!lstrcpyA(ClassName,ansiclassname)) {
  402. //
  403. // ClassName must be bad because lstrcpy faulted
  404. //
  405. b = FALSE;
  406. rc = ERROR_INVALID_PARAMETER;
  407. }
  408. } else {
  409. b = FALSE;
  410. rc = ERROR_INSUFFICIENT_BUFFER;
  411. }
  412. }
  413. MyFree(ansiclassname);
  414. } else {
  415. rc = ERROR_NOT_ENOUGH_MEMORY;
  416. b = FALSE;
  417. }
  418. }
  419. if(UnicodeMachineName) {
  420. MyFree(UnicodeMachineName);
  421. }
  422. SetLastError(rc);
  423. return(b);
  424. }
  425. #else
  426. //
  427. // Unicode stub
  428. //
  429. BOOL
  430. WINAPI
  431. SetupDiClassNameFromGuidExW(
  432. IN CONST GUID *ClassGuid,
  433. OUT PWSTR ClassName,
  434. IN DWORD ClassNameSize,
  435. OUT PDWORD RequiredSize, OPTIONAL
  436. IN PCWSTR MachineName, OPTIONAL
  437. IN PVOID Reserved
  438. )
  439. {
  440. UNREFERENCED_PARAMETER(ClassGuid);
  441. UNREFERENCED_PARAMETER(ClassName);
  442. UNREFERENCED_PARAMETER(ClassNameSize);
  443. UNREFERENCED_PARAMETER(RequiredSize);
  444. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  445. return(FALSE);
  446. }
  447. #endif
  448. BOOL
  449. WINAPI
  450. SetupDiClassNameFromGuidEx(
  451. IN CONST GUID *ClassGuid,
  452. OUT PTSTR ClassName,
  453. IN DWORD ClassNameSize,
  454. OUT PDWORD RequiredSize, OPTIONAL
  455. IN PCTSTR MachineName, OPTIONAL
  456. IN PVOID Reserved
  457. )
  458. /*++
  459. Routine Description:
  460. This API retrieves the class name associated with the class GUID. It does this
  461. by searching through all installed classes in the PnP Class branch of the registry.
  462. Arguments:
  463. ClassGuid - Supplies the class GUID for which the class name is to be retrieved.
  464. ClassName - Receives the name of the class for the specified GUID.
  465. ClassNameSize - Supplies the size, in characters, of the ClassName buffer.
  466. RequiredSize - Optionally, receives the number of characters required to store
  467. the class name (including terminating NULL). This will always be less
  468. than MAX_CLASS_NAME_LEN.
  469. MachineName - Optionally, supplies the name of the remote machine where the specified
  470. class is installed. If this parameter is not supplied, the local machine is
  471. used.
  472. Reserved - Reserved for future use--must be NULL.
  473. Return Value:
  474. If the function succeeds, the return value is TRUE.
  475. If the function fails, the return value is FALSE. To get extended error
  476. information, call GetLastError.
  477. --*/
  478. {
  479. CONFIGRET cr;
  480. DWORD Err = NO_ERROR;
  481. HMACHINE hMachine;
  482. //
  483. // Make sure the caller didn't pass us anything in the Reserved parameter.
  484. //
  485. if(Reserved) {
  486. SetLastError(ERROR_INVALID_PARAMETER);
  487. return FALSE;
  488. }
  489. //
  490. // If the caller specified a remote machine name, connect to that machine now.
  491. //
  492. if(MachineName) {
  493. cr = CM_Connect_Machine(MachineName, &hMachine);
  494. if(cr != CR_SUCCESS) {
  495. SetLastError(MapCrToSpError(cr, ERROR_INVALID_DATA));
  496. return FALSE;
  497. }
  498. } else {
  499. hMachine = NULL;
  500. }
  501. try {
  502. //
  503. // Get the class name associated with this GUID.
  504. //
  505. cr = CM_Get_Class_Name_Ex((LPGUID)ClassGuid,
  506. ClassName,
  507. &ClassNameSize,
  508. 0,
  509. hMachine
  510. );
  511. if((RequiredSize) && ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))) {
  512. *RequiredSize = ClassNameSize;
  513. }
  514. if(cr != CR_SUCCESS) {
  515. Err = (cr == CR_BUFFER_SMALL) ? ERROR_INSUFFICIENT_BUFFER
  516. : ERROR_INVALID_CLASS;
  517. }
  518. } except(EXCEPTION_EXECUTE_HANDLER) {
  519. Err = ERROR_INVALID_PARAMETER;
  520. }
  521. if(hMachine) {
  522. CM_Disconnect_Machine(hMachine);
  523. }
  524. SetLastError(Err);
  525. return(Err == NO_ERROR);
  526. }
  527. #ifdef UNICODE
  528. //
  529. // ANSI version
  530. //
  531. BOOL
  532. WINAPI
  533. SetupDiClassGuidsFromNameA(
  534. IN PCSTR ClassName,
  535. OUT LPGUID ClassGuidList,
  536. IN DWORD ClassGuidListSize,
  537. OUT PDWORD RequiredSize
  538. )
  539. {
  540. PWSTR classname;
  541. DWORD rc;
  542. BOOL b;
  543. rc = pSetupCaptureAndConvertAnsiArg(ClassName,&classname);
  544. if(rc != NO_ERROR) {
  545. SetLastError(rc);
  546. return(FALSE);
  547. }
  548. b = SetupDiClassGuidsFromNameExW(classname,ClassGuidList,ClassGuidListSize,RequiredSize,NULL,NULL);
  549. rc = GetLastError();
  550. MyFree(classname);
  551. SetLastError(rc);
  552. return(b);
  553. }
  554. #else
  555. //
  556. // Unicode stub
  557. //
  558. BOOL
  559. WINAPI
  560. SetupDiClassGuidsFromNameW(
  561. IN PCWSTR ClassName,
  562. OUT LPGUID ClassGuidList,
  563. IN DWORD ClassGuidListSize,
  564. OUT PDWORD RequiredSize
  565. )
  566. {
  567. UNREFERENCED_PARAMETER(ClassName);
  568. UNREFERENCED_PARAMETER(ClassGuidList);
  569. UNREFERENCED_PARAMETER(ClassGuidListSize);
  570. UNREFERENCED_PARAMETER(RequiredSize);
  571. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  572. return(FALSE);
  573. }
  574. #endif
  575. BOOL
  576. WINAPI
  577. SetupDiClassGuidsFromName(
  578. IN PCTSTR ClassName,
  579. OUT LPGUID ClassGuidList,
  580. IN DWORD ClassGuidListSize,
  581. OUT PDWORD RequiredSize
  582. )
  583. /*++
  584. Routine Description:
  585. See SetupDiClassGuidsFromNameEx for details.
  586. --*/
  587. {
  588. return SetupDiClassGuidsFromNameEx(ClassName,
  589. ClassGuidList,
  590. ClassGuidListSize,
  591. RequiredSize,
  592. NULL,
  593. NULL
  594. );
  595. }
  596. #ifdef UNICODE
  597. //
  598. // ANSI version
  599. //
  600. BOOL
  601. WINAPI
  602. SetupDiClassGuidsFromNameExA(
  603. IN PCSTR ClassName,
  604. OUT LPGUID ClassGuidList,
  605. IN DWORD ClassGuidListSize,
  606. OUT PDWORD RequiredSize,
  607. IN PCSTR MachineName, OPTIONAL
  608. IN PVOID Reserved
  609. )
  610. {
  611. PCWSTR UnicodeClassName, UnicodeMachineName;
  612. DWORD rc;
  613. BOOL b;
  614. rc = pSetupCaptureAndConvertAnsiArg(ClassName, &UnicodeClassName);
  615. if(rc != NO_ERROR) {
  616. SetLastError(rc);
  617. return FALSE;
  618. }
  619. if(MachineName) {
  620. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  621. if(rc != NO_ERROR) {
  622. MyFree(UnicodeClassName);
  623. SetLastError(rc);
  624. return FALSE;
  625. }
  626. } else {
  627. UnicodeMachineName = NULL;
  628. }
  629. b = SetupDiClassGuidsFromNameExW(UnicodeClassName,
  630. ClassGuidList,
  631. ClassGuidListSize,
  632. RequiredSize,
  633. UnicodeMachineName,
  634. Reserved
  635. );
  636. rc = GetLastError();
  637. MyFree(UnicodeClassName);
  638. if(UnicodeMachineName) {
  639. MyFree(UnicodeMachineName);
  640. }
  641. SetLastError(rc);
  642. return(b);
  643. }
  644. #else
  645. //
  646. // Unicode stub
  647. //
  648. BOOL
  649. WINAPI
  650. SetupDiClassGuidsFromNameExW(
  651. IN PCWSTR ClassName,
  652. OUT LPGUID ClassGuidList,
  653. IN DWORD ClassGuidListSize,
  654. OUT PDWORD RequiredSize,
  655. IN PCWSTR MachineName, OPTIONAL
  656. IN PVOID Reserved
  657. )
  658. {
  659. UNREFERENCED_PARAMETER(ClassName);
  660. UNREFERENCED_PARAMETER(ClassGuidList);
  661. UNREFERENCED_PARAMETER(ClassGuidListSize);
  662. UNREFERENCED_PARAMETER(RequiredSize);
  663. UNREFERENCED_PARAMETER(MachineName);
  664. UNREFERENCED_PARAMETER(Reserved);
  665. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  666. return(FALSE);
  667. }
  668. #endif
  669. BOOL
  670. WINAPI
  671. SetupDiClassGuidsFromNameEx(
  672. IN PCTSTR ClassName,
  673. OUT LPGUID ClassGuidList,
  674. IN DWORD ClassGuidListSize,
  675. OUT PDWORD RequiredSize,
  676. IN PCTSTR MachineName, OPTIONAL
  677. IN PVOID Reserved
  678. )
  679. /*++
  680. Routine Description:
  681. This API retrieves the GUID(s) associated with the specified class name.
  682. This list is built up based on what classes are currently installed on
  683. the system.
  684. Arguments:
  685. ClassName - Supplies the class name for which to retrieve associated class GUIDs.
  686. ClassGuidList - Supplies a pointer to an array of GUIDs that will receive the
  687. list of GUIDs associated with the specified class name.
  688. ClassGuidListSize - Supplies the number of GUIDs in the ClassGuidList buffer.
  689. RequiredSize - Supplies a pointer to the variable that recieves the number of GUIDs
  690. associated with the class name. If there are more GUIDs than there is room in
  691. the ClassGuidList buffer, then this value indicates how big the list must be in
  692. order to store all of the GUIDs.
  693. MachineName - Optionally, supplies the name of the remote machine where the specified
  694. class name is to be 'looked up' (i.e., where one or more classes are installed that
  695. have this name). If this parameter is not specified, the local machine is used.
  696. Reserved - Reserved for future use--must be NULL.
  697. Return Value:
  698. If the function succeeds, the return value is TRUE.
  699. If the function fails, the return value is FALSE. To get extended error
  700. information, call GetLastError.
  701. --*/
  702. {
  703. BOOL MoreToEnum;
  704. DWORD Err = NO_ERROR;
  705. CONFIGRET cr;
  706. ULONG i, CurClassNameLen, GuidMatchCount = 0;
  707. GUID CurClassGuid;
  708. TCHAR CurClassName[MAX_CLASS_NAME_LEN];
  709. HMACHINE hMachine;
  710. //
  711. // Make sure the caller specified the class name, and didn't pass us anything in the
  712. // Reserved parameter.
  713. //
  714. if(!ClassName || Reserved) {
  715. SetLastError(ERROR_INVALID_PARAMETER);
  716. return FALSE;
  717. }
  718. //
  719. // If the caller specified a remote machine name, connect to that machine now.
  720. //
  721. if(MachineName) {
  722. cr = CM_Connect_Machine(MachineName, &hMachine);
  723. if(cr != CR_SUCCESS) {
  724. SetLastError(MapCrToSpError(cr, ERROR_INVALID_DATA));
  725. return FALSE;
  726. }
  727. } else {
  728. hMachine = NULL;
  729. }
  730. try {
  731. //
  732. // Enumerate all the installed classes.
  733. //
  734. for(i = 0, MoreToEnum = TRUE; MoreToEnum; i++) {
  735. if((cr = CM_Enumerate_Classes_Ex(i, &CurClassGuid, 0, hMachine)) != CR_SUCCESS) {
  736. //
  737. // For any failure other than no-more-to-enum (or some kind of RPC error),
  738. // we simply want to go on to the next class.
  739. //
  740. switch(cr) {
  741. case CR_INVALID_MACHINENAME :
  742. case CR_REMOTE_COMM_FAILURE :
  743. case CR_MACHINE_UNAVAILABLE :
  744. case CR_NO_CM_SERVICES :
  745. case CR_ACCESS_DENIED :
  746. case CR_CALL_NOT_IMPLEMENTED :
  747. case CR_REGISTRY_ERROR :
  748. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  749. //
  750. // Fall through to 'no more values' case to terminate loop.
  751. //
  752. case CR_NO_SUCH_VALUE :
  753. MoreToEnum = FALSE;
  754. break;
  755. default :
  756. //
  757. // Nothing to do.
  758. //
  759. break;
  760. }
  761. continue;
  762. }
  763. //
  764. // Now, retrieve the class name associated with this class GUID.
  765. //
  766. CurClassNameLen = SIZECHARS(CurClassName);
  767. if(CM_Get_Class_Name_Ex(&CurClassGuid,
  768. CurClassName,
  769. &CurClassNameLen,
  770. 0,
  771. hMachine) != CR_SUCCESS) {
  772. continue;
  773. }
  774. //
  775. // See if the current class name matches the class we're interested in.
  776. //
  777. if(!lstrcmpi(ClassName, CurClassName)) {
  778. if(GuidMatchCount < ClassGuidListSize) {
  779. CopyMemory(&(ClassGuidList[GuidMatchCount]), &CurClassGuid, sizeof(GUID));
  780. }
  781. GuidMatchCount++;
  782. }
  783. }
  784. if(Err == NO_ERROR) {
  785. *RequiredSize = GuidMatchCount;
  786. if(GuidMatchCount > ClassGuidListSize) {
  787. Err = ERROR_INSUFFICIENT_BUFFER;
  788. }
  789. }
  790. } except(EXCEPTION_EXECUTE_HANDLER) {
  791. Err = ERROR_INVALID_PARAMETER;
  792. }
  793. if(hMachine) {
  794. CM_Disconnect_Machine(hMachine);
  795. }
  796. SetLastError(Err);
  797. return(Err == NO_ERROR);
  798. }
  799. #ifdef UNICODE
  800. //
  801. // ANSI version
  802. //
  803. BOOL
  804. WINAPI
  805. SetupDiGetClassDescriptionA(
  806. IN CONST GUID *ClassGuid,
  807. OUT PSTR ClassDescription,
  808. IN DWORD ClassDescriptionSize,
  809. OUT PDWORD RequiredSize OPTIONAL
  810. )
  811. {
  812. return SetupDiGetClassDescriptionExA(ClassGuid,
  813. ClassDescription,
  814. ClassDescriptionSize,
  815. RequiredSize,
  816. NULL,
  817. NULL
  818. );
  819. }
  820. #else
  821. //
  822. // Unicode stub
  823. //
  824. BOOL
  825. WINAPI
  826. SetupDiGetClassDescriptionW(
  827. IN CONST GUID *ClassGuid,
  828. OUT PWSTR ClassDescription,
  829. IN DWORD ClassDescriptionSize,
  830. OUT PDWORD RequiredSize OPTIONAL
  831. )
  832. {
  833. UNREFERENCED_PARAMETER(ClassGuid);
  834. UNREFERENCED_PARAMETER(ClassDescription);
  835. UNREFERENCED_PARAMETER(ClassDescriptionSize);
  836. UNREFERENCED_PARAMETER(RequiredSize);
  837. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  838. return(FALSE);
  839. }
  840. #endif
  841. BOOL
  842. WINAPI
  843. SetupDiGetClassDescription(
  844. IN CONST GUID *ClassGuid,
  845. OUT PTSTR ClassDescription,
  846. IN DWORD ClassDescriptionSize,
  847. OUT PDWORD RequiredSize OPTIONAL
  848. )
  849. /*++
  850. Routine Description:
  851. This routine retrieves the class description associated with the specified
  852. class GUID.
  853. Arguments:
  854. ClassGuid - Specifies the class GUID to retrieve the description for.
  855. ClassDescription - Supplies the address of the character buffer that is to receive
  856. the textual description of the class.
  857. ClassDescriptionSize - Supplies the size, in characters, of the ClassDescription buffer.
  858. RequiredSize - Optionally, receives the number of characters required to store
  859. the class description (including terminating NULL). This will always be less
  860. than LINE_LEN.
  861. Return Value:
  862. If the function succeeds, the return value is TRUE.
  863. If the function fails, the return value is FALSE. To get extended error
  864. information, call GetLastError.
  865. --*/
  866. {
  867. return SetupDiGetClassDescriptionEx(ClassGuid,
  868. ClassDescription,
  869. ClassDescriptionSize,
  870. RequiredSize,
  871. NULL,
  872. NULL
  873. );
  874. }
  875. #ifdef UNICODE
  876. //
  877. // ANSI version
  878. //
  879. BOOL
  880. WINAPI
  881. SetupDiGetClassDescriptionExA(
  882. IN CONST GUID *ClassGuid,
  883. OUT PSTR ClassDescription,
  884. IN DWORD ClassDescriptionSize,
  885. OUT PDWORD RequiredSize, OPTIONAL
  886. IN PCSTR MachineName, OPTIONAL
  887. IN PVOID Reserved
  888. )
  889. {
  890. WCHAR UnicodeClassDescription[LINE_LEN];
  891. PSTR ansidescription;
  892. DWORD requiredsize;
  893. DWORD rc;
  894. BOOL b;
  895. PCWSTR UnicodeMachineName;
  896. if(MachineName) {
  897. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  898. if(rc != NO_ERROR) {
  899. SetLastError(rc);
  900. return FALSE;
  901. }
  902. } else {
  903. UnicodeMachineName = NULL;
  904. }
  905. b = SetupDiGetClassDescriptionExW(ClassGuid,
  906. UnicodeClassDescription,
  907. SIZECHARS(UnicodeClassDescription),
  908. &requiredsize,
  909. UnicodeMachineName,
  910. Reserved
  911. );
  912. rc = GetLastError();
  913. if(b) {
  914. if(ansidescription = pSetupUnicodeToAnsi(UnicodeClassDescription)) {
  915. requiredsize = lstrlenA(ansidescription)+1;
  916. if(RequiredSize) {
  917. try {
  918. *RequiredSize = requiredsize;
  919. } except(EXCEPTION_EXECUTE_HANDLER) {
  920. rc = ERROR_INVALID_PARAMETER;
  921. b = FALSE;
  922. }
  923. }
  924. if(b) {
  925. if(requiredsize <= ClassDescriptionSize) {
  926. if(!lstrcpyA(ClassDescription,ansidescription)) {
  927. //
  928. // ClassDescription must be bad because lstrcpy faulted.
  929. //
  930. rc = ERROR_INVALID_PARAMETER;
  931. b = FALSE;
  932. }
  933. } else {
  934. rc = ERROR_INSUFFICIENT_BUFFER;
  935. b = FALSE;
  936. }
  937. }
  938. MyFree(ansidescription);
  939. } else {
  940. rc = ERROR_NOT_ENOUGH_MEMORY;
  941. b = FALSE;
  942. }
  943. }
  944. if(UnicodeMachineName) {
  945. MyFree(UnicodeMachineName);
  946. }
  947. SetLastError(rc);
  948. return(b);
  949. }
  950. #else
  951. //
  952. // Unicode stub
  953. //
  954. BOOL
  955. WINAPI
  956. SetupDiGetClassDescriptionExW(
  957. IN CONST GUID *ClassGuid,
  958. OUT PWSTR ClassDescription,
  959. IN DWORD ClassDescriptionSize,
  960. OUT PDWORD RequiredSize, OPTIONAL
  961. IN PCWSTR MachineName, OPTIONAL
  962. IN PVOID Reserved
  963. )
  964. {
  965. UNREFERENCED_PARAMETER(ClassGuid);
  966. UNREFERENCED_PARAMETER(ClassDescription);
  967. UNREFERENCED_PARAMETER(ClassDescriptionSize);
  968. UNREFERENCED_PARAMETER(RequiredSize);
  969. UNREFERENCED_PARAMETER(MachineName);
  970. UNREFERENCED_PARAMETER(Reserved);
  971. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  972. return(FALSE);
  973. }
  974. #endif
  975. BOOL
  976. WINAPI
  977. SetupDiGetClassDescriptionEx(
  978. IN CONST GUID *ClassGuid,
  979. OUT PTSTR ClassDescription,
  980. IN DWORD ClassDescriptionSize,
  981. OUT PDWORD RequiredSize, OPTIONAL
  982. IN PCTSTR MachineName, OPTIONAL
  983. IN PVOID Reserved
  984. )
  985. /*++
  986. Routine Description:
  987. This routine retrieves the class description associated with the specified
  988. class GUID.
  989. Arguments:
  990. ClassGuid - Specifies the class GUID to retrieve the description for.
  991. ClassDescription - Supplies the address of the character buffer that is to receive
  992. the textual description of the class.
  993. ClassDescriptionSize - Supplies the size, in characters, of the ClassDescription buffer.
  994. RequiredSize - Optionally, receives the number of characters required to store
  995. the class description (including terminating NULL). This will always be less
  996. than LINE_LEN.
  997. MachineName - Optionally, supplies the name of the remote machine where the class
  998. whose name we're retrieving is installed. If this parameter is not supplied,
  999. the local machine is used.
  1000. Reserved - Reserved for future use--must be NULL.
  1001. Return Value:
  1002. If the function succeeds, the return value is TRUE.
  1003. If the function fails, the return value is FALSE. To get extended error
  1004. information, call GetLastError.
  1005. --*/
  1006. {
  1007. DWORD Err = NO_ERROR;
  1008. LONG l;
  1009. TCHAR NullChar = TEXT('\0');
  1010. CONFIGRET cr;
  1011. HKEY hk = INVALID_HANDLE_VALUE;
  1012. DWORD ValueType, BufferSize;
  1013. BOOL DescFound = FALSE;
  1014. HMACHINE hMachine;
  1015. //
  1016. // Make sure the caller didn't pass us anything in the Reserved parameter.
  1017. //
  1018. if(Reserved) {
  1019. SetLastError(ERROR_INVALID_PARAMETER);
  1020. return FALSE;
  1021. }
  1022. //
  1023. // If the caller specified a remote machine name, connect to that machine now.
  1024. //
  1025. if(MachineName) {
  1026. cr = CM_Connect_Machine(MachineName, &hMachine);
  1027. if(cr != CR_SUCCESS) {
  1028. SetLastError(MapCrToSpError(cr, ERROR_INVALID_DATA));
  1029. return FALSE;
  1030. }
  1031. } else {
  1032. hMachine = NULL;
  1033. }
  1034. try {
  1035. if(CM_Open_Class_Key_Ex((LPGUID)ClassGuid,
  1036. NULL,
  1037. KEY_READ,
  1038. RegDisposition_OpenExisting,
  1039. &hk,
  1040. CM_OPEN_CLASS_KEY_INSTALLER,
  1041. hMachine) != CR_SUCCESS) {
  1042. Err = ERROR_INVALID_CLASS;
  1043. hk = INVALID_HANDLE_VALUE;
  1044. goto clean0;
  1045. }
  1046. //
  1047. // Retrieve the class description from the opened key. This is an (optional)
  1048. // unnamed REG_SZ value.
  1049. //
  1050. BufferSize = ClassDescriptionSize * sizeof(TCHAR);
  1051. l = RegQueryValueEx(hk,
  1052. &NullChar, // retrieved the unnamed value
  1053. NULL,
  1054. &ValueType,
  1055. (LPBYTE)ClassDescription,
  1056. &BufferSize
  1057. );
  1058. if((l == ERROR_SUCCESS) || (l == ERROR_MORE_DATA)) {
  1059. //
  1060. // Verify that the data type is correct.
  1061. //
  1062. if(ValueType == REG_SZ) {
  1063. DescFound = TRUE;
  1064. BufferSize /= sizeof(TCHAR); // we need this in characters
  1065. //
  1066. // Be careful here, because the user may have passed in a NULL
  1067. // pointer for the ClassDescription buffer (ie, they just wanted
  1068. // to know what size they needed). RegQueryValueEx would return
  1069. // ERROR_SUCCESS in this case, but we want to return
  1070. // ERROR_INSUFFICIENT_BUFFER.
  1071. //
  1072. if((l == ERROR_MORE_DATA) || !ClassDescription) {
  1073. Err = ERROR_INSUFFICIENT_BUFFER;
  1074. }
  1075. }
  1076. }
  1077. if(!DescFound) {
  1078. //
  1079. // Then we simply retrieve the class name associated with this GUID--in
  1080. // this case it serves as both name and description.
  1081. //
  1082. BufferSize = ClassDescriptionSize;
  1083. cr = CM_Get_Class_Name_Ex((LPGUID)ClassGuid,
  1084. ClassDescription,
  1085. &BufferSize,
  1086. 0,
  1087. hMachine
  1088. );
  1089. switch(cr) {
  1090. case CR_BUFFER_SMALL :
  1091. Err = ERROR_INSUFFICIENT_BUFFER;
  1092. //
  1093. // Allow to fall through to CR_SUCCESS case.
  1094. //
  1095. case CR_SUCCESS :
  1096. DescFound = TRUE;
  1097. break;
  1098. case CR_REGISTRY_ERROR :
  1099. Err = ERROR_INVALID_CLASS;
  1100. break;
  1101. default :
  1102. Err = ERROR_INVALID_PARAMETER;
  1103. }
  1104. }
  1105. //
  1106. // Store the required size in the output parameter, if supplied.
  1107. //
  1108. if(DescFound && RequiredSize) {
  1109. *RequiredSize = BufferSize;
  1110. }
  1111. clean0:
  1112. ; // Nothing to do.
  1113. } except(EXCEPTION_EXECUTE_HANDLER) {
  1114. Err = ERROR_INVALID_PARAMETER;
  1115. //
  1116. // Reference the following variable so the compiler will respect statement ordering
  1117. // w.r.t. assignment.
  1118. //
  1119. hk = hk;
  1120. }
  1121. if(hk != INVALID_HANDLE_VALUE) {
  1122. RegCloseKey(hk);
  1123. }
  1124. if(hMachine) {
  1125. CM_Disconnect_Machine(hMachine);
  1126. }
  1127. SetLastError(Err);
  1128. return(Err == NO_ERROR);
  1129. }
  1130. BOOL
  1131. WINAPI
  1132. SetupDiBuildClassInfoList(
  1133. IN DWORD Flags,
  1134. OUT LPGUID ClassGuidList,
  1135. IN DWORD ClassGuidListSize,
  1136. OUT PDWORD RequiredSize
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. See SetupDiBuildClassInfoListEx for details.
  1141. --*/
  1142. {
  1143. return SetupDiBuildClassInfoListEx(Flags, ClassGuidList, ClassGuidListSize, RequiredSize, NULL, NULL);
  1144. }
  1145. #ifdef UNICODE
  1146. //
  1147. // ANSI version
  1148. //
  1149. BOOL
  1150. WINAPI
  1151. SetupDiBuildClassInfoListExA(
  1152. IN DWORD Flags,
  1153. OUT LPGUID ClassGuidList,
  1154. IN DWORD ClassGuidListSize,
  1155. OUT PDWORD RequiredSize,
  1156. IN PCSTR MachineName, OPTIONAL
  1157. IN PVOID Reserved
  1158. )
  1159. {
  1160. PCWSTR UnicodeMachineName;
  1161. DWORD rc;
  1162. BOOL b;
  1163. b = FALSE;
  1164. if(MachineName) {
  1165. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  1166. } else {
  1167. UnicodeMachineName = NULL;
  1168. rc = NO_ERROR;
  1169. }
  1170. if(rc == NO_ERROR) {
  1171. b = SetupDiBuildClassInfoListExW(Flags,
  1172. ClassGuidList,
  1173. ClassGuidListSize,
  1174. RequiredSize,
  1175. UnicodeMachineName,
  1176. Reserved
  1177. );
  1178. rc = GetLastError();
  1179. if(UnicodeMachineName) {
  1180. MyFree(UnicodeMachineName);
  1181. }
  1182. }
  1183. SetLastError(rc);
  1184. return b;
  1185. }
  1186. #else
  1187. //
  1188. // Unicode version
  1189. //
  1190. BOOL
  1191. WINAPI
  1192. SetupDiBuildClassInfoListExW(
  1193. IN DWORD Flags,
  1194. OUT LPGUID ClassGuidList,
  1195. IN DWORD ClassGuidListSize,
  1196. OUT PDWORD RequiredSize,
  1197. IN PCWSTR MachineName, OPTIONAL
  1198. IN PVOID Reserved
  1199. )
  1200. {
  1201. UNREFERENCED_PARAMETER(Flags);
  1202. UNREFERENCED_PARAMETER(ClassGuidList);
  1203. UNREFERENCED_PARAMETER(ClassGuidListSize);
  1204. UNREFERENCED_PARAMETER(RequiredSize);
  1205. UNREFERENCED_PARAMETER(MachineName);
  1206. UNREFERENCED_PARAMETER(Reserved);
  1207. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1208. return(FALSE);
  1209. }
  1210. #endif
  1211. BOOL
  1212. WINAPI
  1213. SetupDiBuildClassInfoListEx(
  1214. IN DWORD Flags,
  1215. OUT LPGUID ClassGuidList,
  1216. IN DWORD ClassGuidListSize,
  1217. OUT PDWORD RequiredSize,
  1218. IN PCTSTR MachineName, OPTIONAL
  1219. IN PVOID Reserved
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This routine returns a list of class GUIDs representing every class installed
  1224. on the user's system. (NOTE: Classes that have a 'NoUseClass' value entry in
  1225. their registry branch will be excluded from this list.)
  1226. Arguments:
  1227. Flags - Supplies flags used to control exclusion of classes from the list. If
  1228. no flags are specified, then all classes are included. The flags may be a
  1229. combination of the following:
  1230. DIBCI_NOINSTALLCLASS - Exclude a class if it has the value entry
  1231. 'NoInstallClass' in its registry key.
  1232. DIBCI_NODISPLAYCLASS - Exclude a class if it has the value entry
  1233. 'NoDisplayClass' in its registry key.
  1234. ClassGuidList - Supplies the address of an array of GUIDs that will receive the
  1235. GUID list.
  1236. ClassGuidListSize - Supplies the number of GUIDs in the ClassGuidList array.
  1237. RequiredSize - Supplies the address of a variable that will receive the number
  1238. of GUIDs returned. If this number is greater than the size of the ClassGuidList,
  1239. then this number will specify how large the array needs to be in order to contain
  1240. the list.
  1241. MachineName - Optionally, supplies the name of a remote machine to retrieve installed
  1242. classes from. If this parameter is not specified, the local machine is used.
  1243. Reserved - Reserved for future use--must be NULL.
  1244. Return Value:
  1245. If the function succeeds, the return value is TRUE.
  1246. If the function fails, the return value is FALSE. To get extended error
  1247. information, call GetLastError.
  1248. --*/
  1249. {
  1250. DWORD Err = NO_ERROR, ClassGuidCount = 0;
  1251. CONFIGRET cr;
  1252. BOOL MoreToEnum;
  1253. ULONG i;
  1254. HKEY hk = INVALID_HANDLE_VALUE;
  1255. GUID CurClassGuid;
  1256. HMACHINE hMachine;
  1257. //
  1258. // Make sure the caller didn't pass us anything in the Reserved parameter.
  1259. //
  1260. if(Reserved) {
  1261. SetLastError(ERROR_INVALID_PARAMETER);
  1262. return FALSE;
  1263. }
  1264. //
  1265. // If the caller specified a remote machine name, connect to that machine now.
  1266. //
  1267. if(MachineName) {
  1268. cr = CM_Connect_Machine(MachineName, &hMachine);
  1269. if(cr != CR_SUCCESS) {
  1270. SetLastError(MapCrToSpError(cr, ERROR_INVALID_DATA));
  1271. return FALSE;
  1272. }
  1273. } else {
  1274. hMachine = NULL;
  1275. }
  1276. try {
  1277. //
  1278. // Enumerate through the list of all installed classes.
  1279. //
  1280. for(i = 0, MoreToEnum = TRUE; MoreToEnum; i++) {
  1281. cr = CM_Enumerate_Classes_Ex(i,
  1282. &CurClassGuid,
  1283. 0,
  1284. hMachine
  1285. );
  1286. if(cr != CR_SUCCESS) {
  1287. //
  1288. // For any failure other than no-more-to-enum (or some kind of RPC error),
  1289. // we simply want to go on to the next class.
  1290. //
  1291. switch(cr) {
  1292. case CR_INVALID_MACHINENAME :
  1293. case CR_REMOTE_COMM_FAILURE :
  1294. case CR_MACHINE_UNAVAILABLE :
  1295. case CR_NO_CM_SERVICES :
  1296. case CR_ACCESS_DENIED :
  1297. case CR_CALL_NOT_IMPLEMENTED :
  1298. case CR_REGISTRY_ERROR :
  1299. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1300. //
  1301. // Fall through to 'no more values' case to terminate loop.
  1302. //
  1303. case CR_NO_SUCH_VALUE :
  1304. MoreToEnum = FALSE;
  1305. break;
  1306. default :
  1307. //
  1308. // Nothing to do.
  1309. //
  1310. break;
  1311. }
  1312. continue;
  1313. }
  1314. //
  1315. // Open the key for this class.
  1316. //
  1317. if(CM_Open_Class_Key_Ex(&CurClassGuid,
  1318. NULL,
  1319. KEY_READ,
  1320. RegDisposition_OpenExisting,
  1321. &hk,
  1322. CM_OPEN_CLASS_KEY_INSTALLER,
  1323. hMachine) != CR_SUCCESS) {
  1324. hk = INVALID_HANDLE_VALUE;
  1325. continue;
  1326. }
  1327. //
  1328. // First, check for the presence of the value entry "NoUseClass"
  1329. // If this value is present, then we will skip this class.
  1330. //
  1331. if(RegQueryValueEx(hk, pszNoUseClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  1332. goto clean0;
  1333. }
  1334. //
  1335. // Check for special exclusion flags.
  1336. //
  1337. if(Flags & DIBCI_NOINSTALLCLASS) {
  1338. if(RegQueryValueEx(hk, pszNoInstallClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  1339. goto clean0;
  1340. }
  1341. }
  1342. if(Flags & DIBCI_NODISPLAYCLASS) {
  1343. if(RegQueryValueEx(hk, pszNoDisplayClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  1344. goto clean0;
  1345. }
  1346. }
  1347. if(ClassGuidCount < ClassGuidListSize) {
  1348. CopyMemory(&(ClassGuidList[ClassGuidCount]), &CurClassGuid, sizeof(GUID));
  1349. }
  1350. ClassGuidCount++;
  1351. clean0:
  1352. RegCloseKey(hk);
  1353. hk = INVALID_HANDLE_VALUE;
  1354. }
  1355. if(Err == NO_ERROR) {
  1356. *RequiredSize = ClassGuidCount;
  1357. if(ClassGuidCount > ClassGuidListSize) {
  1358. Err = ERROR_INSUFFICIENT_BUFFER;
  1359. }
  1360. }
  1361. } except(EXCEPTION_EXECUTE_HANDLER) {
  1362. Err = ERROR_INVALID_PARAMETER;
  1363. if(hk != INVALID_HANDLE_VALUE) {
  1364. RegCloseKey(hk);
  1365. }
  1366. }
  1367. if(hMachine) {
  1368. CM_Disconnect_Machine(hMachine);
  1369. }
  1370. SetLastError(Err);
  1371. return(Err == NO_ERROR);
  1372. }