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.

3639 lines
124 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devreg.c
  5. Abstract:
  6. Device Installer routines for registry storage/retrieval.
  7. Author:
  8. Lonny McMichael (lonnym) 1-July-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Private function prototypes
  15. //
  16. DWORD
  17. pSetupOpenOrCreateDevRegKey(
  18. IN PDEVICE_INFO_SET DeviceInfoSet,
  19. IN PDEVINFO_ELEM DevInfoElem,
  20. IN DWORD Scope,
  21. IN DWORD HwProfile,
  22. IN DWORD KeyType,
  23. IN BOOL Create,
  24. IN REGSAM samDesired,
  25. OUT PHKEY hDevRegKey,
  26. OUT PDWORD KeyDisposition OPTIONAL
  27. );
  28. BOOL
  29. pSetupFindUniqueKey(
  30. IN HKEY hkRoot,
  31. IN LPTSTR SubKey,
  32. IN size_t SubKeySize
  33. );
  34. DWORD
  35. pSetupOpenOrCreateDeviceInterfaceRegKey(
  36. IN HKEY hInterfaceClassKey,
  37. IN PDEVICE_INFO_SET DeviceInfoSet,
  38. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  39. IN BOOL Create,
  40. IN REGSAM samDesired,
  41. OUT PHKEY hDeviceInterfaceKey,
  42. OUT PDWORD KeyDisposition OPTIONAL
  43. );
  44. DWORD
  45. pSetupDeleteDeviceInterfaceKey(
  46. IN HKEY hInterfaceClassKey,
  47. IN PDEVICE_INFO_SET DeviceInfoSet,
  48. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  49. );
  50. HKEY
  51. WINAPI
  52. SetupDiOpenClassRegKey(
  53. IN CONST GUID *ClassGuid, OPTIONAL
  54. IN REGSAM samDesired
  55. )
  56. /*++
  57. Routine Description:
  58. This API opens the installer class registry key or a specific class
  59. installer's subkey.
  60. Arguments:
  61. ClassGuid - Optionally, supplies a pointer to the GUID of the class whose
  62. key is to be opened. If this parameter is NULL, then the root of the
  63. class tree will be opened.
  64. samDesired - Specifies the access you require for this key.
  65. Return Value:
  66. If the function succeeds, the return value is a handle to an opened registry
  67. key.
  68. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  69. extended error information, call GetLastError.
  70. Remarks:
  71. This API _will not_ create a registry key if it doesn't already exist.
  72. The handle returned from this API must be closed by calling RegCloseKey.
  73. To get at the interface class (DeviceClasses) branch, or to access the
  74. registry on a remote machine, use SetupDiOpenClassRegKeyEx.
  75. --*/
  76. {
  77. DWORD Err;
  78. HKEY hKey = INVALID_HANDLE_VALUE;
  79. try {
  80. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  81. hKey = SetupDiOpenClassRegKeyEx(ClassGuid,
  82. samDesired,
  83. DIOCR_INSTALLER,
  84. NULL,
  85. NULL)
  86. );
  87. } except(pSetupExceptionFilter(GetExceptionCode())) {
  88. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  89. }
  90. SetLastError(Err);
  91. return hKey;
  92. }
  93. //
  94. // ANSI version
  95. //
  96. HKEY
  97. WINAPI
  98. SetupDiOpenClassRegKeyExA(
  99. IN CONST GUID *ClassGuid, OPTIONAL
  100. IN REGSAM samDesired,
  101. IN DWORD Flags,
  102. IN PCSTR MachineName, OPTIONAL
  103. IN PVOID Reserved
  104. )
  105. {
  106. PCWSTR UnicodeMachineName = NULL;
  107. HKEY hk = INVALID_HANDLE_VALUE;
  108. DWORD rc;
  109. try {
  110. if(MachineName) {
  111. rc = pSetupCaptureAndConvertAnsiArg(MachineName,
  112. &UnicodeMachineName
  113. );
  114. if(rc != NO_ERROR) {
  115. leave;
  116. }
  117. }
  118. rc = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  119. hk = SetupDiOpenClassRegKeyExW(ClassGuid,
  120. samDesired,
  121. Flags,
  122. UnicodeMachineName,
  123. Reserved)
  124. );
  125. } except(pSetupExceptionFilter(GetExceptionCode())) {
  126. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &rc);
  127. }
  128. if(UnicodeMachineName) {
  129. MyFree(UnicodeMachineName);
  130. }
  131. SetLastError(rc);
  132. return hk;
  133. }
  134. HKEY
  135. WINAPI
  136. SetupDiOpenClassRegKeyEx(
  137. IN CONST GUID *ClassGuid, OPTIONAL
  138. IN REGSAM samDesired,
  139. IN DWORD Flags,
  140. IN PCTSTR MachineName, OPTIONAL
  141. IN PVOID Reserved
  142. )
  143. /*++
  144. Routine Description:
  145. This API opens the root of either the installer or the interface class
  146. registry branch, or a specified class subkey under one of these branches.
  147. If the root key is requested, it will be created if not already present
  148. (i.e., you're always guaranteed to get a handle to the root unless a
  149. registry error occurs).
  150. If a particular class subkey is requested, it will be returned if present.
  151. Otherwise, this API will return ERROR_INVALID_CLASS.
  152. Arguments:
  153. ClassGuid - Optionally, supplies a pointer to the GUID of the class whose
  154. key is to be opened. If this parameter is NULL, then the root of the
  155. class tree will be opened. This GUID is either an installer class or
  156. an interface class depending on the Flags argument.
  157. samDesired - Specifies the access you require for this key.
  158. Flags - Specifies which registry branch the key is to be opened for. May
  159. be one of the following values:
  160. DIOCR_INSTALLER - Open the class installer (Class) branch.
  161. DIOCR_INTERFACE - Open the interface class (DeviceClasses) branch.
  162. MachineName - If specified, this value indicates the remote machine where
  163. the key is to be opened.
  164. Reserved - Reserved for future use--must be NULL.
  165. Return Value:
  166. If the function succeeds, the return value is a handle to an opened
  167. registry key.
  168. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  169. extended error information, call GetLastError.
  170. Remarks:
  171. The handle returned from this API must be closed by calling RegCloseKey.
  172. --*/
  173. {
  174. HKEY hk = INVALID_HANDLE_VALUE;
  175. CONFIGRET cr;
  176. DWORD Err = NO_ERROR;
  177. HMACHINE hMachine = NULL;
  178. try {
  179. //
  180. // Make sure the user didn't pass us anything in the Reserved parameter.
  181. //
  182. if(Reserved) {
  183. Err = ERROR_INVALID_PARAMETER;
  184. leave;
  185. }
  186. //
  187. // Validate the flags (really, just an enum for now, but treated as
  188. // flags for future extensibility).
  189. //
  190. if((Flags & ~(DIOCR_INSTALLER | DIOCR_INTERFACE)) ||
  191. ((Flags != DIOCR_INSTALLER) && (Flags != DIOCR_INTERFACE))) {
  192. Err = ERROR_INVALID_FLAGS;
  193. leave;
  194. }
  195. if(MachineName) {
  196. if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
  197. //
  198. // Make sure machine handle is still invalid, so we won't
  199. // try to disconnect later.
  200. //
  201. hMachine = NULL;
  202. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  203. leave;
  204. }
  205. }
  206. if((cr = CM_Open_Class_Key_Ex((LPGUID)ClassGuid,
  207. NULL,
  208. samDesired,
  209. ClassGuid ? RegDisposition_OpenExisting
  210. : RegDisposition_OpenAlways,
  211. &hk,
  212. (Flags & DIOCR_INSTALLER) ? CM_OPEN_CLASS_KEY_INSTALLER
  213. : CM_OPEN_CLASS_KEY_INTERFACE,
  214. hMachine)) != CR_SUCCESS)
  215. {
  216. hk = INVALID_HANDLE_VALUE;
  217. if(cr == CR_NO_SUCH_REGISTRY_KEY) {
  218. Err = ERROR_INVALID_CLASS;
  219. } else {
  220. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  221. }
  222. }
  223. } except(pSetupExceptionFilter(GetExceptionCode())) {
  224. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  225. }
  226. if(hMachine) {
  227. CM_Disconnect_Machine(hMachine);
  228. }
  229. SetLastError(Err);
  230. return hk;
  231. }
  232. //
  233. // ANSI version
  234. //
  235. HKEY
  236. WINAPI
  237. SetupDiCreateDevRegKeyA(
  238. IN HDEVINFO DeviceInfoSet,
  239. IN PSP_DEVINFO_DATA DeviceInfoData,
  240. IN DWORD Scope,
  241. IN DWORD HwProfile,
  242. IN DWORD KeyType,
  243. IN HINF InfHandle, OPTIONAL
  244. IN PCSTR InfSectionName OPTIONAL
  245. )
  246. {
  247. DWORD rc;
  248. PWSTR name = NULL;
  249. HKEY h = INVALID_HANDLE_VALUE;
  250. try {
  251. if(InfSectionName) {
  252. rc = pSetupCaptureAndConvertAnsiArg(InfSectionName, &name);
  253. if(rc != NO_ERROR) {
  254. leave;
  255. }
  256. }
  257. rc = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  258. h = SetupDiCreateDevRegKeyW(DeviceInfoSet,
  259. DeviceInfoData,
  260. Scope,
  261. HwProfile,
  262. KeyType,
  263. InfHandle,
  264. name)
  265. );
  266. } except(pSetupExceptionFilter(GetExceptionCode())) {
  267. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &rc);
  268. }
  269. if(name) {
  270. MyFree(name);
  271. }
  272. SetLastError(rc);
  273. return h;
  274. }
  275. HKEY
  276. WINAPI
  277. SetupDiCreateDevRegKey(
  278. IN HDEVINFO DeviceInfoSet,
  279. IN PSP_DEVINFO_DATA DeviceInfoData,
  280. IN DWORD Scope,
  281. IN DWORD HwProfile,
  282. IN DWORD KeyType,
  283. IN HINF InfHandle, OPTIONAL
  284. IN PCTSTR InfSectionName OPTIONAL
  285. )
  286. /*++
  287. Routine Description:
  288. This routine creates a registry storage key for device-specific
  289. configuration information, and returns a handle to the key.
  290. Arguments:
  291. DeviceInfoSet - Supplies a handle to the device information set containing
  292. information about the device instance whose registry configuration
  293. storage key is to be created.
  294. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure
  295. indicating the device instance to create the registry key for.
  296. Scope - Specifies the scope of the registry key to be created. This
  297. determines where the information is actually stored--the key created
  298. may be one that is global (i.e., constant regardless of current
  299. hardware profile) or hardware profile-specific. May be one of the
  300. following values:
  301. DICS_FLAG_GLOBAL - Create a key to store global configuration
  302. information.
  303. DICS_FLAG_CONFIGSPECIFIC - Create a key to store hardware profile-
  304. specific information.
  305. HwProfile - Specifies the hardware profile to create a key for, if the
  306. Scope parameter is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter
  307. is 0, then the key for the current hardware profile should be created
  308. (i.e., in the Class branch under HKEY_CURRENT_CONFIG). If Scope is
  309. DICS_FLAG_GLOBAL, then this parameter is ignored.
  310. KeyType - Specifies the type of registry storage key to be created. May be
  311. one of the following values:
  312. DIREG_DEV - Create a hardware registry key for the device. This is the
  313. key for storage of driver-independent configuration information.
  314. (This key is in the device instance key in the Enum branch.
  315. DIREG_DRV - Create a software, or driver, registry key for the device.
  316. (This key is located in the class branch.)
  317. InfHandle - Optionally, supplies the handle of an opened INF file
  318. containing an install section to be executed for the newly-created key.
  319. If this parameter is specified, then InfSectionName must be specified
  320. as well.
  321. NOTE: INF-based installation is not supported for remoted device
  322. information sets (e.g., as created by passing a non-NULL MachineName in
  323. to SetupDiCreateDeviceInfoListEx). This routine will fail with
  324. ERROR_REMOTE_REQUEST_UNSUPPORTED in those cases.
  325. InfSectionName - Optionally, supplies the name of an install section in the
  326. INF file specified by InfHandle. This section will be executed for the
  327. newly created key. If this parameter is specified, then InfHandle must
  328. be specified as well.
  329. Return Value:
  330. If the function succeeds, the return value is a handle to a newly-created
  331. registry key where private configuration data pertaining to this device
  332. instance may be stored/retrieved. This handle will have KEY_READ and
  333. KEY_WRITE access.
  334. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  335. extended error information, call GetLastError.
  336. Remarks:
  337. The handle returned from this routine must be closed by calling
  338. RegCloseKey.
  339. If a driver key is being created (i.e., KeyType is DIREG_DRV), then the
  340. specified device instance must have been previously registered. In other
  341. words, if the device information element was created by calling
  342. SetupDiCreateDeviceInfo, then SetupDiRegisterDeviceInfo must have been
  343. subsequently called (typically, as part of DIF_REGISTERDEVICE processing).
  344. During GUI-mode setup on Windows NT, quiet-install behavior is always
  345. employed in the absence of a user-supplied file queue, regardless of
  346. whether the device information element has the DI_QUIETINSTALL flag set.
  347. --*/
  348. {
  349. HKEY hk = INVALID_HANDLE_VALUE;
  350. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  351. DWORD Err;
  352. PDEVINFO_ELEM DevInfoElem;
  353. PSP_FILE_CALLBACK MsgHandler;
  354. PVOID MsgHandlerContext;
  355. BOOL FreeMsgHandlerContext = FALSE;
  356. BOOL MsgHandlerIsNativeCharWidth;
  357. BOOL NoProgressUI;
  358. DWORD KeyDisposition;
  359. try {
  360. //
  361. // Make sure that either both InfHandle and InfSectionName are
  362. // specified, or neither are...
  363. //
  364. if(InfHandle && (InfHandle != INVALID_HANDLE_VALUE)) {
  365. if(!InfSectionName) {
  366. Err = ERROR_INVALID_PARAMETER;
  367. leave;
  368. }
  369. } else {
  370. if(InfSectionName) {
  371. Err = ERROR_INVALID_PARAMETER;
  372. leave;
  373. } else {
  374. //
  375. // Let's stick with _one_ value to indicate that the INF handle
  376. // wasn't suplied (the official one)...
  377. //
  378. InfHandle = INVALID_HANDLE_VALUE;
  379. }
  380. }
  381. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  382. Err = ERROR_INVALID_HANDLE;
  383. leave;
  384. }
  385. //
  386. // We don't support installation remotely.
  387. //
  388. if((pDeviceInfoSet->hMachine) && (InfHandle != INVALID_HANDLE_VALUE)) {
  389. Err = ERROR_REMOTE_REQUEST_UNSUPPORTED;
  390. leave;
  391. }
  392. //
  393. // Get a pointer to the element for the specified device
  394. // instance.
  395. //
  396. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  397. DeviceInfoData,
  398. NULL))) {
  399. Err = ERROR_INVALID_PARAMETER;
  400. leave;
  401. }
  402. //
  403. // First try to open the requested registry storage key, and if that
  404. // fails, then try to create it. We do this so we can keep track of
  405. // whether or not the key was newly-created (in case we need to do
  406. // clean-up later upon encountering a subsequent error).
  407. //
  408. Err = pSetupOpenOrCreateDevRegKey(pDeviceInfoSet,
  409. DevInfoElem,
  410. Scope,
  411. HwProfile,
  412. KeyType,
  413. TRUE,
  414. KEY_READ | KEY_WRITE,
  415. &hk,
  416. &KeyDisposition
  417. );
  418. if(Err != NO_ERROR) {
  419. //
  420. // Make sure hk is still invalid so we won't try to close it
  421. // later.
  422. //
  423. hk = INVALID_HANDLE_VALUE;
  424. leave;
  425. }
  426. //
  427. // We successfully created the storage key, now run an INF install
  428. // section against it (if specified).
  429. //
  430. if(InfHandle != INVALID_HANDLE_VALUE) {
  431. //
  432. // If a copy msg handler and context haven't been specified, then
  433. // use the default one.
  434. //
  435. if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
  436. MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
  437. MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
  438. MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
  439. } else {
  440. NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
  441. if(!(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
  442. DevInfoElem->InstallParamBlock.hwndParent,
  443. (NoProgressUI ? INVALID_HANDLE_VALUE
  444. : NULL),
  445. 0,
  446. 0,
  447. NULL))) {
  448. Err = ERROR_NOT_ENOUGH_MEMORY;
  449. leave;
  450. }
  451. FreeMsgHandlerContext = TRUE;
  452. MsgHandler = SetupDefaultQueueCallback;
  453. MsgHandlerIsNativeCharWidth = TRUE;
  454. }
  455. Err = GLE_FN_CALL(FALSE,
  456. _SetupInstallFromInfSection(
  457. DevInfoElem->InstallParamBlock.hwndParent,
  458. InfHandle,
  459. InfSectionName,
  460. SPINST_ALL,
  461. hk,
  462. NULL,
  463. 0,
  464. MsgHandler,
  465. MsgHandlerContext,
  466. ((KeyType == DIREG_DEV) ? DeviceInfoSet
  467. : INVALID_HANDLE_VALUE),
  468. ((KeyType == DIREG_DEV) ? DeviceInfoData
  469. : NULL),
  470. MsgHandlerIsNativeCharWidth,
  471. NULL)
  472. );
  473. }
  474. } except(pSetupExceptionFilter(GetExceptionCode())) {
  475. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  476. }
  477. if(FreeMsgHandlerContext) {
  478. SetupTermDefaultQueueCallback(MsgHandlerContext);
  479. }
  480. if(Err != NO_ERROR) {
  481. //
  482. // Close registry handle, if necessary, and delete key (if newly-
  483. // created). We do this prior to unlocking the devinfo set so that at
  484. // least no one using this HDEVINFO can get at this half-finished key.
  485. //
  486. if(hk != INVALID_HANDLE_VALUE) {
  487. RegCloseKey(hk);
  488. hk = INVALID_HANDLE_VALUE;
  489. //
  490. // If the key was newly-created, then we want to delete it.
  491. //
  492. if(KeyDisposition == REG_CREATED_NEW_KEY) {
  493. pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
  494. Scope,
  495. HwProfile,
  496. KeyType,
  497. FALSE,
  498. pDeviceInfoSet->hMachine
  499. );
  500. }
  501. }
  502. }
  503. if(pDeviceInfoSet) {
  504. UnlockDeviceInfoSet(pDeviceInfoSet);
  505. }
  506. SetLastError(Err);
  507. return hk;
  508. }
  509. HKEY
  510. WINAPI
  511. SetupDiOpenDevRegKey(
  512. IN HDEVINFO DeviceInfoSet,
  513. IN PSP_DEVINFO_DATA DeviceInfoData,
  514. IN DWORD Scope,
  515. IN DWORD HwProfile,
  516. IN DWORD KeyType,
  517. IN REGSAM samDesired
  518. )
  519. /*++
  520. Routine Description:
  521. This routine opens a registry storage key for device-specific configuration
  522. information, and returns a handle to the key.
  523. Arguments:
  524. DeviceInfoSet - Supplies a handle to the device information set containing
  525. information about the device instance whose registry configuration
  526. storage key is to be opened.
  527. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure
  528. indicating the device instance to open the registry key for.
  529. Scope - Specifies the scope of the registry key to be opened. This
  530. determines where the information is actually stored--the key opened may
  531. be one that is global (i.e., constant regardless of current hardware
  532. profile) or hardware profile-specific. May be one of the following
  533. values:
  534. DICS_FLAG_GLOBAL - Open a key to store global configuration
  535. information.
  536. DICS_FLAG_CONFIGSPECIFIC - Open a key to store hardware profile-
  537. specific information.
  538. HwProfile - Specifies the hardware profile to open a key for, if the Scope
  539. parameter is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter is 0,
  540. then the key for the current hardware profile should be opened (e.g.,
  541. in the Enum or Class branch under HKEY_CURRENT_CONFIG). If Scope is
  542. SPDICS_FLAG_GLOBAL, then this parameter is ignored.
  543. KeyType - Specifies the type of registry storage key to be opened. May be
  544. one of the following values:
  545. DIREG_DEV - Open a hardware registry key for the device. This is the
  546. key for storage of driver-independent configuration information.
  547. (This key is in the device instance key in the Enum branch.
  548. DIREG_DRV - Open a software (i.e., driver) registry key for the device.
  549. (This key is located in the class branch.)
  550. samDesired - Specifies the access you require for this key.
  551. Return Value:
  552. If the function succeeds, the return value is a handle to an opened
  553. registry key where private configuration data pertaining to this device
  554. instance may be stored/retrieved.
  555. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  556. extended error information, call GetLastError.
  557. Remarks:
  558. The handle returned from this routine must be closed by calling
  559. RegCloseKey.
  560. If a driver key is being opened (i.e., KeyType is DIREG_DRV), then the
  561. specified device instance must have been previously registered. In other
  562. words, if the device information element was created by calling
  563. SetupDiCreateDeviceInfo, then SetupDiRegisterDeviceInfo must have been
  564. subsequently called (typically, as part of DIF_REGISTERDEVICE processing).
  565. --*/
  566. {
  567. HKEY hk = INVALID_HANDLE_VALUE;
  568. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  569. DWORD Err;
  570. PDEVINFO_ELEM DevInfoElem;
  571. try {
  572. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  573. Err = ERROR_INVALID_HANDLE;
  574. leave;
  575. }
  576. //
  577. // Get a pointer to the element for the specified device
  578. // instance.
  579. //
  580. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  581. DeviceInfoData,
  582. NULL)) {
  583. //
  584. // Open the requested registry storage key.
  585. //
  586. Err = pSetupOpenOrCreateDevRegKey(pDeviceInfoSet,
  587. DevInfoElem,
  588. Scope,
  589. HwProfile,
  590. KeyType,
  591. FALSE,
  592. samDesired,
  593. &hk,
  594. NULL
  595. );
  596. if(Err != NO_ERROR) {
  597. //
  598. // Make sure hk is still invalid so we won't try to close it
  599. // later.
  600. //
  601. hk = INVALID_HANDLE_VALUE;
  602. }
  603. } else {
  604. Err = ERROR_INVALID_PARAMETER;
  605. }
  606. } except(pSetupExceptionFilter(GetExceptionCode())) {
  607. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  608. }
  609. if(pDeviceInfoSet) {
  610. UnlockDeviceInfoSet(pDeviceInfoSet);
  611. }
  612. SetLastError(Err);
  613. return hk;
  614. }
  615. DWORD
  616. pSetupOpenOrCreateDevRegKey(
  617. IN PDEVICE_INFO_SET pDeviceInfoSet,
  618. IN PDEVINFO_ELEM DevInfoElem,
  619. IN DWORD Scope,
  620. IN DWORD HwProfile,
  621. IN DWORD KeyType,
  622. IN BOOL Create,
  623. IN REGSAM samDesired,
  624. OUT PHKEY hDevRegKey,
  625. OUT PDWORD KeyDisposition
  626. )
  627. /*++
  628. Routine Description:
  629. This routine creates or opens a registry storage key for the specified
  630. device information element, and returns a handle to the opened key.
  631. Arguments:
  632. DeviceInfoSet - Supplies a pointer to the device information set containing
  633. the element for which a registry storage key is to be created/opened.
  634. DevInfoElem - Supplies a pointer to the device information element for
  635. which a registry storage key is to be created/opened.
  636. Scope - Specifies the scope of the registry key to be created/opened. This
  637. determines where the information is actually stored--the key created
  638. may be one that is global (i.e., constant regardless of current
  639. hardware profile) or hardware profile-specific. May be one of the
  640. following values:
  641. DICS_FLAG_GLOBAL - Create/open a key to store global configuration
  642. information.
  643. DICS_FLAG_CONFIGSPECIFIC - Create/open a key to store hardware profile-
  644. specific information.
  645. HwProfile - Specifies the hardware profile to create/open a key for, if the
  646. Scope parameter is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter
  647. is 0, then the key for the current hardware profile should be created/
  648. opened (i.e., in the Class branch under HKEY_CURRENT_CONFIG). If Scope
  649. is SPDICS_FLAG_GLOBAL, then this parameter is ignored.
  650. KeyType - Specifies the type of registry storage key to be created/opened.
  651. May be one of the following values:
  652. DIREG_DEV - Create/open a hardware registry key for the device. This
  653. is the key for storage of driver-independent configuration
  654. information. (This key is in the device instance key in the Enum
  655. branch.
  656. DIREG_DRV - Create/open a software, or driver, registry key for the
  657. device. (This key is located in the class branch.)
  658. Create - Specifies whether the key should be created if doesn't already
  659. exist.
  660. samDesired - Specifies the access you require for this key.
  661. hDevRegKey - Supplies the address of a variable that receives a handle to
  662. the requested registry key. (This variable will only be written to if
  663. the handle is successfully opened.)
  664. KeyDisposition - Optionally, supplies the address of a variable that
  665. receives the status of the returned key handle. Can be either:
  666. REG_CREATED_NEW_KEY - The key did not exist and was created.
  667. REG_OPENED_EXISTING_KEY - The key existed and was simply opened without
  668. being changed. (This will always be the case
  669. if the Create parameter is FALSE.)
  670. Return Value:
  671. If the function is successful, the return value is NO_ERROR, otherwise, it
  672. is the ERROR_* code indicating the error that occurred.
  673. Remarks:
  674. If a software key is requested (DIREG_DRV), and there isn't already a
  675. 'Driver' value entry, then one will be created. This entry is of the form:
  676. <ClassGUID>\<instance>
  677. where <instance> is a base-10, 4-digit number that is unique within that
  678. class.
  679. --*/
  680. {
  681. ULONG RegistryBranch;
  682. CONFIGRET cr;
  683. DWORD Err = NO_ERROR;
  684. DWORD Disposition = REG_OPENED_EXISTING_KEY;
  685. HKEY hk, hkClass;
  686. TCHAR DriverKey[GUID_STRING_LEN + 5]; // Eg, {4d36e978-e325-11ce-bfc1-08002be10318}\0000
  687. size_t DriverKeyLength;
  688. BOOL GetKeyDisposition = (KeyDisposition ? TRUE : FALSE);
  689. //
  690. // Under Win95, the class key uses the class name instead of its GUID. The
  691. // maximum length of a class name is less than the length of a GUID string,
  692. // but put a check here just to make sure that this assumption remains
  693. // valid.
  694. //
  695. #if MAX_CLASS_NAME_LEN > MAX_GUID_STRING_LEN
  696. #error MAX_CLASS_NAME_LEN is larger than MAX_GUID_STRING_LEN--fix DriverKey!
  697. #endif
  698. //
  699. // Figure out what flags to pass to CM_Open_DevInst_Key
  700. //
  701. switch(KeyType) {
  702. case DIREG_DEV :
  703. RegistryBranch = CM_REGISTRY_HARDWARE;
  704. break;
  705. case DIREG_DRV :
  706. //
  707. // This key may only be opened if the device instance has been
  708. // registered.
  709. //
  710. if(!(DevInfoElem->DiElemFlags & DIE_IS_REGISTERED)) {
  711. return ERROR_DEVINFO_NOT_REGISTERED;
  712. }
  713. //
  714. // Retrieve the 'Driver' registry property which indicates where
  715. // the storage key is located in the class branch.
  716. //
  717. DriverKeyLength = sizeof(DriverKey);
  718. if((cr = CM_Get_DevInst_Registry_Property_Ex(
  719. DevInfoElem->DevInst,
  720. CM_DRP_DRIVER,
  721. NULL,
  722. DriverKey,
  723. (PULONG)&DriverKeyLength,
  724. 0,
  725. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  726. if(cr != CR_NO_SUCH_VALUE) {
  727. return MapCrToSpError(cr, ERROR_INVALID_DATA);
  728. } else if(!Create) {
  729. return ERROR_KEY_DOES_NOT_EXIST;
  730. }
  731. //
  732. // The Driver entry doesn't exist, and we should create it.
  733. //
  734. hk = INVALID_HANDLE_VALUE;
  735. if(CR_SUCCESS != CM_Open_Class_Key_Ex(
  736. NULL,
  737. NULL,
  738. KEY_READ | KEY_WRITE,
  739. RegDisposition_OpenAlways,
  740. &hkClass,
  741. 0,
  742. pDeviceInfoSet->hMachine)) {
  743. //
  744. // This shouldn't fail.
  745. //
  746. return ERROR_INVALID_DATA;
  747. }
  748. try {
  749. //
  750. // Find a unique key name under this class key.
  751. //
  752. // FUTURE-2002/04/3D-lonnym -- UmPnPMgr should be responsible for generating driver keys
  753. // Presently, there are places in cfgmgr32 and in umpnpmgr
  754. // (as well as here) where a new driver key is assigned.
  755. // This should all be centralized in one place.
  756. //
  757. DriverKeyLength = SIZECHARS(DriverKey);
  758. if(CR_SUCCESS != CM_Get_Class_Key_Name_Ex(
  759. &(DevInfoElem->ClassGuid),
  760. DriverKey,
  761. (PULONG)&DriverKeyLength,
  762. 0,
  763. pDeviceInfoSet->hMachine)) {
  764. Err = ERROR_INVALID_CLASS;
  765. leave;
  766. }
  767. //
  768. // Get actual length of string (not including terminating
  769. // NULL)...
  770. //
  771. if(!MYVERIFY(SUCCEEDED(StringCchLength(DriverKey,
  772. SIZECHARS(DriverKey),
  773. &DriverKeyLength
  774. )))) {
  775. //
  776. // CM API gave us garbage!!!
  777. //
  778. Err = ERROR_INVALID_DATA;
  779. leave;
  780. }
  781. Err = ERROR_FILE_NOT_FOUND;
  782. while(pSetupFindUniqueKey(hkClass,
  783. DriverKey,
  784. SIZECHARS(DriverKey))) {
  785. Err = RegCreateKeyEx(hkClass,
  786. DriverKey,
  787. 0,
  788. NULL,
  789. REG_OPTION_NON_VOLATILE,
  790. KEY_READ | KEY_WRITE,
  791. NULL,
  792. &hk,
  793. &Disposition
  794. );
  795. if(Err == ERROR_SUCCESS) {
  796. //
  797. // Everything's great, unless the Disposition
  798. // indicates that the key already existed. That
  799. // means that someone else claimed the key before
  800. // we got a chance to. In that case, we close this
  801. // key, and try again.
  802. //
  803. if(Disposition == REG_OPENED_EXISTING_KEY) {
  804. RegCloseKey(hk);
  805. hk = INVALID_HANDLE_VALUE;
  806. //
  807. // Truncate off the class instance part, to be
  808. // replaced with a new instance number the next
  809. // go-around.
  810. //
  811. DriverKey[DriverKeyLength] = TEXT('\0');
  812. } else {
  813. break;
  814. }
  815. } else {
  816. hk = INVALID_HANDLE_VALUE;
  817. break;
  818. }
  819. Err = ERROR_FILE_NOT_FOUND;
  820. }
  821. if(Err != NO_ERROR) {
  822. leave;
  823. }
  824. //
  825. // Set the device instance's 'Driver' registry property to
  826. // reflect the new software registry storage location.
  827. //
  828. if(!MYVERIFY(SUCCEEDED(StringCchLength(DriverKey,
  829. SIZECHARS(DriverKey),
  830. &DriverKeyLength
  831. )))) {
  832. //
  833. // this should never fail!
  834. //
  835. Err = ERROR_INVALID_DATA;
  836. leave;
  837. }
  838. cr = CM_Set_DevInst_Registry_Property_Ex(
  839. DevInfoElem->DevInst,
  840. CM_DRP_DRIVER,
  841. DriverKey,
  842. (DriverKeyLength + 1) * sizeof(TCHAR),
  843. 0,
  844. pDeviceInfoSet->hMachine
  845. );
  846. if(cr != CR_SUCCESS) {
  847. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  848. leave;
  849. }
  850. //
  851. // If the caller requested that we return the key's
  852. // disposition, and they're creating the global driver key,
  853. // then we need to set the disposition now. Otherwise, we
  854. // would always report the key as REG_OPENED_EXISTING_KEY,
  855. // since we just got through creating it up above.
  856. //
  857. if(GetKeyDisposition && (Scope == DICS_FLAG_GLOBAL)) {
  858. *KeyDisposition = REG_CREATED_NEW_KEY;
  859. GetKeyDisposition = FALSE;
  860. }
  861. //
  862. // At this point, we successfully created a new driver key,
  863. // and we stored the key's name in the Driver devnode
  864. // property. Close our key handle and set it back to
  865. // INVALID_HANDLE_VALUE so we'll know not to try to delete
  866. // the key below.
  867. //
  868. RegCloseKey(hk);
  869. hk = INVALID_HANDLE_VALUE;
  870. } except(pSetupExceptionFilter(GetExceptionCode())) {
  871. pSetupExceptionHandler(GetExceptionCode(),
  872. ERROR_INVALID_PARAMETER,
  873. &Err
  874. );
  875. }
  876. if(hk != INVALID_HANDLE_VALUE) {
  877. MYASSERT(Err != NO_ERROR);
  878. RegCloseKey(hk);
  879. //
  880. // Additionally, if the disposition indicates that the key
  881. // was newly-created, then we need to delete it, because
  882. // something failed subsequent to this key's creation, and
  883. // we need to clean up.
  884. //
  885. if(Disposition == REG_CREATED_NEW_KEY) {
  886. RegDeleteKey(hkClass, DriverKey);
  887. }
  888. }
  889. RegCloseKey(hkClass);
  890. if(Err != NO_ERROR) {
  891. return Err;
  892. }
  893. }
  894. RegistryBranch = CM_REGISTRY_SOFTWARE;
  895. break;
  896. default :
  897. return ERROR_INVALID_FLAGS;
  898. }
  899. if(Scope == DICS_FLAG_CONFIGSPECIFIC) {
  900. RegistryBranch |= CM_REGISTRY_CONFIG;
  901. } else if(Scope != DICS_FLAG_GLOBAL) {
  902. return ERROR_INVALID_FLAGS;
  903. }
  904. //
  905. // If we're creating the key, and we need to track whether this key is
  906. // getting created, then we may have to make two calls to
  907. // CM_Open_DevInst_Key_Ex (the first attempting to open an existing key,
  908. // and the second to create it if it didn't exist).
  909. //
  910. if(Create && GetKeyDisposition) {
  911. cr = CM_Open_DevInst_Key_Ex(DevInfoElem->DevInst,
  912. samDesired,
  913. HwProfile,
  914. RegDisposition_OpenExisting,
  915. &hk,
  916. RegistryBranch,
  917. pDeviceInfoSet->hMachine
  918. );
  919. if(cr == CR_SUCCESS) {
  920. //
  921. // The key was already in existence.
  922. //
  923. *KeyDisposition = REG_OPENED_EXISTING_KEY;
  924. goto exit;
  925. }
  926. }
  927. cr = CM_Open_DevInst_Key_Ex(DevInfoElem->DevInst,
  928. samDesired,
  929. HwProfile,
  930. (Create ? RegDisposition_OpenAlways
  931. : RegDisposition_OpenExisting),
  932. &hk,
  933. RegistryBranch,
  934. pDeviceInfoSet->hMachine
  935. );
  936. if((cr == CR_SUCCESS) && GetKeyDisposition) {
  937. *KeyDisposition = Create ? REG_CREATED_NEW_KEY
  938. : REG_OPENED_EXISTING_KEY;
  939. }
  940. exit:
  941. if(cr == CR_SUCCESS) {
  942. *hDevRegKey = hk;
  943. Err = NO_ERROR;
  944. } else {
  945. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  946. }
  947. return Err;
  948. }
  949. DWORD
  950. _SetupDiGetDeviceRegistryProperty(
  951. IN HDEVINFO DeviceInfoSet,
  952. IN PSP_DEVINFO_DATA DeviceInfoData,
  953. IN DWORD Property,
  954. OUT PDWORD PropertyRegDataType, OPTIONAL
  955. OUT PBYTE PropertyBuffer,
  956. IN DWORD PropertyBufferSize,
  957. OUT PDWORD RequiredSize, OPTIONAL
  958. IN BOOL Ansi
  959. )
  960. {
  961. PDEVICE_INFO_SET pDeviceInfoSet;
  962. DWORD Err;
  963. PDEVINFO_ELEM DevInfoElem;
  964. CONFIGRET cr;
  965. ULONG CmRegProperty, PropLength;
  966. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  967. return ERROR_INVALID_HANDLE;
  968. }
  969. Err = NO_ERROR;
  970. try {
  971. //
  972. // Get a pointer to the element for the specified device instance.
  973. //
  974. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  975. DeviceInfoData,
  976. NULL))) {
  977. Err = ERROR_INVALID_PARAMETER;
  978. leave;
  979. }
  980. if(Property < SPDRP_MAXIMUM_PROPERTY) {
  981. CmRegProperty = (ULONG)SPDRP_TO_CMDRP(Property);
  982. } else {
  983. Err = ERROR_INVALID_REG_PROPERTY;
  984. leave;
  985. }
  986. PropLength = PropertyBufferSize;
  987. if(Ansi) {
  988. cr = CM_Get_DevInst_Registry_Property_ExA(DevInfoElem->DevInst,
  989. CmRegProperty,
  990. PropertyRegDataType,
  991. PropertyBuffer,
  992. &PropLength,
  993. 0,
  994. pDeviceInfoSet->hMachine
  995. );
  996. } else {
  997. cr = CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  998. CmRegProperty,
  999. PropertyRegDataType,
  1000. PropertyBuffer,
  1001. &PropLength,
  1002. 0,
  1003. pDeviceInfoSet->hMachine
  1004. );
  1005. }
  1006. if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
  1007. if(RequiredSize) {
  1008. *RequiredSize = PropLength;
  1009. }
  1010. }
  1011. if(cr != CR_SUCCESS) {
  1012. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1013. }
  1014. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1015. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1016. }
  1017. UnlockDeviceInfoSet(pDeviceInfoSet);
  1018. return Err;
  1019. }
  1020. //
  1021. // ANSI version
  1022. //
  1023. BOOL
  1024. WINAPI
  1025. SetupDiGetDeviceRegistryPropertyA(
  1026. IN HDEVINFO DeviceInfoSet,
  1027. IN PSP_DEVINFO_DATA DeviceInfoData,
  1028. IN DWORD Property,
  1029. OUT PDWORD PropertyRegDataType, OPTIONAL
  1030. OUT PBYTE PropertyBuffer,
  1031. IN DWORD PropertyBufferSize,
  1032. OUT PDWORD RequiredSize OPTIONAL
  1033. )
  1034. {
  1035. DWORD Err;
  1036. try {
  1037. Err = _SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1038. DeviceInfoData,
  1039. Property,
  1040. PropertyRegDataType,
  1041. PropertyBuffer,
  1042. PropertyBufferSize,
  1043. RequiredSize,
  1044. TRUE
  1045. );
  1046. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1047. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1048. }
  1049. SetLastError(Err);
  1050. return (Err == NO_ERROR);
  1051. }
  1052. BOOL
  1053. WINAPI
  1054. SetupDiGetDeviceRegistryProperty(
  1055. IN HDEVINFO DeviceInfoSet,
  1056. IN PSP_DEVINFO_DATA DeviceInfoData,
  1057. IN DWORD Property,
  1058. OUT PDWORD PropertyRegDataType, OPTIONAL
  1059. OUT PBYTE PropertyBuffer,
  1060. IN DWORD PropertyBufferSize,
  1061. OUT PDWORD RequiredSize OPTIONAL
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine retrieves the specified property from the Plug & Play device
  1066. storage location in the registry.
  1067. Arguments:
  1068. DeviceInfoSet - Supplies a handle to the device information set containing
  1069. information about the device instance to retrieve a Plug & Play registry
  1070. property for.
  1071. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
  1072. the device instance to retrieve the Plug & Play registry property for.
  1073. Property - Supplies an ordinal specifying the property to be retrieved. Refer
  1074. to sdk\inc\setupapi.h for a complete list of properties that may be retrieved.
  1075. PropertyRegDataType - Optionally, supplies the address of a variable that
  1076. will receive the data type of the property being retrieved. This will
  1077. be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
  1078. PropertyBuffer - Supplies the address of a buffer that receives the property
  1079. data.
  1080. PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer.
  1081. RequiredSize - Optionally, supplies the address of a variable that receives
  1082. the number of bytes required to store the requested property in the buffer.
  1083. Return Value:
  1084. If the function succeeds, the return value is TRUE.
  1085. If the function fails, the return value is FALSE. To get extended error
  1086. information, call GetLastError. If the supplied buffer was not large enough
  1087. to hold the requested property, the error will be ERROR_INSUFFICIENT_BUFFER,
  1088. and RequiredSize will specify how large the buffer needs to be.
  1089. --*/
  1090. {
  1091. DWORD Err;
  1092. try {
  1093. Err = _SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1094. DeviceInfoData,
  1095. Property,
  1096. PropertyRegDataType,
  1097. PropertyBuffer,
  1098. PropertyBufferSize,
  1099. RequiredSize,
  1100. FALSE
  1101. );
  1102. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1103. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1104. }
  1105. SetLastError(Err);
  1106. return (Err == NO_ERROR);
  1107. }
  1108. DWORD
  1109. _SetupDiSetDeviceRegistryProperty(
  1110. IN HDEVINFO DeviceInfoSet,
  1111. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  1112. IN DWORD Property,
  1113. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1114. IN DWORD PropertyBufferSize,
  1115. IN BOOL Ansi
  1116. )
  1117. {
  1118. PDEVICE_INFO_SET pDeviceInfoSet;
  1119. DWORD Err;
  1120. PDEVINFO_ELEM DevInfoElem;
  1121. CONFIGRET cr;
  1122. ULONG CmRegProperty;
  1123. GUID ClassGuid;
  1124. BOOL ClassGuidSpecified;
  1125. TCHAR ClassName[MAX_CLASS_NAME_LEN];
  1126. DWORD ClassNameLength;
  1127. PCWSTR UnicodeGuidString = NULL;
  1128. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  1129. return ERROR_INVALID_HANDLE;
  1130. }
  1131. Err = NO_ERROR;
  1132. try {
  1133. //
  1134. // Get a pointer to the element for the specified device
  1135. // instance.
  1136. //
  1137. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  1138. DeviceInfoData,
  1139. NULL))) {
  1140. Err = ERROR_INVALID_PARAMETER;
  1141. leave;
  1142. }
  1143. //
  1144. // Make sure the property code is in-range, and is not SPDRP_CLASS
  1145. // (the Class property is not settable directly, and is automatically
  1146. // updated when the ClassGUID property changes).
  1147. //
  1148. // FUTURE-2002/04/30-lonnym -- Should disallow setting Class property via CM APIs as well
  1149. // Now that cfgmgr32 is part of setupapi.dll, we could use an internal
  1150. // interface to set the Class property, yet not expose this to callers
  1151. // (thus helping to ensure consistency between the Class and ClassGUID
  1152. // property values).
  1153. //
  1154. if((Property < SPDRP_MAXIMUM_PROPERTY) && (Property != SPDRP_CLASS)) {
  1155. CmRegProperty = (ULONG)SPDRP_TO_CMDRP(Property);
  1156. } else {
  1157. Err = ERROR_INVALID_REG_PROPERTY;
  1158. leave;
  1159. }
  1160. //
  1161. // If the property we're setting is ClassGUID, then we need to check to
  1162. // see whether the new GUID is different from the current one. If there's
  1163. // no change, then we're done.
  1164. //
  1165. if(CmRegProperty == CM_DRP_CLASSGUID) {
  1166. if(!PropertyBuffer) {
  1167. //
  1168. // Then the intent is to reset the device's class GUID. Make
  1169. // sure they passed us a buffer length of zero.
  1170. //
  1171. if(PropertyBufferSize) {
  1172. Err = ERROR_INVALID_PARAMETER;
  1173. leave;
  1174. }
  1175. ClassGuidSpecified = FALSE;
  1176. } else {
  1177. //
  1178. // If we're being called from the ANSI API then we need
  1179. // to convert the ANSI string representation of the GUID
  1180. // to Unicode before we convert the string to an actual GUID.
  1181. //
  1182. if(Ansi) {
  1183. Err = pSetupCaptureAndConvertAnsiArg((PCSTR)PropertyBuffer,
  1184. &UnicodeGuidString
  1185. );
  1186. if(Err == NO_ERROR) {
  1187. Err = pSetupGuidFromString(UnicodeGuidString,
  1188. &ClassGuid
  1189. );
  1190. }
  1191. } else {
  1192. Err = pSetupGuidFromString((PCWSTR)PropertyBuffer,
  1193. &ClassGuid
  1194. );
  1195. }
  1196. if(Err != NO_ERROR) {
  1197. leave;
  1198. }
  1199. ClassGuidSpecified = TRUE;
  1200. }
  1201. if(IsEqualGUID(&(DevInfoElem->ClassGuid),
  1202. (ClassGuidSpecified ? &ClassGuid
  1203. : &GUID_NULL))) {
  1204. //
  1205. // No change--nothing to do.
  1206. //
  1207. leave;
  1208. }
  1209. //
  1210. // We're changing the class of this device. First, make sure that
  1211. // the set containing this device doesn't have an associated class
  1212. // (otherwise, we'll suddenly have a device whose class doesn't
  1213. // match the set's class).
  1214. //
  1215. // Also, make sure this isn't a remoted HDEVINFO set. Any existing
  1216. // class installers or co-installers should be in the loop on a
  1217. // change in class, in case they need to clean-up any persistent
  1218. // resource reservations they've made (e.g., releasing a COM port's
  1219. // DosDevices name back to the COM port name arbiter free pool).
  1220. // Since we can't invoke class-/co-installers remotely, we must
  1221. // disallow this class GUID change.
  1222. //
  1223. if(pDeviceInfoSet->HasClassGuid) {
  1224. Err = ERROR_CLASS_MISMATCH;
  1225. } else if(pDeviceInfoSet->hMachine) {
  1226. Err = ERROR_REMOTE_REQUEST_UNSUPPORTED;
  1227. } else {
  1228. Err = InvalidateHelperModules(DeviceInfoSet, DeviceInfoData, 0);
  1229. }
  1230. if(Err != NO_ERROR) {
  1231. leave;
  1232. }
  1233. //
  1234. // Everything seems to be in order. Before going any further, we
  1235. // need to delete any software keys associated with this device, so
  1236. // we don't leave orphans in the registry when we change the
  1237. // device's class.
  1238. //
  1239. // NTRAID#NTBUG9-614056-2002/05/02-lonnym -- Class-/co-installers need notification of class change
  1240. //
  1241. pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
  1242. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
  1243. (DWORD)-1,
  1244. DIREG_DRV,
  1245. TRUE,
  1246. pDeviceInfoSet->hMachine // must be NULL
  1247. );
  1248. }
  1249. if(Ansi) {
  1250. cr = CM_Set_DevInst_Registry_Property_ExA(DevInfoElem->DevInst,
  1251. CmRegProperty,
  1252. (PVOID)PropertyBuffer,
  1253. PropertyBufferSize,
  1254. 0,
  1255. pDeviceInfoSet->hMachine
  1256. );
  1257. } else {
  1258. cr = CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1259. CmRegProperty,
  1260. (PVOID)PropertyBuffer,
  1261. PropertyBufferSize,
  1262. 0,
  1263. pDeviceInfoSet->hMachine
  1264. );
  1265. }
  1266. if(cr == CR_SUCCESS) {
  1267. //
  1268. // If we were setting the device's ClassGUID property, then we need
  1269. // to update its Class name property as well.
  1270. //
  1271. if(CmRegProperty == CM_DRP_CLASSGUID) {
  1272. if(ClassGuidSpecified) {
  1273. if(!SetupDiClassNameFromGuid(&ClassGuid,
  1274. ClassName,
  1275. SIZECHARS(ClassName),
  1276. &ClassNameLength)) {
  1277. //
  1278. // We couldn't retrieve the corresponding class name.
  1279. // Set ClassNameLength to zero so that we reset class
  1280. // name below.
  1281. //
  1282. ClassNameLength = 0;
  1283. }
  1284. } else {
  1285. //
  1286. // Resetting ClassGUID--we want to reset class name also.
  1287. //
  1288. ClassNameLength = 0;
  1289. }
  1290. CM_Set_DevInst_Registry_Property_Ex(
  1291. DevInfoElem->DevInst,
  1292. CM_DRP_CLASS,
  1293. ClassNameLength ? (PVOID)ClassName : NULL,
  1294. ClassNameLength * sizeof(TCHAR),
  1295. 0,
  1296. pDeviceInfoSet->hMachine
  1297. );
  1298. //
  1299. // Finally, update the device's class GUID, and also update the
  1300. // caller-supplied SP_DEVINFO_DATA structure to reflect the device's
  1301. // new class.
  1302. //
  1303. CopyMemory(&(DevInfoElem->ClassGuid),
  1304. (ClassGuidSpecified ? &ClassGuid : &GUID_NULL),
  1305. sizeof(GUID)
  1306. );
  1307. CopyMemory(&(DeviceInfoData->ClassGuid),
  1308. (ClassGuidSpecified ? &ClassGuid : &GUID_NULL),
  1309. sizeof(GUID)
  1310. );
  1311. }
  1312. } else {
  1313. //
  1314. // For backward compatibility reasons, map CR_INVALID_DATA to
  1315. // ERROR_INVALID_PARAMETER. For everything else, use our generic
  1316. // CR mapping routine...
  1317. //
  1318. if(cr == CR_INVALID_DATA) {
  1319. Err = ERROR_INVALID_PARAMETER;
  1320. } else {
  1321. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1322. }
  1323. }
  1324. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1325. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1326. }
  1327. if(UnicodeGuidString) {
  1328. MyFree(UnicodeGuidString);
  1329. }
  1330. UnlockDeviceInfoSet(pDeviceInfoSet);
  1331. return Err;
  1332. }
  1333. //
  1334. // ANSI version
  1335. //
  1336. BOOL
  1337. WINAPI
  1338. SetupDiSetDeviceRegistryPropertyA(
  1339. IN HDEVINFO DeviceInfoSet,
  1340. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  1341. IN DWORD Property,
  1342. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1343. IN DWORD PropertyBufferSize
  1344. )
  1345. {
  1346. DWORD Err;
  1347. try {
  1348. Err = _SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1349. DeviceInfoData,
  1350. Property,
  1351. PropertyBuffer,
  1352. PropertyBufferSize,
  1353. TRUE
  1354. );
  1355. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1356. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1357. }
  1358. SetLastError(Err);
  1359. return (Err == NO_ERROR);
  1360. }
  1361. BOOL
  1362. WINAPI
  1363. SetupDiSetDeviceRegistryProperty(
  1364. IN HDEVINFO DeviceInfoSet,
  1365. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  1366. IN DWORD Property,
  1367. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1368. IN DWORD PropertyBufferSize
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. This routine sets the specified Plug & Play device registry property.
  1373. Arguments:
  1374. DeviceInfoSet - Supplies a handle to the device information set containing
  1375. information about the device instance to set a Plug & Play registry
  1376. property for.
  1377. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
  1378. the device instance to set the Plug & Play registry property for. If the
  1379. ClassGUID property is being set, then this structure will be updated upon
  1380. return to reflect the device's new class.
  1381. Property - Supplies an ordinal specifying the property to be set. Refer to
  1382. sdk\inc\setupapi.h for a complete listing of values that may be set
  1383. (these values are denoted with 'R/W' in their descriptive comment).
  1384. PropertyBuffer - Supplies the address of a buffer containing the new data
  1385. for the property. If the property is being cleared, then this pointer
  1386. should be NULL, and PropertyBufferSize must be zero.
  1387. PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer. If
  1388. PropertyBuffer isn't specified (i.e., the property is to be cleared),
  1389. then this value must be zero.
  1390. Return Value:
  1391. If the function succeeds, the return value is TRUE.
  1392. If the function fails, the return value is FALSE. To get extended error
  1393. information, call GetLastError.
  1394. Remarks:
  1395. Note that the Class property cannot be set. This is because it is based on
  1396. the corresponding ClassGUID, and is automatically updated when that property
  1397. changes.
  1398. Also, note that when the ClassGUID property changes, this routine automatically
  1399. cleans up any software keys associated with the device. Otherwise, we would
  1400. be left with orphaned registry keys.
  1401. --*/
  1402. {
  1403. DWORD Err;
  1404. try {
  1405. Err = _SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1406. DeviceInfoData,
  1407. Property,
  1408. PropertyBuffer,
  1409. PropertyBufferSize,
  1410. FALSE
  1411. );
  1412. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1413. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1414. }
  1415. SetLastError(Err);
  1416. return (Err == NO_ERROR);
  1417. }
  1418. DWORD
  1419. _SetupDiGetClassRegistryProperty(
  1420. IN CONST GUID *ClassGuid,
  1421. IN DWORD Property,
  1422. OUT PDWORD PropertyRegDataType, OPTIONAL
  1423. OUT PBYTE PropertyBuffer,
  1424. IN DWORD PropertyBufferSize,
  1425. OUT PDWORD RequiredSize, OPTIONAL
  1426. IN PCTSTR MachineName, OPTIONAL
  1427. IN BOOL Ansi
  1428. )
  1429. /*++
  1430. See SetupDiGetClassRegistryProperty
  1431. --*/
  1432. {
  1433. DWORD Err;
  1434. CONFIGRET cr;
  1435. ULONG CmRegProperty, PropLength;
  1436. HMACHINE hMachine = NULL;
  1437. Err = NO_ERROR;
  1438. try {
  1439. //
  1440. // if we want to set register for another machine, find that machine
  1441. //
  1442. if(MachineName) {
  1443. if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
  1444. //
  1445. // Make sure machine handle is still invalid, so we won't
  1446. // try to disconnect later.
  1447. //
  1448. hMachine = NULL;
  1449. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1450. leave;
  1451. }
  1452. }
  1453. if(Property < SPCRP_MAXIMUM_PROPERTY) {
  1454. CmRegProperty = (ULONG)SPCRP_TO_CMCRP(Property);
  1455. } else {
  1456. Err = ERROR_INVALID_REG_PROPERTY;
  1457. leave;
  1458. }
  1459. PropLength = PropertyBufferSize;
  1460. if(Ansi) {
  1461. cr = CM_Get_Class_Registry_PropertyA(
  1462. (LPGUID)ClassGuid,
  1463. CmRegProperty,
  1464. PropertyRegDataType,
  1465. PropertyBuffer,
  1466. &PropLength,
  1467. 0,
  1468. hMachine);
  1469. } else {
  1470. cr = CM_Get_Class_Registry_PropertyW(
  1471. (LPGUID)ClassGuid,
  1472. CmRegProperty,
  1473. PropertyRegDataType,
  1474. PropertyBuffer,
  1475. &PropLength,
  1476. 0,
  1477. hMachine);
  1478. }
  1479. if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
  1480. if(RequiredSize) {
  1481. *RequiredSize = PropLength;
  1482. }
  1483. }
  1484. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1485. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1486. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1487. }
  1488. if (hMachine != NULL) {
  1489. CM_Disconnect_Machine(hMachine);
  1490. }
  1491. return Err;
  1492. }
  1493. //
  1494. // ANSI version
  1495. //
  1496. WINSETUPAPI
  1497. BOOL
  1498. WINAPI
  1499. SetupDiGetClassRegistryPropertyA(
  1500. IN CONST GUID *ClassGuid,
  1501. IN DWORD Property,
  1502. OUT PDWORD PropertyRegDataType, OPTIONAL
  1503. OUT PBYTE PropertyBuffer,
  1504. IN DWORD PropertyBufferSize,
  1505. OUT PDWORD RequiredSize, OPTIONAL
  1506. IN PCSTR MachineName, OPTIONAL
  1507. IN PVOID Reserved
  1508. )
  1509. /*++
  1510. See SetupDiGetClassRegistryProperty
  1511. --*/
  1512. {
  1513. PCWSTR MachineString = NULL;
  1514. DWORD Err = NO_ERROR;
  1515. try {
  1516. if(Reserved != NULL) {
  1517. //
  1518. // make sure caller doesn't pass a value here
  1519. // so we know we can use this at a later date
  1520. //
  1521. Err = ERROR_INVALID_PARAMETER;
  1522. leave;
  1523. }
  1524. //
  1525. // convert machine-name to local
  1526. //
  1527. if(MachineName != NULL) {
  1528. Err = pSetupCaptureAndConvertAnsiArg(MachineName,
  1529. &MachineString
  1530. );
  1531. if(Err != NO_ERROR) {
  1532. leave;
  1533. }
  1534. }
  1535. Err = _SetupDiGetClassRegistryProperty(ClassGuid,
  1536. Property,
  1537. PropertyRegDataType,
  1538. PropertyBuffer,
  1539. PropertyBufferSize,
  1540. RequiredSize,
  1541. MachineString,
  1542. TRUE
  1543. );
  1544. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1545. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1546. }
  1547. if(MachineString) {
  1548. MyFree(MachineString);
  1549. }
  1550. SetLastError(Err);
  1551. return (Err == NO_ERROR);
  1552. }
  1553. WINSETUPAPI
  1554. BOOL
  1555. WINAPI
  1556. SetupDiGetClassRegistryProperty(
  1557. IN CONST GUID *ClassGuid,
  1558. IN DWORD Property,
  1559. OUT PDWORD PropertyRegDataType, OPTIONAL
  1560. OUT PBYTE PropertyBuffer,
  1561. IN DWORD PropertyBufferSize,
  1562. OUT PDWORD RequiredSize, OPTIONAL
  1563. IN PCTSTR MachineName, OPTIONAL
  1564. IN PVOID Reserved
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This routine gets the specified Plug & Play device class registry property.
  1569. This is just a wrapper around the Config Mgr API
  1570. Typically the properties here can be overridden on a per-device basis,
  1571. however this routine returns the class properties only.
  1572. Arguments:
  1573. ClassGuid - Supplies the GUID for the device setup class from which the
  1574. property is to be retrieved.
  1575. Property - Supplies an ordinal specifying the property to be retrieved.
  1576. Refer to sdk\inc\setupapi.h for a complete listing of values that may
  1577. be set (these values are denoted with 'R/W' in their descriptive
  1578. comment).
  1579. PropertyRegDataType - Optionally, supplies the address of a variable that
  1580. will receive the data type of the property being retrieved. This will
  1581. be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
  1582. PropertyBuffer - Supplies the address of a buffer that receives the
  1583. property data.
  1584. PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer.
  1585. RequiredSize - Optionally, supplies the address of a variable that receives
  1586. the number of bytes required to store the requested property in the
  1587. buffer.
  1588. MachineName - Allows properties to be set on a remote machine (if Non-NULL)
  1589. Reserved - should be NULL
  1590. Return Value:
  1591. If the function succeeds, the return value is TRUE.
  1592. If the function fails, the return value is FALSE. To get extended error
  1593. information, call GetLastError.
  1594. --*/
  1595. {
  1596. DWORD Err = NO_ERROR;
  1597. try {
  1598. if(Reserved != NULL) {
  1599. //
  1600. // make sure caller doesn't pass a value here
  1601. // so we know we can use this at a later date
  1602. Err = ERROR_INVALID_PARAMETER;
  1603. leave;
  1604. }
  1605. Err = _SetupDiGetClassRegistryProperty(ClassGuid,
  1606. Property,
  1607. PropertyRegDataType,
  1608. PropertyBuffer,
  1609. PropertyBufferSize,
  1610. RequiredSize,
  1611. MachineName,
  1612. FALSE
  1613. );
  1614. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1615. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1616. }
  1617. SetLastError(Err);
  1618. return (Err == NO_ERROR);
  1619. }
  1620. DWORD
  1621. _SetupDiSetClassRegistryProperty(
  1622. IN CONST GUID *ClassGuid,
  1623. IN DWORD Property,
  1624. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1625. IN DWORD PropertyBufferSize,
  1626. IN PCTSTR MachineName, OPTIONAL
  1627. IN BOOL Ansi
  1628. )
  1629. /*++
  1630. See SetupDiGetClassRegistryProperty
  1631. --*/
  1632. {
  1633. DWORD Err;
  1634. CONFIGRET cr;
  1635. ULONG CmRegProperty, PropLength;
  1636. HMACHINE hMachine = NULL;
  1637. Err = NO_ERROR;
  1638. try {
  1639. //
  1640. // if we want to set register for another machine, find that machine
  1641. //
  1642. if(MachineName) {
  1643. if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
  1644. //
  1645. // Make sure machine handle is still invalid, so we won't
  1646. // try to disconnect later.
  1647. //
  1648. hMachine = NULL;
  1649. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1650. leave;
  1651. }
  1652. }
  1653. if(Property < SPCRP_MAXIMUM_PROPERTY) {
  1654. CmRegProperty = (ULONG)SPCRP_TO_CMCRP(Property);
  1655. } else {
  1656. Err = ERROR_INVALID_REG_PROPERTY;
  1657. leave;
  1658. }
  1659. PropLength = PropertyBufferSize;
  1660. if(Ansi) {
  1661. cr = CM_Set_Class_Registry_PropertyA(
  1662. (LPGUID)ClassGuid,
  1663. CmRegProperty,
  1664. PropertyBuffer,
  1665. PropLength,
  1666. 0,
  1667. hMachine);
  1668. } else {
  1669. cr = CM_Set_Class_Registry_PropertyW(
  1670. (LPGUID)ClassGuid,
  1671. CmRegProperty,
  1672. PropertyBuffer,
  1673. PropLength,
  1674. 0,
  1675. hMachine);
  1676. }
  1677. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  1678. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1679. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1680. }
  1681. if(hMachine != NULL) {
  1682. CM_Disconnect_Machine(hMachine);
  1683. }
  1684. return Err;
  1685. }
  1686. //
  1687. // ANSI version
  1688. //
  1689. WINSETUPAPI
  1690. BOOL
  1691. WINAPI
  1692. SetupDiSetClassRegistryPropertyA(
  1693. IN CONST GUID *ClassGuid,
  1694. IN DWORD Property,
  1695. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1696. IN DWORD PropertyBufferSize,
  1697. IN PCSTR MachineName, OPTIONAL
  1698. IN PVOID Reserved
  1699. )
  1700. /*++
  1701. See SetupDiSetClassRegistryProperty
  1702. --*/
  1703. {
  1704. PCWSTR MachineString = NULL;
  1705. DWORD Err = NO_ERROR;
  1706. try {
  1707. if(Reserved != NULL) {
  1708. //
  1709. // make sure caller doesn't pass a value here
  1710. // so we know we can use this at a later date
  1711. Err = ERROR_INVALID_PARAMETER;
  1712. leave;
  1713. }
  1714. //
  1715. // convert machine-name to local
  1716. //
  1717. if(MachineName != NULL) {
  1718. Err = pSetupCaptureAndConvertAnsiArg(MachineName,
  1719. &MachineString
  1720. );
  1721. if(Err != NO_ERROR) {
  1722. leave;
  1723. }
  1724. }
  1725. Err = _SetupDiSetClassRegistryProperty(ClassGuid,
  1726. Property,
  1727. PropertyBuffer,
  1728. PropertyBufferSize,
  1729. MachineString,
  1730. TRUE
  1731. );
  1732. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1733. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1734. }
  1735. if(MachineString) {
  1736. MyFree(MachineString);
  1737. }
  1738. SetLastError(Err);
  1739. return (Err == NO_ERROR);
  1740. }
  1741. WINSETUPAPI
  1742. BOOL
  1743. WINAPI
  1744. SetupDiSetClassRegistryProperty(
  1745. IN CONST GUID *ClassGuid,
  1746. IN DWORD Property,
  1747. IN CONST BYTE* PropertyBuffer, OPTIONAL
  1748. IN DWORD PropertyBufferSize,
  1749. IN PCTSTR MachineName, OPTIONAL
  1750. IN PVOID Reserved
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. This routine sets the specified Plug & Play device class registry property.
  1755. This is just a wrapper around the Config Mgr API
  1756. Typically the properties here can be overridden on a per-device basis
  1757. Arguments:
  1758. ClassGuid - Supplies the device setup class GUID for which the property is
  1759. to be set.
  1760. Property - Supplies an ordinal specifying the property to be set. Refer to
  1761. sdk\inc\setupapi.h for a complete list of class properties that are
  1762. writeable.
  1763. PropertyBuffer - Supplies the address of a buffer containing the property
  1764. data.
  1765. PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer.
  1766. MachineName - Optionally, specifies a remote machine where the class
  1767. properties are to be set.
  1768. Reserved - should be NULL
  1769. Return Value:
  1770. If the function succeeds, the return value is TRUE.
  1771. If the function fails, the return value is FALSE. To get extended error
  1772. information, call GetLastError.
  1773. --*/
  1774. {
  1775. DWORD Err;
  1776. try {
  1777. if(Reserved != NULL) {
  1778. //
  1779. // make sure caller doesn't pass a value here
  1780. // so we know we can use this at a later date
  1781. Err = ERROR_INVALID_PARAMETER;
  1782. leave;
  1783. }
  1784. Err = _SetupDiSetClassRegistryProperty(ClassGuid,
  1785. Property,
  1786. PropertyBuffer,
  1787. PropertyBufferSize,
  1788. MachineName,
  1789. FALSE
  1790. );
  1791. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1792. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1793. }
  1794. SetLastError(Err);
  1795. return (Err == NO_ERROR);
  1796. }
  1797. BOOL
  1798. pSetupFindUniqueKey(
  1799. IN HKEY hkRoot,
  1800. IN LPTSTR SubKey,
  1801. IN size_t SubKeySize
  1802. )
  1803. /*++
  1804. Routine Description:
  1805. This routine finds a unique key under the specified subkey. This key is
  1806. of the form <SubKey>\xxxx, where xxxx is a base-10, 4-digit number.
  1807. Arguments:
  1808. hkRoot - Root key under which the specified SubKey is located.
  1809. SubKey - Supplies the address of a buffer containing the subkey name under
  1810. which a unique key is to be generated. This buffer must contain enough
  1811. additional space to acccomodate the concatenation of "\\nnnn" (i.e.,
  1812. 5 extra characters, not counting terminating null.
  1813. SubKeySize - Supplies the size, in characters, of the SubKey buffer.
  1814. Return Value:
  1815. If the function succeeds, the return value is TRUE.
  1816. If the function fails, the return value is FALSE.
  1817. --*/
  1818. {
  1819. INT i;
  1820. HKEY hk;
  1821. HRESULT hr;
  1822. size_t SubKeyEnd;
  1823. PTSTR InstancePath;
  1824. size_t InstancePathBufferSize;
  1825. //
  1826. // Find the end of the string, so we know where to add our unique instance
  1827. // subkey path.
  1828. //
  1829. hr = StringCchLength(SubKey,
  1830. SubKeySize,
  1831. &SubKeyEnd
  1832. );
  1833. if(FAILED(hr)) {
  1834. MYASSERT(FALSE);
  1835. return FALSE;
  1836. }
  1837. InstancePath = SubKey + SubKeyEnd;
  1838. InstancePathBufferSize = SubKeySize - SubKeyEnd;
  1839. for(i = 0; i <= 9999; i++) {
  1840. hr = StringCchPrintf(InstancePath,
  1841. InstancePathBufferSize,
  1842. pszUniqueSubKey,
  1843. i
  1844. );
  1845. if(FAILED(hr)) {
  1846. MYASSERT(FALSE);
  1847. return FALSE;
  1848. }
  1849. if(ERROR_SUCCESS != RegOpenKeyEx(hkRoot, SubKey, 0, KEY_READ, &hk)) {
  1850. return TRUE;
  1851. }
  1852. RegCloseKey(hk);
  1853. }
  1854. return FALSE;
  1855. }
  1856. BOOL
  1857. WINAPI
  1858. SetupDiDeleteDevRegKey(
  1859. IN HDEVINFO DeviceInfoSet,
  1860. IN PSP_DEVINFO_DATA DeviceInfoData,
  1861. IN DWORD Scope,
  1862. IN DWORD HwProfile,
  1863. IN DWORD KeyType
  1864. )
  1865. /*++
  1866. Routine Description:
  1867. This routine deletes the specified registry key(s) associated with a device
  1868. information element.
  1869. Arguments:
  1870. DeviceInfoSet - Supplies a handle to the device information set containing
  1871. the device instance to delete key(s) for.
  1872. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure
  1873. indicating the device instance to delete key(s) for.
  1874. Scope - Specifies the scope of the registry key to be deleted. This
  1875. determines where the key to be deleted is located--the key may be one
  1876. that is global (i.e., constant regardless of current hardware profile)
  1877. or hardware profile-specific. May be a combination of the following
  1878. values:
  1879. DICS_FLAG_GLOBAL - Delete the key that stores global configuration
  1880. information.
  1881. DICS_FLAG_CONFIGSPECIFIC - Delete the key that stores hardware profile-
  1882. specific information.
  1883. HwProfile - Specifies the hardware profile to delete a key for, if the
  1884. Scope parameter includes the DICS_FLAG_CONFIGSPECIFIC flag. If this
  1885. parameter is 0, then the key for the current hardware profile should be
  1886. deleted (i.e., in the Class branch under HKEY_CURRENT_CONFIG). If this
  1887. parameter is 0xFFFFFFFF, then the key for _all_ hardware profiles
  1888. should be deleted.
  1889. KeyType - Specifies the type of registry storage key to be deleted. May be
  1890. one of the following values:
  1891. DIREG_DEV - Delete the hardware registry key for the device. This is
  1892. the key for storage of driver-independent configuration
  1893. information. (This key is in the device instance key in
  1894. the Enum branch.
  1895. DIREG_DRV - Delete the software (i.e., driver) registry key for the
  1896. device. (This key is located in the class branch.)
  1897. DIREG_BOTH - Delete both the hardware and software keys for the device.
  1898. Return Value:
  1899. If the function succeeds, the return value is TRUE.
  1900. If the function fails, the return value is FALSE. To get extended error
  1901. information, call GetLastError.
  1902. --*/
  1903. {
  1904. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  1905. DWORD Err;
  1906. PDEVINFO_ELEM DevInfoElem;
  1907. CONFIGRET cr;
  1908. try {
  1909. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  1910. Err = ERROR_INVALID_HANDLE;
  1911. leave;
  1912. }
  1913. //
  1914. // Get a pointer to the element for the specified device
  1915. // instance.
  1916. //
  1917. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  1918. DeviceInfoData,
  1919. NULL)) {
  1920. Err = pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
  1921. Scope,
  1922. HwProfile,
  1923. KeyType,
  1924. FALSE,
  1925. pDeviceInfoSet->hMachine
  1926. );
  1927. } else {
  1928. Err = ERROR_INVALID_PARAMETER;
  1929. }
  1930. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1931. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1932. }
  1933. if(pDeviceInfoSet) {
  1934. UnlockDeviceInfoSet(pDeviceInfoSet);
  1935. }
  1936. SetLastError(Err);
  1937. return (Err == NO_ERROR);
  1938. }
  1939. DWORD
  1940. pSetupDeleteDevRegKeys(
  1941. IN DEVINST DevInst,
  1942. IN DWORD Scope,
  1943. IN DWORD HwProfile,
  1944. IN DWORD KeyType,
  1945. IN BOOL DeleteUserKeys,
  1946. IN HMACHINE hMachine OPTIONAL
  1947. )
  1948. /*++
  1949. Routine Description:
  1950. This is the worker routine for SetupDiDeleteDevRegKey. See the discussion
  1951. of that API for details.
  1952. Return Value:
  1953. If successful, the return value is NO_ERROR;
  1954. If failure, the return value is a Win32 error code indicating the cause of
  1955. failure.
  1956. Remarks:
  1957. Even if one of the operations in this routine fails, all operations will be
  1958. attempted. Thus, as many keys as possible will be deleted. The error
  1959. returned will be the first error that was encountered in this case.
  1960. --*/
  1961. {
  1962. CONFIGRET cr = CR_SUCCESS, crTemp;
  1963. TCHAR DriverKey[GUID_STRING_LEN + 5]; // Eg, {4d36e978-e325-11ce-bfc1-08002be10318}\0000
  1964. size_t DriverKeyLength;
  1965. HRESULT hr;
  1966. if(Scope & DICS_FLAG_GLOBAL) {
  1967. if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
  1968. //
  1969. // Retrieve the current Driver key name, in case we have to restore
  1970. // it.
  1971. //
  1972. DriverKeyLength = sizeof(DriverKey);
  1973. cr = CM_Get_DevInst_Registry_Property_Ex(DevInst,
  1974. CM_DRP_DRIVER,
  1975. NULL,
  1976. DriverKey,
  1977. (PULONG)&DriverKeyLength,
  1978. 0,
  1979. hMachine
  1980. );
  1981. if(cr == CR_SUCCESS) {
  1982. //
  1983. // Get the actual size of the driver key name returned.
  1984. //
  1985. hr = StringCchLength(DriverKey,
  1986. SIZECHARS(DriverKey),
  1987. &DriverKeyLength
  1988. );
  1989. if(!MYVERIFY(SUCCEEDED(hr))) {
  1990. //
  1991. // CM API gave us garbage!!!
  1992. //
  1993. return ERROR_INVALID_DATA;
  1994. }
  1995. DriverKeyLength = (DriverKeyLength + 1) * sizeof(TCHAR);
  1996. MYASSERT(DriverKeyLength == sizeof(DriverKey));
  1997. //
  1998. // Driver key exists and is valid, so make sure we delete its
  1999. // per-hwprofile and per-user counterparts as well.
  2000. //
  2001. Scope |= DICS_FLAG_CONFIGSPECIFIC;
  2002. HwProfile = (DWORD)-1;
  2003. DeleteUserKeys = TRUE;
  2004. } else if(cr == CR_NO_SUCH_VALUE) {
  2005. //
  2006. // There is no driver key, so don't bother trying to delete it
  2007. // (in any of its forms).
  2008. //
  2009. if(KeyType == DIREG_BOTH) {
  2010. //
  2011. // Still need to delete the device keys.
  2012. //
  2013. KeyType = DIREG_DEV;
  2014. //
  2015. // If the device keys all get deleted successfully, then
  2016. // we'll consider the function call successful.
  2017. //
  2018. cr = CR_SUCCESS;
  2019. } else {
  2020. //
  2021. // We weren't asked to delete any device keys, so we're
  2022. // done!
  2023. //
  2024. return NO_ERROR;
  2025. }
  2026. } else {
  2027. //
  2028. // We failed for some other reason--remember this error. If
  2029. // we're supposed to delete device keys, we'll go ahead and
  2030. // try to do that.
  2031. //
  2032. if(KeyType == DIREG_BOTH) {
  2033. KeyType = DIREG_DEV;
  2034. } else {
  2035. return MapCrToSpError(cr, ERROR_INVALID_DATA);
  2036. }
  2037. }
  2038. }
  2039. }
  2040. if(Scope & DICS_FLAG_CONFIGSPECIFIC) {
  2041. if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
  2042. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2043. HwProfile,
  2044. CM_REGISTRY_HARDWARE | CM_REGISTRY_CONFIG,
  2045. hMachine
  2046. );
  2047. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2048. cr = crTemp;
  2049. }
  2050. }
  2051. if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
  2052. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2053. HwProfile,
  2054. CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG,
  2055. hMachine
  2056. );
  2057. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2058. cr = crTemp;
  2059. }
  2060. }
  2061. }
  2062. if(DeleteUserKeys) {
  2063. if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
  2064. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2065. 0,
  2066. CM_REGISTRY_HARDWARE | CM_REGISTRY_USER,
  2067. hMachine
  2068. );
  2069. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2070. cr = crTemp;
  2071. }
  2072. }
  2073. if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
  2074. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2075. 0,
  2076. CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER,
  2077. hMachine
  2078. );
  2079. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2080. cr = crTemp;
  2081. }
  2082. }
  2083. }
  2084. //
  2085. // We intentionally save the global keys for last. As part of deleting the
  2086. // driver key, we _should_ also reset the devnode's Driver property, since
  2087. // there is a small window during which it is pointing to a non-nonexistent
  2088. // key, but some other devnode might come along and claim that empty slot.
  2089. // Voila! You'd then have two devnodes sharing the same driver key. This
  2090. // would be _very_ bad. Unfortunately, the driver value must remain in tact
  2091. // until _after_ the key has been deleted.
  2092. //
  2093. // NTRAID#NTBUG9-613881-2002/05/01-lonnym -- CfgMgr should ensure driver key integrity
  2094. //
  2095. if(Scope & DICS_FLAG_GLOBAL) {
  2096. if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
  2097. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2098. 0,
  2099. CM_REGISTRY_HARDWARE,
  2100. hMachine
  2101. );
  2102. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2103. cr = crTemp;
  2104. }
  2105. }
  2106. if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
  2107. crTemp = CM_Delete_DevInst_Key_Ex(DevInst,
  2108. 0,
  2109. CM_REGISTRY_SOFTWARE,
  2110. hMachine
  2111. );
  2112. if(crTemp == CR_SUCCESS) {
  2113. //
  2114. // First, we delete the key. Then, we reset the Driver property
  2115. // to sever the link with the key. We have to do things in this
  2116. // order since deleting the key always depends on the Driver
  2117. // property to be there. Ideally, we would do things in the
  2118. // reverse order. By deleting the key first, it is technically
  2119. // possible another devnode could come and grab that slot, with
  2120. // our devnode still pointing there for a brief period of time.
  2121. //
  2122. CM_Set_DevInst_Registry_Property_Ex(DevInst,
  2123. CM_DRP_DRIVER,
  2124. NULL,
  2125. 0,
  2126. 0,
  2127. hMachine
  2128. );
  2129. }
  2130. if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
  2131. cr = crTemp;
  2132. }
  2133. }
  2134. }
  2135. return MapCrToSpError(cr, ERROR_INVALID_DATA);
  2136. }
  2137. //
  2138. // ANSI version
  2139. //
  2140. HKEY
  2141. WINAPI
  2142. SetupDiCreateDeviceInterfaceRegKeyA(
  2143. IN HDEVINFO DeviceInfoSet,
  2144. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  2145. IN DWORD Reserved,
  2146. IN REGSAM samDesired,
  2147. IN HINF InfHandle, OPTIONAL
  2148. IN PCSTR InfSectionName OPTIONAL
  2149. )
  2150. {
  2151. DWORD rc;
  2152. PWSTR name = NULL;
  2153. HKEY h = INVALID_HANDLE_VALUE;
  2154. try {
  2155. if(InfSectionName) {
  2156. rc = pSetupCaptureAndConvertAnsiArg(InfSectionName, &name);
  2157. if(rc != NO_ERROR) {
  2158. leave;
  2159. }
  2160. }
  2161. rc = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  2162. h = SetupDiCreateDeviceInterfaceRegKeyW(
  2163. DeviceInfoSet,
  2164. DeviceInterfaceData,
  2165. Reserved,
  2166. samDesired,
  2167. InfHandle,
  2168. name)
  2169. );
  2170. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2171. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &rc);
  2172. }
  2173. if(name) {
  2174. MyFree(name);
  2175. }
  2176. SetLastError(rc);
  2177. return(h);
  2178. }
  2179. HKEY
  2180. WINAPI
  2181. SetupDiCreateDeviceInterfaceRegKey(
  2182. IN HDEVINFO DeviceInfoSet,
  2183. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  2184. IN DWORD Reserved,
  2185. IN REGSAM samDesired,
  2186. IN HINF InfHandle, OPTIONAL
  2187. IN PCTSTR InfSectionName OPTIONAL
  2188. )
  2189. /*++
  2190. Routine Description:
  2191. This routine creates a registry storage key for a particular device
  2192. interface, and returns a handle to the key.
  2193. Arguments:
  2194. DeviceInfoSet - Supplies a handle to the device information set containing
  2195. the device interface for whom a registry key is to be created.
  2196. DeviceInterfaceData - Supplies a pointer to a device interface data
  2197. structure indicating which device interface a key is to be created for.
  2198. Reserved - Reserved for future use, must be set to 0.
  2199. samDesired - Specifies the registry access desired for the resulting key
  2200. handle.
  2201. InfHandle - Optionally, supplies the handle of an opened INF file
  2202. containing an install section to be executed for the newly-created key.
  2203. If this parameter is specified, then InfSectionName must be specified
  2204. as well.
  2205. NOTE: INF-based installation is not supported for remoted device
  2206. information sets (e.g., as created by passing a non-NULL MachineName in
  2207. to SetupDiCreateDeviceInfoListEx). This routine will fail with
  2208. ERROR_REMOTE_REQUEST_UNSUPPORTED in those cases.
  2209. InfSectionName - Optionally, supplies the name of an install section in the
  2210. INF file specified by InfHandle. This section will be executed for the
  2211. newly created key. If this parameter is specified, then InfHandle must
  2212. be specified as well.
  2213. Return Value:
  2214. If the function succeeds, the return value is a handle to a newly-created
  2215. registry key where private configuration data pertaining to this device
  2216. interface may be stored/retrieved.
  2217. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  2218. extended error information, call GetLastError.
  2219. Remarks:
  2220. The handle returned from this routine must be closed by calling
  2221. RegCloseKey.
  2222. During GUI-mode setup on Windows NT, quiet-install behavior is always
  2223. employed in the absence of a user-supplied file queue, regardless of
  2224. whether the device information element has the DI_QUIETINSTALL flag set.
  2225. --*/
  2226. {
  2227. HKEY hk = INVALID_HANDLE_VALUE, hSubKey = INVALID_HANDLE_VALUE;
  2228. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  2229. DWORD Err;
  2230. PDEVINFO_ELEM DevInfoElem;
  2231. PSP_FILE_CALLBACK MsgHandler;
  2232. PVOID MsgHandlerContext;
  2233. BOOL FreeMsgHandlerContext = FALSE;
  2234. BOOL MsgHandlerIsNativeCharWidth;
  2235. BOOL NoProgressUI;
  2236. DWORD KeyDisposition;
  2237. try {
  2238. if(Reserved != 0) {
  2239. Err = ERROR_INVALID_PARAMETER;
  2240. leave;
  2241. }
  2242. //
  2243. // Make sure that either both InfHandle and InfSectionName are
  2244. // specified, or neither are...
  2245. //
  2246. if(InfHandle && (InfHandle != INVALID_HANDLE_VALUE)) {
  2247. if(!InfSectionName) {
  2248. Err = ERROR_INVALID_PARAMETER;
  2249. leave;
  2250. }
  2251. } else {
  2252. if(InfSectionName) {
  2253. Err = ERROR_INVALID_PARAMETER;
  2254. leave;
  2255. } else {
  2256. //
  2257. // Let's stick with _one_ value to indicate that the INF handle
  2258. // wasn't suplied (the official one)...
  2259. //
  2260. InfHandle = INVALID_HANDLE_VALUE;
  2261. }
  2262. }
  2263. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2264. Err = ERROR_INVALID_HANDLE;
  2265. leave;
  2266. }
  2267. //
  2268. // We don't support installation remotely.
  2269. //
  2270. if((pDeviceInfoSet->hMachine) && (InfHandle != INVALID_HANDLE_VALUE)) {
  2271. Err = ERROR_REMOTE_REQUEST_UNSUPPORTED;
  2272. leave;
  2273. }
  2274. //
  2275. // Get a pointer to the device information element for the specified
  2276. // device interface.
  2277. //
  2278. if(!(DevInfoElem = FindDevInfoElemForDeviceInterface(pDeviceInfoSet, DeviceInterfaceData))) {
  2279. Err = ERROR_INVALID_PARAMETER;
  2280. leave;
  2281. }
  2282. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  2283. hk = SetupDiOpenClassRegKeyEx(
  2284. &(DeviceInterfaceData->InterfaceClassGuid),
  2285. KEY_READ,
  2286. DIOCR_INTERFACE,
  2287. (pDeviceInfoSet->hMachine
  2288. ? pStringTableStringFromId(pDeviceInfoSet->StringTable,
  2289. pDeviceInfoSet->MachineName)
  2290. : NULL),
  2291. NULL)
  2292. );
  2293. if(Err != NO_ERROR) {
  2294. leave;
  2295. }
  2296. //
  2297. // Now, create the client-accessible registry storage key for this
  2298. // device interface.
  2299. //
  2300. Err = pSetupOpenOrCreateDeviceInterfaceRegKey(hk,
  2301. pDeviceInfoSet,
  2302. DeviceInterfaceData,
  2303. TRUE,
  2304. samDesired,
  2305. &hSubKey,
  2306. &KeyDisposition
  2307. );
  2308. if(Err != NO_ERROR) {
  2309. leave;
  2310. }
  2311. //
  2312. // We successfully created the storage key, now run an INF install
  2313. // section against it (if specified).
  2314. //
  2315. if(InfHandle != INVALID_HANDLE_VALUE) {
  2316. //
  2317. // If a copy msg handler and context haven't been specified, then
  2318. // use the default one.
  2319. //
  2320. if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
  2321. MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
  2322. MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
  2323. MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
  2324. } else {
  2325. NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
  2326. if(!(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
  2327. DevInfoElem->InstallParamBlock.hwndParent,
  2328. (NoProgressUI ? INVALID_HANDLE_VALUE
  2329. : NULL),
  2330. 0,
  2331. 0,
  2332. NULL))) {
  2333. Err = ERROR_NOT_ENOUGH_MEMORY;
  2334. leave;
  2335. }
  2336. FreeMsgHandlerContext = TRUE;
  2337. MsgHandler = SetupDefaultQueueCallback;
  2338. MsgHandlerIsNativeCharWidth = TRUE;
  2339. }
  2340. Err = GLE_FN_CALL(FALSE,
  2341. _SetupInstallFromInfSection(
  2342. DevInfoElem->InstallParamBlock.hwndParent,
  2343. InfHandle,
  2344. InfSectionName,
  2345. SPINST_ALL ^ SPINST_LOGCONFIG,
  2346. hSubKey,
  2347. NULL,
  2348. 0,
  2349. MsgHandler,
  2350. MsgHandlerContext,
  2351. INVALID_HANDLE_VALUE,
  2352. NULL,
  2353. MsgHandlerIsNativeCharWidth,
  2354. NULL)
  2355. );
  2356. }
  2357. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2358. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2359. }
  2360. if(FreeMsgHandlerContext) {
  2361. SetupTermDefaultQueueCallback(MsgHandlerContext);
  2362. }
  2363. if(Err != NO_ERROR) {
  2364. //
  2365. // Close registry handle, if necessary, and delete key (if newly-
  2366. // created). We do this prior to unlocking the devinfo set so that at
  2367. // least no one using this HDEVINFO can get at this half-finished key.
  2368. //
  2369. if(hSubKey != INVALID_HANDLE_VALUE) {
  2370. RegCloseKey(hSubKey);
  2371. hSubKey = INVALID_HANDLE_VALUE;
  2372. //
  2373. // If the key was newly-created, then we want to delete it.
  2374. //
  2375. if(KeyDisposition == REG_CREATED_NEW_KEY) {
  2376. //
  2377. // Now delete the device interface key.
  2378. //
  2379. MYASSERT(hk != INVALID_HANDLE_VALUE);
  2380. Err = pSetupDeleteDeviceInterfaceKey(hk,
  2381. pDeviceInfoSet,
  2382. DeviceInterfaceData
  2383. );
  2384. }
  2385. }
  2386. }
  2387. if(hk != INVALID_HANDLE_VALUE) {
  2388. RegCloseKey(hk);
  2389. }
  2390. if(pDeviceInfoSet) {
  2391. UnlockDeviceInfoSet(pDeviceInfoSet);
  2392. }
  2393. SetLastError(Err);
  2394. return hSubKey;
  2395. }
  2396. HKEY
  2397. WINAPI
  2398. SetupDiOpenDeviceInterfaceRegKey(
  2399. IN HDEVINFO DeviceInfoSet,
  2400. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  2401. IN DWORD Reserved,
  2402. IN REGSAM samDesired
  2403. )
  2404. /*++
  2405. Routine Description:
  2406. This routine opens a registry storage key for a particular device
  2407. interface, and returns a handle to the key.
  2408. Arguments:
  2409. DeviceInfoSet - Supplies a handle to the device information set containing
  2410. the device interface for whom a registry key is to be opened.
  2411. DeviceInterfaceData - Supplies a pointer to a device interface data
  2412. structure indicating which device interface a key is to be opened for.
  2413. Reserved - Reserved for future use, must be set to 0.
  2414. samDesired - Specifies the access you require for this key.
  2415. Return Value:
  2416. If the function succeeds, the return value is a handle to an opened
  2417. registry key where private configuration data pertaining to this device
  2418. interface may be stored/retrieved.
  2419. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  2420. extended error information, call GetLastError.
  2421. Remarks:
  2422. The handle returned from this routine must be closed by calling RegCloseKey.
  2423. --*/
  2424. {
  2425. HKEY hk = INVALID_HANDLE_VALUE, hSubKey = INVALID_HANDLE_VALUE;
  2426. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  2427. DWORD Err;
  2428. PDEVINFO_ELEM DevInfoElem;
  2429. try {
  2430. if(Reserved != 0) {
  2431. Err = ERROR_INVALID_PARAMETER;
  2432. leave;
  2433. }
  2434. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2435. Err = ERROR_INVALID_HANDLE;
  2436. leave;
  2437. }
  2438. //
  2439. // Get a pointer to the device information element for the specified
  2440. // device interface.
  2441. //
  2442. if(!(DevInfoElem = FindDevInfoElemForDeviceInterface(pDeviceInfoSet, DeviceInterfaceData))) {
  2443. Err = ERROR_INVALID_PARAMETER;
  2444. leave;
  2445. }
  2446. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  2447. hk = SetupDiOpenClassRegKeyEx(
  2448. &(DeviceInterfaceData->InterfaceClassGuid),
  2449. KEY_READ,
  2450. DIOCR_INTERFACE,
  2451. (pDeviceInfoSet->hMachine
  2452. ? pStringTableStringFromId(pDeviceInfoSet->StringTable,
  2453. pDeviceInfoSet->MachineName)
  2454. : NULL),
  2455. NULL)
  2456. );
  2457. if(Err != NO_ERROR) {
  2458. leave;
  2459. }
  2460. //
  2461. // Now, open up the client-accessible registry storage key for this
  2462. // device interface.
  2463. //
  2464. Err = pSetupOpenOrCreateDeviceInterfaceRegKey(hk,
  2465. pDeviceInfoSet,
  2466. DeviceInterfaceData,
  2467. FALSE,
  2468. samDesired,
  2469. &hSubKey,
  2470. NULL
  2471. );
  2472. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2473. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2474. }
  2475. if(pDeviceInfoSet) {
  2476. UnlockDeviceInfoSet(pDeviceInfoSet);
  2477. }
  2478. if(hk != INVALID_HANDLE_VALUE) {
  2479. RegCloseKey(hk);
  2480. }
  2481. SetLastError(Err);
  2482. return hSubKey;
  2483. }
  2484. BOOL
  2485. WINAPI
  2486. SetupDiDeleteDeviceInterfaceRegKey(
  2487. IN HDEVINFO DeviceInfoSet,
  2488. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  2489. IN DWORD Reserved
  2490. )
  2491. /*++
  2492. Routine Description:
  2493. This routine deletes the registry key associated with a device interface.
  2494. Arguments:
  2495. DeviceInfoSet - Supplies a handle to the device information set containing
  2496. the device interface whose registry key is to be deleted.
  2497. DeviceInterfaceData - Supplies a pointer to a device interface data
  2498. structure indicating which device interface is to have its registry key
  2499. deleted.
  2500. Reserved - Reserved for future use, must be set to 0.
  2501. Return Value:
  2502. If the function succeeds, the return value is TRUE.
  2503. If the function fails, the return value is FALSE. To get extended error
  2504. information, call GetLastError.
  2505. --*/
  2506. {
  2507. HKEY hk = INVALID_HANDLE_VALUE;
  2508. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  2509. DWORD Err;
  2510. PDEVINFO_ELEM DevInfoElem;
  2511. try {
  2512. if(Reserved != 0) {
  2513. Err = ERROR_INVALID_PARAMETER;
  2514. leave;
  2515. }
  2516. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2517. Err = ERROR_INVALID_HANDLE;
  2518. leave;
  2519. }
  2520. //
  2521. // Get a pointer to the device information element for the specified
  2522. // device interface.
  2523. //
  2524. if(!(DevInfoElem = FindDevInfoElemForDeviceInterface(pDeviceInfoSet, DeviceInterfaceData))) {
  2525. Err = ERROR_INVALID_PARAMETER;
  2526. leave;
  2527. }
  2528. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  2529. hk = SetupDiOpenClassRegKeyEx(
  2530. &(DeviceInterfaceData->InterfaceClassGuid),
  2531. KEY_READ,
  2532. DIOCR_INTERFACE,
  2533. (pDeviceInfoSet->hMachine
  2534. ? pStringTableStringFromId(pDeviceInfoSet->StringTable,
  2535. pDeviceInfoSet->MachineName)
  2536. : NULL),
  2537. NULL)
  2538. );
  2539. if(Err != NO_ERROR) {
  2540. leave;
  2541. }
  2542. //
  2543. // Now delete the device interface key.
  2544. //
  2545. Err = pSetupDeleteDeviceInterfaceKey(hk,
  2546. pDeviceInfoSet,
  2547. DeviceInterfaceData
  2548. );
  2549. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2550. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2551. }
  2552. if(pDeviceInfoSet) {
  2553. UnlockDeviceInfoSet(pDeviceInfoSet);
  2554. }
  2555. if(hk != INVALID_HANDLE_VALUE) {
  2556. RegCloseKey(hk);
  2557. }
  2558. SetLastError(Err);
  2559. return (Err == NO_ERROR);
  2560. }
  2561. DWORD
  2562. pSetupOpenOrCreateDeviceInterfaceRegKey(
  2563. IN HKEY hInterfaceClassKey,
  2564. IN PDEVICE_INFO_SET DeviceInfoSet,
  2565. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  2566. IN BOOL Create,
  2567. IN REGSAM samDesired,
  2568. OUT PHKEY hDeviceInterfaceKey,
  2569. OUT PDWORD KeyDisposition OPTIONAL
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. This routine creates or opens a registry storage key for the specified
  2574. device interface, and returns a handle to the opened key.
  2575. Arguments:
  2576. hInterfaceClassKey - Supplies a handle to the opened interface class key,
  2577. underneath which the device interface storage key is to be opened or
  2578. created.
  2579. DeviceInfoSet - Supplies a pointer to the device information set containing
  2580. the device interface for which a registry storage key is to be opened
  2581. or created.
  2582. DeviceInterfaceData - Supplies a pointer to a device interface data
  2583. structure indicating which device interface a key is to be opened/
  2584. created for.
  2585. Create - Specifies whether the key should be created if doesn't already
  2586. exist.
  2587. samDesired - Specifies the access you require for this key.
  2588. hDeviceInterfaceKey - Supplies the address of a variable that receives a
  2589. handle to the requested registry key. (This variable will only be
  2590. written to if the handle is successfully opened.)
  2591. KeyDisposition - Optionally, supplies the address of a variable that
  2592. receives the status of the returned key handle. Can be either:
  2593. REG_CREATED_NEW_KEY - The key did not exist and was created.
  2594. REG_OPENED_EXISTING_KEY - The key existed and was simply opened without
  2595. being changed. (This will always be the case
  2596. if the Create parameter is FALSE.)
  2597. Return Value:
  2598. If the function is successful, the return value is NO_ERROR, otherwise, it
  2599. is a Win32 error code indicating the error that occurred.
  2600. Remarks:
  2601. The algorithm used to form the storage keys for a device interface must be
  2602. kept in sync with the kernel mode implementation of
  2603. IoOpenDeviceInterfaceRegistryKey.
  2604. --*/
  2605. {
  2606. DWORD Err;
  2607. PDEVICE_INTERFACE_NODE DeviceInterfaceNode;
  2608. LPGUID ClassGuid;
  2609. HKEY hDeviceInterfaceRootKey = INVALID_HANDLE_VALUE;
  2610. HKEY hSubKey;
  2611. DWORD Disposition;
  2612. PCTSTR DevicePath;
  2613. try {
  2614. //
  2615. // Get the device interface node, and verify that its class matches
  2616. // what the caller passed us.
  2617. //
  2618. DeviceInterfaceNode = (PDEVICE_INTERFACE_NODE)(DeviceInterfaceData->Reserved);
  2619. ClassGuid = &(DeviceInfoSet->GuidTable[DeviceInterfaceNode->GuidIndex]);
  2620. if(!IsEqualGUID(ClassGuid, &(DeviceInterfaceData->InterfaceClassGuid))) {
  2621. Err = ERROR_INVALID_PARAMETER;
  2622. leave;
  2623. }
  2624. //
  2625. // Verify that this device interface hasn't been removed.
  2626. //
  2627. if(DeviceInterfaceNode->Flags & SPINT_REMOVED) {
  2628. Err = ERROR_DEVICE_INTERFACE_REMOVED;
  2629. leave;
  2630. }
  2631. //
  2632. // OK, now open the device interface's root storage key.
  2633. //
  2634. DevicePath = pStringTableStringFromId(DeviceInfoSet->StringTable,
  2635. DeviceInterfaceNode->SymLinkName
  2636. );
  2637. if(ERROR_SUCCESS != OpenDeviceInterfaceSubKey(hInterfaceClassKey,
  2638. DevicePath,
  2639. KEY_READ,
  2640. &hDeviceInterfaceRootKey,
  2641. NULL,
  2642. NULL)) {
  2643. //
  2644. // Make sure hDeviceInterfaceRootKey is still INVALID_HANDLE_VALUE,
  2645. // so we won't try to close it later.
  2646. //
  2647. hDeviceInterfaceRootKey = INVALID_HANDLE_VALUE;
  2648. Err = ERROR_INVALID_PARAMETER;
  2649. leave;
  2650. }
  2651. if(Create) {
  2652. Err = RegCreateKeyEx(hDeviceInterfaceRootKey,
  2653. pszDeviceParameters,
  2654. 0,
  2655. NULL,
  2656. REG_OPTION_NON_VOLATILE,
  2657. samDesired,
  2658. NULL,
  2659. &hSubKey,
  2660. KeyDisposition
  2661. );
  2662. } else {
  2663. if(KeyDisposition) {
  2664. //
  2665. // We set this prior to calling RegOpenKeyEx because we don't
  2666. // want anything to go wrong once we've successfully opened
  2667. // that key (i.e., we're protecting against the case where
  2668. // KeyDispositiot is a bogus pointer).
  2669. //
  2670. *KeyDisposition = REG_OPENED_EXISTING_KEY;
  2671. }
  2672. Err = RegOpenKeyEx(hDeviceInterfaceRootKey,
  2673. pszDeviceParameters,
  2674. 0,
  2675. samDesired,
  2676. &hSubKey
  2677. );
  2678. }
  2679. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2680. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2681. }
  2682. if(hDeviceInterfaceRootKey != INVALID_HANDLE_VALUE) {
  2683. RegCloseKey(hDeviceInterfaceRootKey);
  2684. }
  2685. if(Err == NO_ERROR) {
  2686. *hDeviceInterfaceKey = hSubKey;
  2687. }
  2688. return Err;
  2689. }
  2690. DWORD
  2691. pSetupDeleteDeviceInterfaceKey(
  2692. IN HKEY hInterfaceClassKey,
  2693. IN PDEVICE_INFO_SET DeviceInfoSet,
  2694. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  2695. )
  2696. /*++
  2697. Routine Description:
  2698. This routine deletes a device interface registry key (recursively deleting
  2699. any subkeys as well).
  2700. Arguments:
  2701. hInterfaceClassKey - Supplies the handle to the registry key underneath
  2702. which the 2-level interface class hierarchy exists.
  2703. DeviceInfoSet - Supplies a pointer to the device information set containing
  2704. the device interface whose registry key is to be deleted.
  2705. DeviceInterfaceData - Supplies a pointer to a device interface data
  2706. structure indicating which device interface is to have its registry key
  2707. deleted.
  2708. Return Value:
  2709. If successful, the return value is NO_ERROR;
  2710. If failure, the return value is a Win32 error code indicating the cause of
  2711. failure.
  2712. --*/
  2713. {
  2714. DWORD Err;
  2715. PDEVICE_INTERFACE_NODE DeviceInterfaceNode;
  2716. LPGUID ClassGuid;
  2717. HKEY hDeviceInterfaceRootKey;
  2718. PCTSTR DevicePath;
  2719. Err = NO_ERROR;
  2720. hDeviceInterfaceRootKey = INVALID_HANDLE_VALUE;
  2721. try {
  2722. //
  2723. // Get the device interface node, and verify that its class matches
  2724. // what the caller passed us.
  2725. //
  2726. DeviceInterfaceNode = (PDEVICE_INTERFACE_NODE)(DeviceInterfaceData->Reserved);
  2727. ClassGuid = &(DeviceInfoSet->GuidTable[DeviceInterfaceNode->GuidIndex]);
  2728. if(!IsEqualGUID(ClassGuid, &(DeviceInterfaceData->InterfaceClassGuid))) {
  2729. Err = ERROR_INVALID_PARAMETER;
  2730. leave;
  2731. }
  2732. //
  2733. // Verify that this device interface hasn't been removed.
  2734. //
  2735. if(DeviceInterfaceNode->Flags & SPINT_REMOVED) {
  2736. Err = ERROR_DEVICE_INTERFACE_REMOVED;
  2737. leave;
  2738. }
  2739. //
  2740. // OK, now open the device interface's root storage key.
  2741. //
  2742. DevicePath = pStringTableStringFromId(DeviceInfoSet->StringTable,
  2743. DeviceInterfaceNode->SymLinkName
  2744. );
  2745. if(ERROR_SUCCESS != OpenDeviceInterfaceSubKey(hInterfaceClassKey,
  2746. DevicePath,
  2747. KEY_READ,
  2748. &hDeviceInterfaceRootKey,
  2749. NULL,
  2750. NULL)) {
  2751. //
  2752. // Make sure hDeviceInterfaceRootKey is still INVALID_HANDLE_VALUE, so we
  2753. // won't try to close it later.
  2754. //
  2755. hDeviceInterfaceRootKey = INVALID_HANDLE_VALUE;
  2756. Err = ERROR_INVALID_PARAMETER;
  2757. leave;
  2758. }
  2759. Err = pSetupRegistryDelnode(hDeviceInterfaceRootKey, pszDeviceParameters);
  2760. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2761. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2762. }
  2763. if(hDeviceInterfaceRootKey != INVALID_HANDLE_VALUE) {
  2764. RegCloseKey(hDeviceInterfaceRootKey);
  2765. }
  2766. return Err;
  2767. }
  2768. DWORD
  2769. _SetupDiGetCustomDeviceProperty(
  2770. IN HDEVINFO DeviceInfoSet,
  2771. IN PSP_DEVINFO_DATA DeviceInfoData,
  2772. IN CONST VOID *CustomPropertyName, // ANSI or Unicode, depending on "Ansi" param.
  2773. IN DWORD Flags,
  2774. OUT PDWORD PropertyRegDataType, OPTIONAL
  2775. OUT PBYTE PropertyBuffer,
  2776. IN DWORD PropertyBufferSize,
  2777. OUT PDWORD RequiredSize, OPTIONAL
  2778. IN BOOL Ansi
  2779. )
  2780. {
  2781. PDEVICE_INFO_SET pDeviceInfoSet;
  2782. DWORD Err;
  2783. PDEVINFO_ELEM DevInfoElem;
  2784. CONFIGRET cr;
  2785. ULONG PropLength, CmFlags;
  2786. //
  2787. // At present, there's only one valid flag...
  2788. //
  2789. if(Flags & ~DICUSTOMDEVPROP_MERGE_MULTISZ) {
  2790. return ERROR_INVALID_FLAGS;
  2791. }
  2792. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2793. return ERROR_INVALID_HANDLE;
  2794. }
  2795. Err = NO_ERROR;
  2796. try {
  2797. //
  2798. // Get a pointer to the element for the specified device
  2799. // instance.
  2800. //
  2801. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2802. DeviceInfoData,
  2803. NULL))) {
  2804. Err = ERROR_INVALID_PARAMETER;
  2805. leave;
  2806. }
  2807. if(Flags & DICUSTOMDEVPROP_MERGE_MULTISZ) {
  2808. CmFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ;
  2809. } else {
  2810. CmFlags = 0;
  2811. }
  2812. PropLength = PropertyBufferSize;
  2813. if(Ansi) {
  2814. cr = CM_Get_DevInst_Custom_Property_ExA(
  2815. DevInfoElem->DevInst,
  2816. CustomPropertyName,
  2817. PropertyRegDataType,
  2818. PropertyBuffer,
  2819. &PropLength,
  2820. CmFlags,
  2821. pDeviceInfoSet->hMachine
  2822. );
  2823. } else {
  2824. cr = CM_Get_DevInst_Custom_Property_ExW(
  2825. DevInfoElem->DevInst,
  2826. CustomPropertyName,
  2827. PropertyRegDataType,
  2828. PropertyBuffer,
  2829. &PropLength,
  2830. CmFlags,
  2831. pDeviceInfoSet->hMachine
  2832. );
  2833. }
  2834. if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
  2835. if(RequiredSize) {
  2836. *RequiredSize = PropLength;
  2837. }
  2838. }
  2839. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2840. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2841. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2842. }
  2843. UnlockDeviceInfoSet(pDeviceInfoSet);
  2844. return Err;
  2845. }
  2846. //
  2847. // Unicode version
  2848. //
  2849. BOOL
  2850. WINAPI
  2851. SetupDiGetCustomDevicePropertyW(
  2852. IN HDEVINFO DeviceInfoSet,
  2853. IN PSP_DEVINFO_DATA DeviceInfoData,
  2854. IN PCWSTR CustomPropertyName,
  2855. IN DWORD Flags,
  2856. OUT PDWORD PropertyRegDataType, OPTIONAL
  2857. OUT PBYTE PropertyBuffer,
  2858. IN DWORD PropertyBufferSize,
  2859. OUT PDWORD RequiredSize OPTIONAL
  2860. )
  2861. /*++
  2862. Routine Description:
  2863. This routine retrieves the data for the specified property, either from the
  2864. device information element's hardware key, or from the most-specific
  2865. per-hardware-id storage key containing that property.
  2866. Arguments:
  2867. DeviceInfoSet -- Supplies a handle to the device information set containing
  2868. information about the device instance to retrieve a Plug & Play
  2869. registry property for.
  2870. DeviceInfoData -- Supplies a pointer to a SP_DEVINFO_DATA structure
  2871. indicating the device instance to retrieve the Plug & Play registry
  2872. property for
  2873. CustomPropertyName - Supplies the name of the property to be retrieved.
  2874. Flags - Supplies flags controlling how the property data is to be
  2875. retrieved. May be a combination of the following values:
  2876. DICUSTOMDEVPROP_MERGE_MULTISZ : Merge the devnode-specific REG_SZ or
  2877. REG_MULTI_SZ property (if present) with
  2878. the per-hardware-id REG_SZ or
  2879. REG_MULTI_SZ property (if present).
  2880. The resultant data will always be a
  2881. multi-sz list.
  2882. PropertyRegDataType -- Optionally, supplies the address of a variable that
  2883. will receive the data type of the property being retrieved. This will
  2884. be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
  2885. PropertyBuffer -- Supplies the address of a buffer that receives the
  2886. property data.
  2887. PropertyBufferSize -- Supplies the length, in bytes, of PropertyBuffer.
  2888. RequiredSize -- Optionally, supplies the address of a variable that
  2889. receives the number of bytes required to store the requested property
  2890. in the buffer.
  2891. Return Value:
  2892. If the function succeeds, the return value is TRUE.
  2893. If the function fails, the return value is FALSE. To get extended error
  2894. information, call GetLastError. If the supplied buffer was not large
  2895. enough to hold the requested property, the error will be
  2896. ERROR_INSUFFICIENT_BUFFER and RequiredSize will specify how large the
  2897. buffer needs to be.
  2898. --*/
  2899. {
  2900. DWORD Err;
  2901. try {
  2902. Err = _SetupDiGetCustomDeviceProperty(DeviceInfoSet,
  2903. DeviceInfoData,
  2904. CustomPropertyName,
  2905. Flags,
  2906. PropertyRegDataType,
  2907. PropertyBuffer,
  2908. PropertyBufferSize,
  2909. RequiredSize,
  2910. FALSE // want Unicode results
  2911. );
  2912. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2913. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2914. }
  2915. SetLastError(Err);
  2916. return (Err == NO_ERROR);
  2917. }
  2918. //
  2919. // ANSI version
  2920. //
  2921. BOOL
  2922. WINAPI
  2923. SetupDiGetCustomDevicePropertyA(
  2924. IN HDEVINFO DeviceInfoSet,
  2925. IN PSP_DEVINFO_DATA DeviceInfoData,
  2926. IN PCSTR CustomPropertyName,
  2927. IN DWORD Flags,
  2928. OUT PDWORD PropertyRegDataType, OPTIONAL
  2929. OUT PBYTE PropertyBuffer,
  2930. IN DWORD PropertyBufferSize,
  2931. OUT PDWORD RequiredSize OPTIONAL
  2932. )
  2933. /*++
  2934. Routine Description:
  2935. (See SetupDiGetCustomDevicePropertyW)
  2936. --*/
  2937. {
  2938. DWORD Err;
  2939. try {
  2940. Err = _SetupDiGetCustomDeviceProperty(DeviceInfoSet,
  2941. DeviceInfoData,
  2942. CustomPropertyName,
  2943. Flags,
  2944. PropertyRegDataType,
  2945. PropertyBuffer,
  2946. PropertyBufferSize,
  2947. RequiredSize,
  2948. TRUE // want ANSI results
  2949. );
  2950. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2951. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2952. }
  2953. SetLastError(Err);
  2954. return (Err == NO_ERROR);
  2955. }