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.

1600 lines
47 KiB

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