Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1604 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. reg.c
  5. Abstract:
  6. Implements utilities to parse a registry key string, and also implements
  7. wrappers to the registry API. There are four groups of APIs in this
  8. source file: enumerator functions, query functions, open and create
  9. functions, and registry string parsing functions.
  10. The enumerator functions allow simplified enumeration, where the caller
  11. typically allocates an enumeration structure on the stack and calls a
  12. registry enum API such as EnumFirstRegKeyStr. The caller then accesses
  13. the enumeration structure directly. The registry enumeration functions
  14. maintain a handle to the parent registry key, so remember to abort
  15. registry key enumeration if your code completes before all keys are
  16. enumerated.
  17. The query functions allow simplified querying, where the caller receives
  18. a MemAlloc'd pointer to the data and does not have to worry about managing
  19. the numerous parameters needed to do the query. The query functions
  20. also allow filtering of values that are not the expected type. All
  21. query functions have a version with 2 appended to the function name which
  22. allow the caller to specify an alternative allocator and deallocator.
  23. The open and create functions simplify the process of obtaining a key
  24. handle. They allow the caller to specify a key string as input and return
  25. the key handle as output.
  26. The registry string parsing functions are utilities that can be used when
  27. processing registry key strings. The functions extract the registry root
  28. from a string, convert it into a handle, convert a hive handle into a
  29. string, and so on.
  30. Author:
  31. Jim Schmidt (jimschm) 20-Mar-1997
  32. Revisions:
  33. jimschm 26-May-1999 Moved from win9xupg, gutted as well
  34. ovidiut 22-Feb-1999 Added GetRegSubkeysCount
  35. calinn 23-Sep-1998 Fixed REG_SZ filtering
  36. jimschm 25-Mar-1998 Added CreateEncodedRegistryStringEx
  37. jimschm 21-Oct-1997 Added EnumFirstKeyInTree/EnumNextKeyInTree
  38. marcw 16-Jul-1997 Added CreateEncodedRegistryString/FreeEncodedRegistryString
  39. jimschm 22-Jun-1997 Added GetRegData
  40. --*/
  41. #include "pch.h"
  42. REGSAM g_OpenSam = KEY_ALL_ACCESS;
  43. REGSAM g_CreateSam = KEY_ALL_ACCESS;
  44. //
  45. // Private prototypes
  46. //
  47. BOOL
  48. pPopRegKeyInfoW (
  49. IN PREGTREE_ENUMW EnumPtr
  50. );
  51. //
  52. // Implementation
  53. //
  54. PWSTR
  55. StringCopyABW (
  56. OUT PWSTR Buf,
  57. IN PCWSTR a,
  58. IN PCWSTR b
  59. )
  60. {
  61. PWSTR r = Buf;
  62. while (*a && a < b) {
  63. *Buf++ = *a++;
  64. }
  65. *Buf = 0;
  66. return r;
  67. }
  68. UINT
  69. SizeOfStringW (
  70. PCWSTR str
  71. )
  72. {
  73. return (lstrlenW(str) + 1) * sizeof(WCHAR);
  74. }
  75. PWSTR
  76. GetEndOfStringW (
  77. PCWSTR p
  78. )
  79. {
  80. while (*p) {
  81. p++;
  82. }
  83. return (PWSTR) p;
  84. }
  85. REGSAM
  86. SetRegOpenAccessMode (
  87. REGSAM Mode
  88. )
  89. {
  90. REGSAM OldMode;
  91. OldMode = g_OpenSam;
  92. g_OpenSam = Mode;
  93. return OldMode;
  94. }
  95. REGSAM
  96. GetRegOpenAccessMode (
  97. REGSAM Mode
  98. )
  99. {
  100. return g_OpenSam;
  101. }
  102. REGSAM
  103. SetRegCreateAccessMode (
  104. REGSAM Mode
  105. )
  106. {
  107. REGSAM OldMode;
  108. OldMode = g_CreateSam;
  109. g_CreateSam = Mode;
  110. return OldMode;
  111. }
  112. REGSAM
  113. GetRegCreateAccessMode (
  114. REGSAM Mode
  115. )
  116. {
  117. return g_CreateSam;
  118. }
  119. /*++
  120. Routine Description:
  121. EnumFirstRegKeyA and EnumFirstRegKeyW begin an enumeration of registry
  122. subkeys. They initialize the registy enumeration structure and
  123. call the registry APIs to enumerate subkeys of the specified key handle.
  124. Arguments:
  125. EnumPtr - Receives the updated state of enumeration. The structure
  126. can be accessed directly.
  127. Key - Specifies the handle of the registry key to enumerate.
  128. Return Value:
  129. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  130. Call GetLastError for the failure code.
  131. --*/
  132. BOOL
  133. EnumFirstRegKeyW (
  134. OUT PREGKEY_ENUMW EnumPtr,
  135. IN HKEY hKey
  136. )
  137. {
  138. ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMW));
  139. EnumPtr->KeyHandle = hKey;
  140. return EnumNextRegKeyW (EnumPtr);
  141. }
  142. /*++
  143. Routine Description:
  144. CreateRegKeyA and CreateRegKeyW create a subkey if it does not
  145. exist already, or open a subkey if it already exists.
  146. Arguments:
  147. ParentKey - Specifies a handle to the parent registry key to contain
  148. the new key.
  149. NewKeyName - Specifies the name of the subkey to create or open.
  150. Return Value:
  151. The handle to an open registry key upon success, or NULL if an
  152. error occurred. Call GetLastError for a failure code.
  153. --*/
  154. HKEY
  155. RealCreateRegKeyW (
  156. IN HKEY ParentKey,
  157. IN PCWSTR NewKeyName
  158. )
  159. {
  160. LONG rc;
  161. HKEY SubKey;
  162. DWORD DontCare;
  163. rc = RegCreateKeyExW (
  164. ParentKey,
  165. NewKeyName,
  166. 0,
  167. NULL,
  168. 0,
  169. g_CreateSam,
  170. NULL,
  171. &SubKey,
  172. &DontCare
  173. );
  174. if (rc != ERROR_SUCCESS) {
  175. SetLastError (rc);
  176. return NULL;
  177. }
  178. return SubKey;
  179. }
  180. /*++
  181. Routine Description:
  182. CreateRegKeyStrA and CreateRegKeyStrW create a subkey if it does not
  183. exist already, or open a subkey if it already exists.
  184. Arguments:
  185. NewKeyName - Specifies the full path to the key to create or open.
  186. Return Value:
  187. The handle to an open registry key upon success, or NULL if an
  188. error occurred. Call GetLastError for a failure code.
  189. --*/
  190. HKEY
  191. RealCreateRegKeyStrW (
  192. IN PCWSTR NewKeyName
  193. )
  194. {
  195. LONG rc;
  196. DWORD DontCare;
  197. WCHAR RegKey[MAX_PATH];
  198. PCWSTR Start;
  199. PCWSTR End;
  200. HKEY Parent, NewKey;
  201. BOOL CloseParent = FALSE;
  202. DWORD EndPos;
  203. //
  204. // Get the root
  205. //
  206. Parent = ConvertRootStringToKeyW (NewKeyName, &EndPos);
  207. if (!Parent) {
  208. return NULL;
  209. }
  210. Start = &NewKeyName[EndPos];
  211. if (!(*Start)) {
  212. return Parent;
  213. }
  214. //
  215. // Create each node until entire key exists
  216. //
  217. NewKey = NULL;
  218. do {
  219. //
  220. // Find end of this node
  221. //
  222. End = wcschr (Start, '\\');
  223. if (!End) {
  224. End = GetEndOfStringW (Start);
  225. }
  226. StringCopyABW (RegKey, Start, End);
  227. //
  228. // Try to open the key (unless it's the last in the string)
  229. //
  230. if (*End) {
  231. rc = RegOpenKeyExW (
  232. Parent,
  233. RegKey,
  234. 0,
  235. KEY_READ|KEY_CREATE_SUB_KEY,
  236. &NewKey
  237. );
  238. if (rc != ERROR_SUCCESS) {
  239. NewKey = NULL;
  240. }
  241. } else {
  242. NewKey = NULL;
  243. }
  244. //
  245. // If open failed, create the key
  246. //
  247. if (NewKey) {
  248. rc = ERROR_SUCCESS;
  249. } else {
  250. rc = RegCreateKeyExW (
  251. Parent,
  252. RegKey,
  253. 0,
  254. NULL,
  255. 0,
  256. g_CreateSam,
  257. NULL,
  258. &NewKey,
  259. &DontCare
  260. );
  261. }
  262. if (CloseParent) {
  263. CloseRegKey (Parent);
  264. }
  265. if (rc != ERROR_SUCCESS) {
  266. SetLastError (rc);
  267. return NULL;
  268. }
  269. Parent = NewKey;
  270. CloseParent = TRUE;
  271. //
  272. // Go to next node
  273. //
  274. Start = End;
  275. if (*Start) {
  276. Start++;
  277. }
  278. } while (*Start);
  279. return Parent;
  280. }
  281. /*++
  282. Routine Description:
  283. OpenRegKeyStrA and OpenRegKeyStrW parse a text string that specifies a
  284. registry key into the hive and subkey, and then they open the subkey
  285. and return the handle.
  286. Arguments:
  287. RegKey - Specifies the complete path to the registry subkey, including
  288. the hive.
  289. Return Value:
  290. A non-NULL registry handle if successful, or NULL if either the subkey
  291. could not be opened or the string is malformed.
  292. --*/
  293. HKEY
  294. RealOpenRegKeyStrW (
  295. IN PCWSTR RegKey
  296. )
  297. {
  298. DWORD End;
  299. HKEY RootKey;
  300. HKEY Key;
  301. RootKey = ConvertRootStringToKeyW (RegKey, &End);
  302. if (!RootKey) {
  303. return NULL;
  304. }
  305. if (!RegKey[End]) {
  306. return RootKey;
  307. }
  308. Key = RealOpenRegKeyW (RootKey, &RegKey[End]);
  309. return Key;
  310. }
  311. /*++
  312. Routine Description:
  313. EnumFirstRegKeyStrA and EnumFirstRegKeyStrW start an enumeration of
  314. subkeys within the given key. In these functions, the key is specified
  315. via a string instead of an HKEY value.
  316. Arguments:
  317. EnumPtr - Receives the updated state of enumeration. The structure
  318. can be accessed directly.
  319. RegKey - Specifies the full path of the registry key to enumerate.
  320. Return Value:
  321. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  322. Call GetLastError for the failure code.
  323. --*/
  324. BOOL
  325. RealEnumFirstRegKeyStrW (
  326. IN PREGKEY_ENUMW EnumPtr,
  327. IN PCWSTR RegKey
  328. )
  329. {
  330. HKEY Key;
  331. BOOL b;
  332. Key = RealOpenRegKeyStrW (RegKey);
  333. if (!Key) {
  334. return FALSE;
  335. }
  336. b = EnumFirstRegKeyW (EnumPtr, Key);
  337. if (!b) {
  338. CloseRegKey (Key);
  339. } else {
  340. EnumPtr->OpenedByEnum = TRUE;
  341. }
  342. return b;
  343. }
  344. /*++
  345. Routine Description:
  346. AbortRegKeyEnumA and AbortRegKeyEnumW release all resources associated
  347. with a registry subkey enumeration. Call this function to stop the
  348. enumeration before it completes by itself.
  349. Arguments:
  350. EnumPtr - Specifies the enumeration to stop. Receives the updated
  351. state of enumeration.
  352. Return Value:
  353. none
  354. --*/
  355. VOID
  356. AbortRegKeyEnumW (
  357. IN OUT PREGKEY_ENUMW EnumPtr
  358. )
  359. {
  360. if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
  361. CloseRegKey (EnumPtr->KeyHandle);
  362. EnumPtr->KeyHandle = NULL;
  363. }
  364. }
  365. /*++
  366. Routine Description:
  367. EnumNextRegKeyA and EnumNextRegKeyW continue an enumeration started by
  368. one of the subkey enumeration routines above. If all items have been
  369. enumerated, this function cleans up all resources and returns FALSE.
  370. Arguments:
  371. EnumPtr - Specifies the enumeration to continue. Receives the updated
  372. state of enumeration. The structure can be accessed directly.
  373. Return Value:
  374. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  375. Call GetLastError for the failure code.
  376. --*/
  377. BOOL
  378. EnumNextRegKeyW (
  379. IN OUT PREGKEY_ENUMW EnumPtr
  380. )
  381. {
  382. LONG rc;
  383. rc = RegEnumKeyW (
  384. EnumPtr->KeyHandle,
  385. EnumPtr->Index,
  386. EnumPtr->SubKeyName,
  387. MAX_PATH
  388. );
  389. if (rc != ERROR_SUCCESS) {
  390. if (EnumPtr->OpenedByEnum) {
  391. CloseRegKey (EnumPtr->KeyHandle);
  392. EnumPtr->KeyHandle = NULL;
  393. }
  394. if (rc == ERROR_NO_MORE_ITEMS) {
  395. SetLastError (ERROR_SUCCESS);
  396. } else {
  397. SetLastError (rc);
  398. }
  399. return FALSE;
  400. }
  401. EnumPtr->Index += 1;
  402. return TRUE;
  403. }
  404. BOOL
  405. pPushRegKeyInfoW (
  406. IN PREGTREE_ENUMW EnumPtr,
  407. IN PCWSTR KeyName
  408. )
  409. {
  410. PREGKEYINFOW RetVal;
  411. PWSTR p;
  412. RetVal = (PREGKEYINFOW) PoolMemGetAlignedMemory (
  413. EnumPtr->EnumPool,
  414. sizeof (REGKEYINFOW)
  415. );
  416. if (!RetVal) {
  417. return FALSE;
  418. }
  419. //
  420. // Initialize struct to zero
  421. //
  422. ZeroMemory (RetVal, sizeof (REGKEYINFOW));
  423. //
  424. // Link parent and child pointers
  425. //
  426. RetVal->Parent = EnumPtr->CurrentKey;
  427. if (EnumPtr->CurrentKey) {
  428. EnumPtr->CurrentKey->Child = RetVal;
  429. }
  430. EnumPtr->CurrentKey = RetVal;
  431. //
  432. // Prepare full key path by appending the key name to the existing
  433. // base
  434. //
  435. RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
  436. p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
  437. if (EnumPtr->FullKeyNameBytes) {
  438. lstrcpyW (p, L"\\");
  439. EnumPtr->FullKeyNameBytes += ByteCountW (p);
  440. p++;
  441. }
  442. lstrcpynW (p, KeyName, MAX_PATH - (EnumPtr->FullKeyNameBytes / sizeof (WCHAR)));
  443. EnumPtr->FullKeyNameBytes += ByteCountW (KeyName);
  444. //
  445. // Save the key name independent of the full registry path.
  446. // Also open the key.
  447. //
  448. lstrcpynW (RetVal->KeyName, KeyName, MAX_PATH);
  449. RetVal->KeyHandle = OpenRegKeyStrW (EnumPtr->FullKeyName);
  450. if (!RetVal->KeyHandle) {
  451. pPopRegKeyInfoW (EnumPtr);
  452. return FALSE;
  453. }
  454. return TRUE;
  455. }
  456. BOOL
  457. pPopRegKeyInfoW (
  458. IN PREGTREE_ENUMW EnumPtr
  459. )
  460. {
  461. PREGKEYINFOW FreeMe;
  462. PWSTR p;
  463. FreeMe = EnumPtr->CurrentKey;
  464. //
  465. // Skip if nothing was ever pushed
  466. //
  467. if (!FreeMe) {
  468. return FALSE;
  469. }
  470. //
  471. // Trim the full key string
  472. //
  473. EnumPtr->CurrentKey = FreeMe->Parent;
  474. EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
  475. p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
  476. *p = 0;
  477. //
  478. // Adjust the linkage
  479. //
  480. if (EnumPtr->CurrentKey) {
  481. EnumPtr->CurrentKey->Child = NULL;
  482. }
  483. //
  484. // Clean up resources
  485. //
  486. if (FreeMe->KeyHandle) {
  487. CloseRegKey (FreeMe->KeyHandle);
  488. }
  489. AbortRegKeyEnumW (&FreeMe->KeyEnum);
  490. PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
  491. //
  492. // Return FALSE if last item was poped
  493. //
  494. return EnumPtr->CurrentKey != NULL;
  495. }
  496. BOOL
  497. RealEnumFirstRegKeyInTreeW (
  498. OUT PREGTREE_ENUMW EnumPtr,
  499. IN PCWSTR BaseKeyStr
  500. )
  501. {
  502. ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMW));
  503. //
  504. // Allocate pool for enum structs
  505. //
  506. EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTreeW");
  507. if (!EnumPtr->EnumPool) {
  508. return FALSE;
  509. }
  510. PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
  511. //
  512. // Push base key on the enum stack
  513. //
  514. if (!pPushRegKeyInfoW (EnumPtr, BaseKeyStr)) {
  515. AbortRegKeyTreeEnumW (EnumPtr);
  516. return FALSE;
  517. }
  518. EnumPtr->EnumBaseBytes = ByteCountW (BaseKeyStr);
  519. //
  520. // Set state so EnumNextRegKeyInTree knows what to do
  521. //
  522. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  523. return TRUE;
  524. }
  525. BOOL
  526. RealEnumNextRegKeyInTreeW (
  527. IN OUT PREGTREE_ENUMW EnumPtr
  528. )
  529. {
  530. if (EnumPtr->State == NO_MORE_ITEMS) {
  531. return FALSE;
  532. }
  533. for (;;) {
  534. switch (EnumPtr->State) {
  535. case ENUMERATE_SUBKEY_BEGIN:
  536. //
  537. // Start enumeration
  538. //
  539. if (EnumFirstRegKeyW (
  540. &EnumPtr->CurrentKey->KeyEnum,
  541. EnumPtr->CurrentKey->KeyHandle
  542. )) {
  543. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  544. } else {
  545. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  546. }
  547. break;
  548. case ENUMERATE_SUBKEY_NEXT:
  549. //
  550. // Continue enumerations
  551. //
  552. if (EnumNextRegKeyW (&EnumPtr->CurrentKey->KeyEnum)) {
  553. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  554. } else {
  555. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  556. }
  557. break;
  558. case ENUMERATE_SUBKEY_DONE:
  559. //
  560. // Enumeration of this key is done; pop and continue.
  561. //
  562. if (!pPopRegKeyInfoW (EnumPtr)) {
  563. EnumPtr->State = NO_MORE_ITEMS;
  564. AbortRegKeyTreeEnumW (EnumPtr);
  565. } else {
  566. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  567. }
  568. break;
  569. case ENUMERATE_SUBKEY_RETURN:
  570. //
  571. // Return enumerated item to caller
  572. //
  573. if (!pPushRegKeyInfoW (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
  574. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  575. break;
  576. }
  577. if (!EnumPtr->FirstEnumerated) {
  578. EnumPtr->FirstEnumerated = TRUE;
  579. EnumPtr->EnumBaseBytes += sizeof (WCHAR);
  580. }
  581. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  582. return TRUE;
  583. default:
  584. return FALSE;
  585. }
  586. }
  587. }
  588. VOID
  589. AbortRegKeyTreeEnumW (
  590. IN OUT PREGTREE_ENUMW EnumPtr
  591. )
  592. {
  593. //
  594. // Free all resources
  595. //
  596. while (pPopRegKeyInfoW (EnumPtr)) {
  597. }
  598. PoolMemDestroyPool (EnumPtr->EnumPool);
  599. }
  600. /*++
  601. Routine Description:
  602. EnumFirstRegValueA and EnumerateFirstRegvalueW enumerate the first registry
  603. value name in the specified subkey.
  604. Arguments:
  605. EnumPtr - Receives the updated state of enumeration. The structure
  606. can be accessed directly.
  607. hKey - Specifies handle of registry subkey to enumerate.
  608. Return Value:
  609. TRUE if successful, or FALSE if an error or if no more values are available.
  610. Call GetLastError for the failure code.
  611. --*/
  612. BOOL
  613. EnumFirstRegValueW (
  614. IN PREGVALUE_ENUMW EnumPtr,
  615. IN HKEY hKey
  616. )
  617. {
  618. ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMW));
  619. EnumPtr->KeyHandle = hKey;
  620. return EnumNextRegValueW (EnumPtr);
  621. }
  622. /*++
  623. Routine Description:
  624. EnumNextRegValueA and EnumNextRegValueW continue the enumeration started
  625. by EnumFirstRegValueA/W. The enumeration structure is updated to
  626. reflect the next value name in the subkey being enumerated.
  627. Arguments:
  628. EnumPtr - Specifies the registry subkey and enumeration position.
  629. Receives the updated state of enumeration. The structure
  630. can be accessed directly.
  631. Return Value:
  632. TRUE if successful, or FALSE if an error or if no more values are available.
  633. Call GetLastError for the failure code.
  634. --*/
  635. BOOL
  636. EnumNextRegValueW (
  637. IN OUT PREGVALUE_ENUMW EnumPtr
  638. )
  639. {
  640. LONG rc;
  641. DWORD ValueNameSize;
  642. ValueNameSize = MAX_PATH;
  643. rc = RegEnumValueW (
  644. EnumPtr->KeyHandle,
  645. EnumPtr->Index,
  646. EnumPtr->ValueName,
  647. &ValueNameSize,
  648. NULL,
  649. &EnumPtr->Type,
  650. NULL,
  651. &EnumPtr->DataSize
  652. );
  653. if (rc == ERROR_NO_MORE_ITEMS) {
  654. SetLastError (ERROR_SUCCESS);
  655. return FALSE;
  656. } else if (rc != ERROR_SUCCESS) {
  657. SetLastError (rc);
  658. return FALSE;
  659. }
  660. EnumPtr->Index += 1;
  661. return TRUE;
  662. }
  663. PVOID
  664. MemAllocWrapper (
  665. IN DWORD Size
  666. )
  667. /*++
  668. Routine Description:
  669. pemAllocWrapper implements a default allocation routine. The APIs
  670. that have a "2" at the end allow the caller to supply an alternative
  671. allocator or deallocator. The routines without the "2" use this
  672. default allocator.
  673. Arguments:
  674. Size - Specifies the amount of memory (in bytes) to allocate
  675. Return Value:
  676. A pointer to a block of memory that can hold Size bytes, or NULL
  677. if allocation fails.
  678. --*/
  679. {
  680. return MemAlloc (Size);
  681. }
  682. VOID
  683. MemFreeWrapper (
  684. IN PVOID Mem
  685. )
  686. /*++
  687. Routine Description:
  688. MemFreeWrapper implements a default deallocation routine.
  689. See MemAllocWrapper above.
  690. Arguments:
  691. Mem - Specifies the block of memory to free, and was allocated by the
  692. MemAllocWrapper function.
  693. Return Value:
  694. none
  695. --*/
  696. {
  697. MemFree (Mem);
  698. }
  699. /*++
  700. Routine Description:
  701. GetRegValueData2A and GetRegValueData2W query a registry value and
  702. return the data as a pointer. They use the specified Alloc and Free
  703. routines to allocate and free the memory as needed.
  704. A GetRegValueData macro is defined, and it uses the default allocators,
  705. simplifying the function parameters and allowing the caller to free
  706. the return value via MemFree.
  707. Arguments:
  708. hKey - Specifies the registry key that holds the specified value.
  709. Value - Specifies the value name to query.
  710. Alloc - Specifies the allocation routine, called to allocate a block of
  711. memory for the return data.
  712. Free - Specifies the deallocation routine, called if an error is encountered
  713. during processing.
  714. Return Value:
  715. A pointer to the data retrieved, or NULL if the value does not exist or an
  716. error occurred. Call GetLastError to obtian the failure code.
  717. --*/
  718. PBYTE
  719. GetRegValueData2W (
  720. IN HKEY hKey,
  721. IN PCWSTR Value,
  722. IN ALLOCATOR Alloc,
  723. IN DEALLOCATOR Free
  724. )
  725. {
  726. LONG rc;
  727. DWORD BufSize;
  728. PBYTE DataBuf;
  729. rc = RegQueryValueExW (hKey, Value, NULL, NULL, NULL, &BufSize);
  730. if (rc != ERROR_SUCCESS) {
  731. SetLastError (rc);
  732. return NULL;
  733. }
  734. DataBuf = (PBYTE) Alloc (BufSize + sizeof(WCHAR));
  735. rc = RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  736. if (rc == ERROR_SUCCESS) {
  737. *((PWSTR) (DataBuf + BufSize)) = 0;
  738. return DataBuf;
  739. }
  740. Free (DataBuf);
  741. SetLastError (rc);
  742. return NULL;
  743. }
  744. /*++
  745. Routine Description:
  746. GetRegValueDataOfType2A and GetRegValueDataOfType2W are extensions of
  747. GetRegValueData. They only return a data pointer when the data stored
  748. in the registry value is the correct type.
  749. Arguments:
  750. hKey - Specifies the registry key to query
  751. Value - Specifies the value name to query
  752. MustBeType - Specifies the type of data (a REG_* constant). If the specified
  753. value has data but is a different type, NULL will be returned.
  754. Alloc - Specifies the allocation routine, called to allocate the return data.
  755. Free - Specifies the deallocation routine, called when an error is encountered.
  756. Return Value:
  757. If successful, returns a pointer to data that matches the specified type.
  758. If the data is a different type, the value name does not exist, or an
  759. error occurs during the query, NULL is returned, and the failure code
  760. can be obtained from GetLastError.
  761. --*/
  762. PBYTE
  763. GetRegValueDataOfType2W (
  764. IN HKEY hKey,
  765. IN PCWSTR Value,
  766. IN DWORD MustBeType,
  767. IN ALLOCATOR Alloc,
  768. IN DEALLOCATOR Free
  769. )
  770. {
  771. LONG rc;
  772. DWORD BufSize;
  773. PBYTE DataBuf;
  774. DWORD Type;
  775. rc = RegQueryValueExW (hKey, Value, NULL, &Type, NULL, &BufSize);
  776. if (rc != ERROR_SUCCESS) {
  777. SetLastError (rc);
  778. return NULL;
  779. }
  780. switch (MustBeType) {
  781. case REG_SZ:
  782. case REG_EXPAND_SZ:
  783. if (Type == REG_SZ) break;
  784. if (Type == REG_EXPAND_SZ) break;
  785. return NULL;
  786. case REG_DWORD:
  787. case REG_DWORD_BIG_ENDIAN:
  788. if (Type == REG_DWORD) break;
  789. if (Type == REG_DWORD_BIG_ENDIAN) break;
  790. return NULL;
  791. default:
  792. if (Type == MustBeType) break;
  793. return NULL;
  794. }
  795. DataBuf = (PBYTE) Alloc (BufSize + sizeof(WCHAR));
  796. rc = RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  797. if (rc == ERROR_SUCCESS) {
  798. *((PWSTR) (DataBuf + BufSize)) = 0;
  799. return DataBuf;
  800. }
  801. Free (DataBuf);
  802. SetLastError (rc);
  803. return NULL;
  804. }
  805. BOOL
  806. GetRegValueTypeAndSizeW (
  807. IN HKEY Key,
  808. IN PCWSTR ValueName,
  809. OUT PDWORD OutType, OPTIONAL
  810. OUT PDWORD OutSize OPTIONAL
  811. )
  812. {
  813. LONG rc;
  814. DWORD Type;
  815. DWORD Size;
  816. rc = RegQueryValueExW (Key, ValueName, NULL, &Type, NULL, &Size);
  817. if (rc == ERROR_SUCCESS) {
  818. if (OutType) {
  819. *OutType = Type;
  820. }
  821. if (OutSize) {
  822. *OutSize = Size;
  823. }
  824. return TRUE;
  825. }
  826. return FALSE;
  827. }
  828. /*++
  829. Routine Description:
  830. GetRegKeyData2A and GetRegKeyData2W return default data associated
  831. with a registry key. They open the specified subkey, query the value,
  832. close the subkey and return the data.
  833. Arguments:
  834. Parent - Specifies the key that contains SubKey.
  835. SubKey - Specifies the name of the subkey to obtain the default value for.
  836. Alloc - Specifies the allocation routine, called to allocate a block of
  837. memory for the registry data.
  838. Free - Specifies the deallocation routine, called to free the block of
  839. data if an error occurs.
  840. Return Value:
  841. A pointer to the block of data obtained from the subkey's default value,
  842. or NULL if the subkey does not exist or an error was encountered. Call
  843. GetLastError for a failure code.
  844. --*/
  845. PBYTE
  846. GetRegKeyData2W (
  847. IN HKEY Parent,
  848. IN PCWSTR SubKey,
  849. IN ALLOCATOR Alloc,
  850. IN DEALLOCATOR Free
  851. )
  852. {
  853. HKEY SubKeyHandle;
  854. PBYTE Data;
  855. SubKeyHandle = OpenRegKeyW (Parent, SubKey);
  856. if (!SubKeyHandle) {
  857. return NULL;
  858. }
  859. Data = GetRegValueData2W (SubKeyHandle, L"", Alloc, Free);
  860. CloseRegKey (SubKeyHandle);
  861. return Data;
  862. }
  863. /*++
  864. Routine Description:
  865. GetRegData2A and GetRegData2W open a registry key, query a value,
  866. close the registry key and return the value.
  867. Arguments:
  868. KeyString - Specifies the registry key to open
  869. ValueName - Specifies the value to query
  870. Alloc - Specifies the allocation routine, used to allocate a block of
  871. memory to hold the value data
  872. Free - Specifies the deallocation routine, used to free the block of
  873. memory when an error is encountered.
  874. Return Value:
  875. A pointer to the registry data retrieved, or NULL if the key or value
  876. does not exist, or if an error occurs. Call GetLastError for a failure code.
  877. --*/
  878. PBYTE
  879. GetRegData2W (
  880. IN PCWSTR KeyString,
  881. IN PCWSTR ValueName,
  882. IN ALLOCATOR Alloc,
  883. IN DEALLOCATOR Free
  884. )
  885. {
  886. HKEY Key;
  887. PBYTE Data;
  888. Key = OpenRegKeyStrW (KeyString);
  889. if (!Key) {
  890. return NULL;
  891. }
  892. Data = GetRegValueData2W (Key, ValueName, Alloc, Free);
  893. CloseRegKey (Key);
  894. return Data;
  895. }
  896. BOOL
  897. GetRegSubkeysCount (
  898. IN HKEY ParentKey,
  899. OUT PDWORD SubKeyCount, OPTIONAL
  900. OUT PDWORD MaxSubKeyLen OPTIONAL
  901. )
  902. /*++
  903. Routine Description:
  904. GetRegSubkeysCount retrieves the number of subkeys of a given parent key.
  905. Arguments:
  906. ParentKey - Specifies a handle to the parent registry key.
  907. SubKeyCount - Receives the number of subkeys
  908. MaxSubKeyLen - Receives the length, in chars, of the longest subkey string
  909. Return Value:
  910. TRUE if the count was retrieved successfully, FALSE otherwise.
  911. In this case, call GetLastError for a failure code.
  912. --*/
  913. {
  914. LONG rc;
  915. rc = RegQueryInfoKey (
  916. ParentKey,
  917. NULL,
  918. NULL,
  919. NULL,
  920. SubKeyCount,
  921. MaxSubKeyLen,
  922. NULL,
  923. NULL,
  924. NULL,
  925. NULL,
  926. NULL,
  927. NULL
  928. );
  929. if (rc != ERROR_SUCCESS) {
  930. return FALSE;
  931. }
  932. return TRUE;
  933. }
  934. /*++
  935. Routine Description:
  936. OpenRegKeyA and OpenRegKeyW open a subkey.
  937. Arguments:
  938. ParentKey - Specifies a handle to the parent registry key to contain
  939. the subkey.
  940. KeyToOpen - Specifies the name of the subkey to open.
  941. Return Value:
  942. The handle to an open registry key upon success, or NULL if an
  943. error occurred. Call GetLastError for a failure code.
  944. --*/
  945. HKEY
  946. RealOpenRegKeyW (
  947. IN HKEY ParentKey,
  948. IN PCWSTR KeyToOpen
  949. )
  950. {
  951. LONG rc;
  952. HKEY SubKey;
  953. rc = RegOpenKeyExW (
  954. ParentKey,
  955. KeyToOpen,
  956. 0,
  957. g_OpenSam,
  958. &SubKey
  959. );
  960. if (rc != ERROR_SUCCESS) {
  961. SetLastError (rc);
  962. return NULL;
  963. }
  964. return SubKey;
  965. }
  966. LONG
  967. RealCloseRegKey (
  968. IN HKEY Key
  969. )
  970. /*++
  971. Routine Description:
  972. RealCloseRegKey closes the reg handle supplied, unless the handle is
  973. a pre-defined Win32 handle. The CloseRegKey macro resolves directly
  974. to this function in the free build, and to OurCloseRegKey in the
  975. checked build.
  976. Arguments:
  977. Key - Specifies the reg handle to close
  978. Return Value:
  979. A standard Win32 error code indicating outcome.
  980. --*/
  981. {
  982. LONG rc = ERROR_INVALID_HANDLE;
  983. if (!Key) {
  984. return ERROR_SUCCESS;
  985. }
  986. if (GetOffsetOfRootKey (Key)) {
  987. return ERROR_SUCCESS;
  988. }
  989. __try {
  990. rc = RegCloseKey (Key);
  991. }
  992. __except (TRUE) {
  993. }
  994. return rc;
  995. }
  996. /*++
  997. Routine Description:
  998. GetOffsetOfRootString returns a non-zero offset to the g_RegRoots table
  999. below. The offset can be used with GetRootStringFromOffset and
  1000. GetRootKeyFromOffset.
  1001. Arguments:
  1002. RootString - A pointer to a string containing the path to a registry key
  1003. LengthPtr - A pointer to a variable that receives the length of the
  1004. registry root, including the joining backslash if it exists.
  1005. Return Value:
  1006. A non-zero offset to the g_RegRoots table, or zero if RootString does not
  1007. contain a registry root.
  1008. --*/
  1009. typedef struct {
  1010. PCSTR RootText;
  1011. PCWSTR WideRootText;
  1012. INT TextLength;
  1013. HKEY RootKey;
  1014. } REGISTRYROOT, *PREGISTRYROOT;
  1015. static
  1016. REGISTRYROOT g_RegRoots[] = {
  1017. "HKLM", L"HKLM", 4, HKEY_LOCAL_MACHINE,
  1018. "HKEY_LOCAL_MACHINE", L"HKEY_LOCAL_MACHINE", 18, HKEY_LOCAL_MACHINE,
  1019. "HKU", L"HKU", 3, HKEY_USERS,
  1020. "HKEY_USERS", L"HKEY_USERS", 10, HKEY_USERS,
  1021. "HKCU", L"HKCU", 4, HKEY_CURRENT_USER,
  1022. "HKEY_CURRENT_USER", L"HKEY_CURRENT_USER", 17, HKEY_CURRENT_USER,
  1023. "HKCC", L"HKCC", 4, HKEY_CURRENT_CONFIG,
  1024. "HKEY_CURRENT_CONFIG", L"HKEY_CURRENT_CONFIG", 19, HKEY_CURRENT_CONFIG,
  1025. "HKCR", L"HKCR", 4, HKEY_CLASSES_ROOT,
  1026. "HKEY_CLASSES_ROOT", L"HKEY_CLASSES_ROOT", 17, HKEY_CLASSES_ROOT,
  1027. "HKDD", L"HKDD", 4, HKEY_DYN_DATA,
  1028. "HKEY_DYN_DATA", L"HKEY_DYN_DATA", 13, HKEY_DYN_DATA,
  1029. NULL, NULL, 0, NULL
  1030. };
  1031. #define REGROOTS 14
  1032. INT
  1033. GetOffsetOfRootStringW (
  1034. IN PCWSTR RootString,
  1035. OUT PDWORD LengthPtr OPTIONAL
  1036. )
  1037. {
  1038. int i;
  1039. WCHAR c;
  1040. for (i = 0 ; g_RegRoots[i].RootText ; i++) {
  1041. if (!_wcsnicmp (RootString, g_RegRoots[i].WideRootText,
  1042. g_RegRoots[i].TextLength)
  1043. ) {
  1044. c = RootString[g_RegRoots[i].TextLength];
  1045. if (c && c != L'\\') {
  1046. continue;
  1047. }
  1048. if (LengthPtr) {
  1049. *LengthPtr = g_RegRoots[i].TextLength;
  1050. if (c) {
  1051. *LengthPtr += 1;
  1052. }
  1053. }
  1054. return i + 1;
  1055. }
  1056. }
  1057. return 0;
  1058. }
  1059. /*++
  1060. Routine Description:
  1061. GetOffsetOfRootKey returns a non-zero offset to the g_RegRoots table
  1062. corresponding to the root that matches the supplied HKEY. This offset
  1063. can be used with GetRootStringFromOffset and GetRootKeyFromOffset.
  1064. Arguments:
  1065. RootKey - Supplies the handle to locate in g_RegRoots table
  1066. Return Value:
  1067. A non-zero offset to the g_RegRoots table, or zero if the handle is not
  1068. a registry root.
  1069. --*/
  1070. INT
  1071. GetOffsetOfRootKey (
  1072. IN HKEY RootKey
  1073. )
  1074. {
  1075. INT i;
  1076. for (i = 0 ; g_RegRoots[i].RootText ; i++) {
  1077. if (g_RegRoots[i].RootKey == RootKey) {
  1078. return i + 1;
  1079. }
  1080. }
  1081. return 0;
  1082. }
  1083. /*++
  1084. Routine Description:
  1085. GetRootStringFromOffset and GetRootKeyFromOffset return a pointer to a
  1086. static string or HKEY, respectively. If the offset supplied is invalid,
  1087. these functions return NULL.
  1088. Arguments:
  1089. i - The offset as returned by GetOffsetOfRootString or GetOffsetOfRootKey
  1090. Return Value:
  1091. A pointer to a static string/HKEY, or NULL if offset is invalid
  1092. --*/
  1093. PCSTR
  1094. GetRootStringFromOffsetA (
  1095. IN INT i
  1096. )
  1097. {
  1098. if (i < 1 || i > REGROOTS) {
  1099. return NULL;
  1100. }
  1101. return g_RegRoots[i - 1].RootText;
  1102. }
  1103. PCWSTR
  1104. GetRootStringFromOffsetW (
  1105. IN INT i
  1106. )
  1107. {
  1108. if (i < 1 || i > REGROOTS) {
  1109. return NULL;
  1110. }
  1111. return g_RegRoots[i - 1].WideRootText;
  1112. }
  1113. HKEY
  1114. GetRootKeyFromOffset (
  1115. IN INT i
  1116. )
  1117. {
  1118. if (i < 1 || i > REGROOTS) {
  1119. return NULL;
  1120. }
  1121. return g_RegRoots[i - 1].RootKey;
  1122. }
  1123. /*++
  1124. Routine Description:
  1125. ConvertRootStringToKey converts a registry key path's root to an HKEY.
  1126. Arguments:
  1127. RegPath - A pointer to a registry string that has a root at the begining
  1128. LengthPtr - An optional pointer to a variable that receives the length of
  1129. the root, including the joining backslash if it exists.
  1130. Return Value:
  1131. A handle to the registry key, or NULL if RegPath does not have a root
  1132. --*/
  1133. HKEY
  1134. ConvertRootStringToKeyW (
  1135. PCWSTR RegPath,
  1136. PDWORD LengthPtr OPTIONAL
  1137. )
  1138. {
  1139. return GetRootKeyFromOffset (GetOffsetOfRootStringW (RegPath, LengthPtr));
  1140. }
  1141. /*++
  1142. Routine Description:
  1143. ConvertKeyToRootString converts a root HKEY to a registry root string
  1144. Arguments:
  1145. RegRoot - A handle to a registry root
  1146. Return Value:
  1147. A pointer to a static string, or NULL if RegRoot is not a valid registry
  1148. root handle
  1149. --*/
  1150. PCWSTR
  1151. ConvertKeyToRootStringW (
  1152. HKEY RegRoot
  1153. )
  1154. {
  1155. return GetRootStringFromOffsetW (GetOffsetOfRootKey (RegRoot));
  1156. }