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.

2134 lines
45 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 three groups of APIs in this
  8. source file: query functions, open and create functions, and registry
  9. string parsing functions.
  10. The query functions allow simplified querying, where the caller receives
  11. a MemAlloc'd pointer to the data and does not have to worry about managing
  12. the numerous parameters needed to do the query. The query functions
  13. also allow filtering of values that are not the expected type. All
  14. query functions have a version with 2 appended to the function name which
  15. allow the caller to specify an alternative allocator and deallocator.
  16. The open and create functions simplify the process of obtaining a key
  17. handle. They allow the caller to specify a key string as input and return
  18. the key handle as output.
  19. The registry string parsing functions are utilities that can be used when
  20. processing registry key strings. The functions extract the registry root
  21. from a string, convert it into a handle, convert a hive handle into a
  22. string, and so on.
  23. Author:
  24. Jim Schmidt (jimschm) 20-Mar-1997
  25. Revisions:
  26. jimschm 18-Sep-2000 Added cache
  27. ovidiut 22-Feb-1999 Added GetRegSubkeysCount
  28. calinn 23-Sep-1998 Fixed REG_SZ filtering
  29. jimschm 25-Mar-1998 Added CreateEncodedRegistryStringEx
  30. jimschm 21-Oct-1997 Added EnumFirstKeyInTree/EnumNextKeyInTree
  31. marcw 16-Jul-1997 Added CreateEncodedRegistryString/FreeEncodedRegistryString
  32. jimschm 22-Jun-1997 Added GetRegData
  33. --*/
  34. #include "pch.h"
  35. #include "migutilp.h"
  36. #include "regp.h"
  37. #ifdef DEBUG
  38. #undef RegCloseKey
  39. #endif
  40. HKEY g_Root = HKEY_ROOT;
  41. REGSAM g_OpenSam = KEY_ALL_ACCESS;
  42. REGSAM g_CreateSam = KEY_ALL_ACCESS;
  43. INT g_RegRefs;
  44. #define DBG_REG "Reg"
  45. //
  46. // Implementation
  47. //
  48. BOOL
  49. RegInitialize (
  50. VOID
  51. )
  52. {
  53. BOOL b = TRUE;
  54. MYASSERT (g_RegRefs >= 0);
  55. g_RegRefs++;
  56. if (g_RegRefs == 1) {
  57. RegInitializeCache (0);
  58. }
  59. return b;
  60. }
  61. VOID
  62. RegTerminate (
  63. VOID
  64. )
  65. {
  66. MYASSERT (g_RegRefs > 0);
  67. g_RegRefs--;
  68. if (!g_RegRefs) {
  69. RegTerminateCache ();
  70. }
  71. #ifdef DEBUG
  72. RegTrackTerminate();
  73. #endif
  74. }
  75. VOID
  76. SetRegRoot (
  77. IN HKEY Root
  78. )
  79. {
  80. g_Root = Root;
  81. }
  82. HKEY
  83. GetRegRoot (
  84. VOID
  85. )
  86. {
  87. return g_Root;
  88. }
  89. REGSAM
  90. SetRegOpenAccessMode (
  91. REGSAM Mode
  92. )
  93. {
  94. REGSAM OldMode;
  95. OldMode = g_OpenSam;
  96. g_OpenSam = Mode;
  97. return OldMode;
  98. }
  99. REGSAM
  100. GetRegOpenAccessMode (
  101. REGSAM Mode
  102. )
  103. {
  104. return g_OpenSam;
  105. }
  106. REGSAM
  107. SetRegCreateAccessMode (
  108. REGSAM Mode
  109. )
  110. {
  111. REGSAM OldMode;
  112. OldMode = g_CreateSam;
  113. g_CreateSam = Mode;
  114. return OldMode;
  115. }
  116. REGSAM
  117. GetRegCreateAccessMode (
  118. REGSAM Mode
  119. )
  120. {
  121. return g_CreateSam;
  122. }
  123. /*++
  124. Routine Description:
  125. OpenRegKeyStrA and OpenRegKeyStrW parse a text string that specifies a
  126. registry key into the hive and subkey, and then they open the subkey
  127. and return the handle.
  128. Arguments:
  129. RegKey - Specifies the complete path to the registry subkey, including
  130. the hive.
  131. Return Value:
  132. A non-NULL registry handle if successful, or NULL if either the subkey
  133. could not be opened or the string is malformed.
  134. --*/
  135. HKEY
  136. RealOpenRegKeyStrA (
  137. IN PCSTR RegKey
  138. DEBUG_TRACKING_PARAMS
  139. )
  140. {
  141. DWORD End;
  142. HKEY RootKey;
  143. HKEY Key;
  144. HKEY parentKey;
  145. PCSTR lastWack;
  146. //
  147. // Attempt to use cache
  148. //
  149. Key = RegGetKeyFromCacheA (RegKey, NULL, g_OpenSam, TRUE);
  150. if (Key) {
  151. TRACK_KEYA (Key, RegKey);
  152. return Key;
  153. }
  154. //
  155. // Attempt to use cache for parent
  156. //
  157. lastWack = _mbsrchr (RegKey, '\\');
  158. if (lastWack) {
  159. parentKey = RegGetKeyFromCacheA (RegKey, lastWack, g_OpenSam, FALSE);
  160. if (parentKey) {
  161. Key = OpenRegKeyWorkerA (parentKey, lastWack + 1 /* , */ DEBUG_TRACKING_ARGS);
  162. RegAddKeyToCacheA (RegKey, Key, g_OpenSam);
  163. return Key;
  164. }
  165. }
  166. //
  167. // Not in cache; use full api
  168. //
  169. DEBUGMSGA ((DBG_REG, "Opening %s", RegKey));
  170. RootKey = ConvertRootStringToKeyA (RegKey, &End);
  171. if (!RootKey) {
  172. return NULL;
  173. }
  174. if (!RegKey[End]) {
  175. OurRegOpenRootKeyA (RootKey, RegKey /* , */ DEBUG_TRACKING_ARGS);
  176. return RootKey;
  177. }
  178. Key = OpenRegKeyWorkerA (RootKey, &RegKey[End] /* , */ DEBUG_TRACKING_ARGS);
  179. if (Key) {
  180. RegAddKeyToCacheA (RegKey, Key, g_OpenSam);
  181. RegRecordParentInCacheA (RegKey, lastWack);
  182. }
  183. return Key;
  184. }
  185. HKEY
  186. RealOpenRegKeyStrW (
  187. IN PCWSTR RegKey
  188. DEBUG_TRACKING_PARAMS
  189. )
  190. {
  191. DWORD End;
  192. HKEY RootKey;
  193. HKEY Key;
  194. HKEY parentKey;
  195. PCWSTR lastWack;
  196. //
  197. // Attempt to use cache
  198. //
  199. Key = RegGetKeyFromCacheW (RegKey, NULL, g_OpenSam, TRUE);
  200. if (Key) {
  201. TRACK_KEYW (Key, RegKey);
  202. return Key;
  203. }
  204. //
  205. // Attempt to use cache for parent
  206. //
  207. lastWack = wcsrchr (RegKey, L'\\');
  208. if (lastWack) {
  209. parentKey = RegGetKeyFromCacheW (RegKey, lastWack, g_OpenSam, FALSE);
  210. if (parentKey) {
  211. Key = OpenRegKeyWorkerW (parentKey, lastWack + 1 /* , */ DEBUG_TRACKING_ARGS);
  212. RegAddKeyToCacheW (RegKey, Key, g_OpenSam);
  213. return Key;
  214. }
  215. }
  216. //
  217. // Not in cache; use full api
  218. //
  219. DEBUGMSGW ((DBG_REG, "Opening %s", RegKey));
  220. RootKey = ConvertRootStringToKeyW (RegKey, &End);
  221. if (!RootKey) {
  222. return NULL;
  223. }
  224. if (!RegKey[End]) {
  225. OurRegOpenRootKeyW (RootKey, RegKey /* , */ DEBUG_TRACKING_ARGS);
  226. return RootKey;
  227. }
  228. Key = OpenRegKeyWorkerW (RootKey, &RegKey[End] /* , */ DEBUG_TRACKING_ARGS);
  229. if (Key) {
  230. RegAddKeyToCacheW (RegKey, Key, g_OpenSam);
  231. RegRecordParentInCacheW (RegKey, lastWack);
  232. }
  233. return Key;
  234. }
  235. HKEY
  236. RealOpenRegKeyStrW1 (
  237. IN PCWSTR RegKey
  238. DEBUG_TRACKING_PARAMS
  239. )
  240. {
  241. PCSTR AnsiRegKey;
  242. HKEY Key;
  243. AnsiRegKey = ConvertWtoA (RegKey);
  244. if (!AnsiRegKey) {
  245. return NULL;
  246. }
  247. Key = RealOpenRegKeyStrA (AnsiRegKey /* , */ DEBUG_TRACKING_ARGS);
  248. FreeConvertedStr (AnsiRegKey);
  249. return Key;
  250. }
  251. BOOL
  252. DeleteRegKeyStrA (
  253. IN PCSTR RegKey
  254. )
  255. {
  256. DWORD End;
  257. HKEY RootKey;
  258. RootKey = ConvertRootStringToKeyA (RegKey, &End);
  259. if (!RootKey) {
  260. return FALSE;
  261. }
  262. if (!RegKey[End]) {
  263. return FALSE;
  264. }
  265. return (RegDeleteKeyA (RootKey, &RegKey[End]) == ERROR_SUCCESS);
  266. }
  267. BOOL
  268. DeleteRegKeyStrW (
  269. IN PCWSTR RegKey
  270. )
  271. {
  272. DWORD End;
  273. HKEY RootKey;
  274. RootKey = ConvertRootStringToKeyW (RegKey, &End);
  275. if (!RootKey) {
  276. return FALSE;
  277. }
  278. if (!RegKey[End]) {
  279. return FALSE;
  280. }
  281. return (RegDeleteKeyW (RootKey, &RegKey[End]) == ERROR_SUCCESS);
  282. }
  283. BOOL
  284. DeleteRegKeyStrW1 (
  285. IN PCWSTR RegKey
  286. )
  287. {
  288. PCSTR AnsiRegKey;
  289. BOOL result = FALSE;
  290. AnsiRegKey = ConvertWtoA (RegKey);
  291. if (!AnsiRegKey) {
  292. return FALSE;
  293. }
  294. result = DeleteRegKeyStrA (AnsiRegKey);
  295. FreeConvertedStr (AnsiRegKey);
  296. return result;
  297. }
  298. BOOL
  299. DeleteEmptyRegKeyStrA (
  300. IN PCSTR RegKey
  301. )
  302. {
  303. DWORD End;
  304. LONG rc;
  305. DWORD subKeys;
  306. DWORD values;
  307. HKEY rootKey;
  308. HKEY subKey;
  309. rootKey = ConvertRootStringToKeyA (RegKey, &End);
  310. if (!rootKey) {
  311. SetLastError (ERROR_INVALID_PARAMETER);
  312. return FALSE;
  313. }
  314. if (!RegKey[End]) {
  315. SetLastError (ERROR_INVALID_PARAMETER);
  316. return FALSE;
  317. }
  318. subKey = OpenRegKeyA (rootKey, &RegKey[End]);
  319. if (!subKey) {
  320. return TRUE;
  321. }
  322. rc = RegQueryInfoKey (subKey, NULL, NULL, NULL, &subKeys, NULL, NULL, &values, NULL, NULL, NULL, NULL);
  323. CloseRegKey (subKey);
  324. if (rc != ERROR_SUCCESS) {
  325. SetLastError (rc);
  326. return FALSE;
  327. }
  328. if (subKeys || values) {
  329. SetLastError (ERROR_ACCESS_DENIED);
  330. return FALSE;
  331. }
  332. rc = RegDeleteKeyA (rootKey, &RegKey[End]);
  333. if (rc != ERROR_SUCCESS) {
  334. SetLastError (rc);
  335. return FALSE;
  336. }
  337. return TRUE;
  338. }
  339. BOOL
  340. DeleteEmptyRegKeyStrW (
  341. IN PCWSTR RegKey
  342. )
  343. {
  344. DWORD End;
  345. LONG rc;
  346. DWORD subKeys;
  347. DWORD values;
  348. HKEY rootKey;
  349. HKEY subKey;
  350. rootKey = ConvertRootStringToKeyW (RegKey, &End);
  351. if (!rootKey) {
  352. SetLastError (ERROR_INVALID_PARAMETER);
  353. return FALSE;
  354. }
  355. if (!RegKey[End]) {
  356. SetLastError (ERROR_INVALID_PARAMETER);
  357. return FALSE;
  358. }
  359. subKey = OpenRegKeyW (rootKey, &RegKey[End]);
  360. if (!subKey) {
  361. return TRUE;
  362. }
  363. rc = RegQueryInfoKey (subKey, NULL, NULL, NULL, &subKeys, NULL, NULL, &values, NULL, NULL, NULL, NULL);
  364. CloseRegKey (subKey);
  365. if (rc != ERROR_SUCCESS) {
  366. SetLastError (rc);
  367. return FALSE;
  368. }
  369. if (subKeys || values) {
  370. SetLastError (ERROR_ACCESS_DENIED);
  371. return FALSE;
  372. }
  373. rc = RegDeleteKeyW (rootKey, &RegKey[End]);
  374. if (rc != ERROR_SUCCESS) {
  375. SetLastError (rc);
  376. return FALSE;
  377. }
  378. return TRUE;
  379. }
  380. BOOL
  381. DeleteEmptyRegKeyStrW1 (
  382. IN PCWSTR RegKey
  383. )
  384. {
  385. PCSTR AnsiRegKey;
  386. BOOL result = FALSE;
  387. AnsiRegKey = ConvertWtoA (RegKey);
  388. if (!AnsiRegKey) {
  389. return FALSE;
  390. }
  391. result = DeleteEmptyRegKeyStrA (AnsiRegKey);
  392. FreeConvertedStr (AnsiRegKey);
  393. return result;
  394. }
  395. PVOID
  396. MemAllocWrapper (
  397. IN DWORD Size
  398. )
  399. /*++
  400. Routine Description:
  401. pemAllocWrapper implements a default allocation routine. The APIs
  402. that have a "2" at the end allow the caller to supply an alternative
  403. allocator or deallocator. The routines without the "2" use this
  404. default allocator.
  405. Arguments:
  406. Size - Specifies the amount of memory (in bytes) to allocate
  407. Return Value:
  408. A pointer to a block of memory that can hold Size bytes, or NULL
  409. if allocation fails.
  410. --*/
  411. {
  412. return MemAlloc (g_hHeap, 0, Size);
  413. }
  414. VOID
  415. MemFreeWrapper (
  416. IN PCVOID Mem
  417. )
  418. /*++
  419. Routine Description:
  420. MemFreeWrapper implements a default deallocation routine.
  421. See MemAllocWrapper above.
  422. Arguments:
  423. Mem - Specifies the block of memory to free, and was allocated by the
  424. MemAllocWrapper function.
  425. Return Value:
  426. none
  427. --*/
  428. {
  429. MemFree (g_hHeap, 0, Mem);
  430. }
  431. /*++
  432. Routine Description:
  433. GetRegValueData2A and GetRegValueData2W query a registry value and
  434. return the data as a pointer. They use the specified Alloc and Free
  435. routines to allocate and free the memory as needed.
  436. A GetRegValueData macro is defined, and it uses the default allocators,
  437. simplifying the function parameters and allowing the caller to free
  438. the return value via MemFree.
  439. Arguments:
  440. hKey - Specifies the registry key that holds the specified value.
  441. Value - Specifies the value name to query.
  442. Alloc - Specifies the allocation routine, called to allocate a block of
  443. memory for the return data.
  444. FreeRoutine - Specifies the deallocation routine, called if an error is encountered
  445. during processing.
  446. Return Value:
  447. A pointer to the data retrieved, or NULL if the value does not exist or an
  448. error occurred. Call GetLastError to obtian the failure code.
  449. --*/
  450. PBYTE
  451. GetRegValueData2A (
  452. IN HKEY hKey,
  453. IN PCSTR Value,
  454. IN ALLOCATOR AllocRoutine,
  455. IN DEALLOCATOR FreeRoutine
  456. )
  457. {
  458. LONG rc;
  459. DWORD BufSize;
  460. PBYTE DataBuf;
  461. rc = RegQueryValueExA (hKey, Value, NULL, NULL, NULL, &BufSize);
  462. if (rc != ERROR_SUCCESS) {
  463. SetLastError ((DWORD)rc);
  464. return NULL;
  465. }
  466. DataBuf = (PBYTE) AllocRoutine (BufSize + sizeof (CHAR));
  467. rc = RegQueryValueExA (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  468. if (rc == ERROR_SUCCESS) {
  469. *((PSTR) DataBuf + BufSize) = 0;
  470. return DataBuf;
  471. }
  472. FreeRoutine (DataBuf);
  473. SetLastError ((DWORD)rc);
  474. return NULL;
  475. }
  476. PBYTE
  477. GetRegValueData2W (
  478. IN HKEY hKey,
  479. IN PCWSTR Value,
  480. IN ALLOCATOR AllocRoutine,
  481. IN DEALLOCATOR FreeRoutine
  482. )
  483. {
  484. LONG rc;
  485. DWORD BufSize = 0;
  486. PBYTE DataBuf;
  487. rc = RegQueryValueExW (hKey, Value, NULL, NULL, NULL, &BufSize);
  488. if (rc != ERROR_SUCCESS) {
  489. SetLastError ((DWORD)rc);
  490. return NULL;
  491. }
  492. DataBuf = (PBYTE) AllocRoutine (BufSize + sizeof(WCHAR));
  493. rc = RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  494. if (rc == ERROR_SUCCESS) {
  495. *((PWSTR) (DataBuf + BufSize)) = 0;
  496. return DataBuf;
  497. }
  498. FreeRoutine (DataBuf);
  499. SetLastError ((DWORD)rc);
  500. return NULL;
  501. }
  502. /*++
  503. Routine Description:
  504. GetRegValueDataOfType2A and GetRegValueDataOfType2W are extensions of
  505. GetRegValueData. They only return a data pointer when the data stored
  506. in the registry value is the correct type.
  507. Arguments:
  508. hKey - Specifies the registry key to query
  509. Value - Specifies the value name to query
  510. MustBeType - Specifies the type of data (a REG_* constant). If the specified
  511. value has data but is a different type, NULL will be returned.
  512. AllocRoutine - Specifies the allocation routine, called to allocate the return data.
  513. FreeRoutine - Specifies the deallocation routine, called when an error is encountered.
  514. Return Value:
  515. If successful, returns a pointer to data that matches the specified type.
  516. If the data is a different type, the value name does not exist, or an
  517. error occurs during the query, NULL is returned, and the failure code
  518. can be obtained from GetLastError.
  519. --*/
  520. PBYTE
  521. GetRegValueDataOfType2A (
  522. IN HKEY hKey,
  523. IN PCSTR Value,
  524. IN DWORD MustBeType,
  525. IN ALLOCATOR AllocRoutine,
  526. IN DEALLOCATOR FreeRoutine
  527. )
  528. {
  529. LONG rc;
  530. DWORD BufSize = 0;
  531. PBYTE DataBuf;
  532. DWORD Type;
  533. rc = RegQueryValueExA (hKey, Value, NULL, &Type, NULL, &BufSize);
  534. if (rc != ERROR_SUCCESS) {
  535. SetLastError ((DWORD)rc);
  536. return NULL;
  537. }
  538. switch (MustBeType) {
  539. case REG_SZ:
  540. case REG_EXPAND_SZ:
  541. if (Type == REG_SZ) {
  542. break;
  543. }
  544. if (Type == REG_EXPAND_SZ) {
  545. break;
  546. }
  547. return NULL;
  548. default:
  549. if (Type == MustBeType) {
  550. break;
  551. }
  552. return NULL;
  553. }
  554. DataBuf = (PBYTE) AllocRoutine (BufSize + sizeof (WORD));
  555. rc = RegQueryValueExA (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  556. if (rc == ERROR_SUCCESS) {
  557. *((PWORD) (DataBuf + BufSize)) = 0;
  558. return DataBuf;
  559. }
  560. MYASSERT (FALSE); //lint !e506
  561. FreeRoutine (DataBuf);
  562. SetLastError ((DWORD)rc);
  563. return NULL;
  564. }
  565. PBYTE
  566. GetRegValueDataOfType2W (
  567. IN HKEY hKey,
  568. IN PCWSTR Value,
  569. IN DWORD MustBeType,
  570. IN ALLOCATOR AllocRoutine,
  571. IN DEALLOCATOR FreeRoutine
  572. )
  573. {
  574. LONG rc;
  575. DWORD BufSize;
  576. PBYTE DataBuf;
  577. DWORD Type;
  578. rc = RegQueryValueExW (hKey, Value, NULL, &Type, NULL, &BufSize);
  579. if (rc != ERROR_SUCCESS) {
  580. SetLastError ((DWORD)rc);
  581. return NULL;
  582. }
  583. switch (MustBeType) {
  584. case REG_SZ:
  585. case REG_EXPAND_SZ:
  586. if (Type == REG_SZ) break;
  587. if (Type == REG_EXPAND_SZ) break;
  588. return NULL;
  589. case REG_DWORD:
  590. case REG_DWORD_BIG_ENDIAN:
  591. if (Type == REG_DWORD) break;
  592. if (Type == REG_DWORD_BIG_ENDIAN) break;
  593. return NULL;
  594. default:
  595. if (Type == MustBeType) break;
  596. return NULL;
  597. }
  598. DataBuf = (PBYTE) AllocRoutine (BufSize + sizeof(WCHAR));
  599. rc = RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
  600. if (rc == ERROR_SUCCESS) {
  601. *((PWSTR) (DataBuf + BufSize)) = 0;
  602. return DataBuf;
  603. }
  604. MYASSERT (FALSE); //lint !e506
  605. FreeRoutine (DataBuf);
  606. SetLastError ((DWORD)rc);
  607. return NULL;
  608. }
  609. BOOL
  610. GetRegValueTypeAndSizeA (
  611. IN HKEY Key,
  612. IN PCSTR ValueName,
  613. OUT PDWORD OutType, OPTIONAL
  614. OUT PDWORD OutSize OPTIONAL
  615. )
  616. {
  617. LONG rc;
  618. DWORD Type;
  619. DWORD Size = 0;
  620. rc = RegQueryValueExA (Key, ValueName, NULL, &Type, NULL, &Size);
  621. if (rc == ERROR_SUCCESS) {
  622. if (OutType) {
  623. *OutType = Type;
  624. }
  625. if (OutSize) {
  626. *OutSize = Size;
  627. }
  628. return TRUE;
  629. }
  630. return FALSE;
  631. }
  632. BOOL
  633. GetRegValueTypeAndSizeW (
  634. IN HKEY Key,
  635. IN PCWSTR ValueName,
  636. OUT PDWORD OutType, OPTIONAL
  637. OUT PDWORD OutSize OPTIONAL
  638. )
  639. {
  640. LONG rc;
  641. DWORD Type;
  642. DWORD Size;
  643. rc = RegQueryValueExW (Key, ValueName, NULL, &Type, NULL, &Size);
  644. if (rc == ERROR_SUCCESS) {
  645. if (OutType) {
  646. *OutType = Type;
  647. }
  648. if (OutSize) {
  649. *OutSize = Size;
  650. }
  651. return TRUE;
  652. }
  653. return FALSE;
  654. }
  655. /*++
  656. Routine Description:
  657. GetRegKeyData2A and GetRegKeyData2W return default data associated
  658. with a registry key. They open the specified subkey, query the value,
  659. close the subkey and return the data.
  660. Arguments:
  661. Parent - Specifies the key that contains SubKey.
  662. SubKey - Specifies the name of the subkey to obtain the default value for.
  663. AllocRoutine - Specifies the allocation routine, called to allocate a block of
  664. memory for the registry data.
  665. FreeRoutine - Specifies the deallocation routine, called to free the block of
  666. data if an error occurs.
  667. Return Value:
  668. A pointer to the block of data obtained from the subkey's default value,
  669. or NULL if the subkey does not exist or an error was encountered. Call
  670. GetLastError for a failure code.
  671. --*/
  672. PBYTE
  673. GetRegKeyData2A (
  674. IN HKEY Parent,
  675. IN PCSTR SubKey,
  676. IN ALLOCATOR AllocRoutine,
  677. IN DEALLOCATOR FreeRoutine
  678. )
  679. {
  680. HKEY SubKeyHandle;
  681. PBYTE Data;
  682. SubKeyHandle = OpenRegKeyA (Parent, SubKey);
  683. if (!SubKeyHandle) {
  684. return NULL;
  685. }
  686. Data = GetRegValueData2A (SubKeyHandle, "", AllocRoutine, FreeRoutine);
  687. CloseRegKey (SubKeyHandle);
  688. return Data;
  689. }
  690. PBYTE
  691. GetRegKeyData2W (
  692. IN HKEY Parent,
  693. IN PCWSTR SubKey,
  694. IN ALLOCATOR AllocRoutine,
  695. IN DEALLOCATOR FreeRoutine
  696. )
  697. {
  698. HKEY SubKeyHandle;
  699. PBYTE Data;
  700. SubKeyHandle = OpenRegKeyW (Parent, SubKey);
  701. if (!SubKeyHandle) {
  702. return NULL;
  703. }
  704. Data = GetRegValueData2W (SubKeyHandle, L"", AllocRoutine, FreeRoutine);
  705. CloseRegKey (SubKeyHandle);
  706. return Data;
  707. }
  708. /*++
  709. Routine Description:
  710. GetRegData2A and GetRegData2W open a registry key, query a value,
  711. close the registry key and return the value.
  712. Arguments:
  713. KeyString - Specifies the registry key to open
  714. ValueName - Specifies the value to query
  715. AllocRoutine - Specifies the allocation routine, used to allocate a block of
  716. memory to hold the value data
  717. FreeRoutine - Specifies the deallocation routine, used to free the block of
  718. memory when an error is encountered.
  719. Return Value:
  720. A pointer to the registry data retrieved, or NULL if the key or value
  721. does not exist, or if an error occurs. Call GetLastError for a failure code.
  722. --*/
  723. PBYTE
  724. GetRegData2A (
  725. IN PCSTR KeyString,
  726. IN PCSTR ValueName,
  727. IN ALLOCATOR AllocRoutine,
  728. IN DEALLOCATOR FreeRoutine
  729. )
  730. {
  731. HKEY Key;
  732. PBYTE Data;
  733. Key = OpenRegKeyStrA (KeyString);
  734. if (!Key) {
  735. return NULL;
  736. }
  737. Data = GetRegValueData2A (Key, ValueName, AllocRoutine, FreeRoutine);
  738. CloseRegKey (Key);
  739. return Data;
  740. }
  741. PBYTE
  742. GetRegData2W (
  743. IN PCWSTR KeyString,
  744. IN PCWSTR ValueName,
  745. IN ALLOCATOR AllocRoutine,
  746. IN DEALLOCATOR FreeRoutine
  747. )
  748. {
  749. HKEY Key;
  750. PBYTE Data;
  751. Key = OpenRegKeyStrW (KeyString);
  752. if (!Key) {
  753. return NULL;
  754. }
  755. Data = GetRegValueData2W (Key, ValueName, AllocRoutine, FreeRoutine);
  756. CloseRegKey (Key);
  757. return Data;
  758. }
  759. BOOL
  760. GetRegSubkeysCount (
  761. IN HKEY ParentKey,
  762. OUT PDWORD SubKeyCount, OPTIONAL
  763. OUT PDWORD MaxSubKeyLen OPTIONAL
  764. )
  765. /*++
  766. Routine Description:
  767. GetRegSubkeysCount retrieves the number of subkeys of a given parent key.
  768. Arguments:
  769. ParentKey - Specifies a handle to the parent registry key.
  770. SubKeyCount - Receives the number of subkeys
  771. MaxSubKeyLen - Receives the length, in chars, of the longest subkey string
  772. Return Value:
  773. TRUE if the count was retrieved successfully, FALSE otherwise.
  774. In this case, call GetLastError for a failure code.
  775. --*/
  776. {
  777. LONG rc;
  778. rc = RegQueryInfoKey (
  779. ParentKey,
  780. NULL,
  781. NULL,
  782. NULL,
  783. SubKeyCount,
  784. MaxSubKeyLen,
  785. NULL,
  786. NULL,
  787. NULL,
  788. NULL,
  789. NULL,
  790. NULL
  791. );
  792. if (rc != ERROR_SUCCESS) {
  793. return FALSE;
  794. }
  795. return TRUE;
  796. }
  797. /*++
  798. Routine Description:
  799. CreateRegKeyA and CreateRegKeyW create a subkey if it does not
  800. exist already, or open a subkey if it already exists.
  801. Arguments:
  802. ParentKey - Specifies a handle to the parent registry key to contain
  803. the new key.
  804. NewKeyName - Specifies the name of the subkey to create or open.
  805. Return Value:
  806. The handle to an open registry key upon success, or NULL if an
  807. error occurred. Call GetLastError for a failure code.
  808. --*/
  809. HKEY
  810. pCreateRegKeyWorkerA (
  811. IN HKEY ParentKey,
  812. IN PCSTR NewKeyName
  813. DEBUG_TRACKING_PARAMS
  814. )
  815. {
  816. LONG rc;
  817. HKEY SubKey;
  818. DWORD DontCare;
  819. rc = OurRegCreateKeyExA (
  820. ParentKey,
  821. NewKeyName,
  822. 0,
  823. NULL,
  824. 0,
  825. g_CreateSam,
  826. NULL,
  827. &SubKey,
  828. &DontCare
  829. DEBUG_TRACKING_ARGS
  830. );
  831. if (rc != ERROR_SUCCESS) {
  832. SetLastError ((DWORD)rc);
  833. return NULL;
  834. }
  835. return SubKey;
  836. }
  837. HKEY
  838. RealCreateRegKeyA (
  839. IN HKEY ParentKey,
  840. IN PCSTR NewKeyName
  841. DEBUG_TRACKING_PARAMS
  842. )
  843. {
  844. HKEY result;
  845. result = pCreateRegKeyWorkerA (ParentKey, NewKeyName /* , */ DEBUG_TRACKING_ARGS);
  846. RegAddKeyToCacheA ("", result, g_CreateSam);
  847. return result;
  848. }
  849. HKEY
  850. pCreateRegKeyWorkerW (
  851. IN HKEY ParentKey,
  852. IN PCWSTR NewKeyName
  853. DEBUG_TRACKING_PARAMS
  854. )
  855. {
  856. LONG rc;
  857. HKEY SubKey;
  858. DWORD DontCare;
  859. rc = OurRegCreateKeyExW (
  860. ParentKey,
  861. NewKeyName,
  862. 0,
  863. NULL,
  864. 0,
  865. g_CreateSam,
  866. NULL,
  867. &SubKey,
  868. &DontCare
  869. DEBUG_TRACKING_ARGS
  870. );
  871. if (rc != ERROR_SUCCESS) {
  872. SetLastError ((DWORD)rc);
  873. return NULL;
  874. }
  875. return SubKey;
  876. }
  877. HKEY
  878. RealCreateRegKeyW (
  879. IN HKEY ParentKey,
  880. IN PCWSTR NewKeyName
  881. DEBUG_TRACKING_PARAMS
  882. )
  883. {
  884. HKEY result;
  885. result = pCreateRegKeyWorkerW (ParentKey, NewKeyName /* , */ DEBUG_TRACKING_ARGS);
  886. RegAddKeyToCacheW (L"", result, g_CreateSam);
  887. return result;
  888. }
  889. /*++
  890. Routine Description:
  891. CreateRegKeyStrA and CreateRegKeyStrW create a subkey if it does not
  892. exist already, or open a subkey if it already exists.
  893. Arguments:
  894. NewKeyName - Specifies the full path to the key to create or open.
  895. Return Value:
  896. The handle to an open registry key upon success, or NULL if an
  897. error occurred. Call GetLastError for a failure code.
  898. --*/
  899. HKEY
  900. RealCreateRegKeyStrA (
  901. IN PCSTR NewKeyName
  902. DEBUG_TRACKING_PARAMS
  903. )
  904. {
  905. LONG rc;
  906. DWORD DontCare;
  907. CHAR RegKey[MAX_REGISTRY_KEYA];
  908. PCSTR Start;
  909. PCSTR End;
  910. HKEY Parent, NewKey;
  911. BOOL CloseParent = FALSE;
  912. DWORD EndPos;
  913. PCSTR lastWack;
  914. HKEY parentKey;
  915. //
  916. // Attempt to use cache
  917. //
  918. NewKey = RegGetKeyFromCacheA (NewKeyName, NULL, g_CreateSam, TRUE);
  919. if (NewKey) {
  920. TRACK_KEYA (NewKey, NewKeyName);
  921. return NewKey;
  922. }
  923. //
  924. // Attempt to use cache for parent
  925. //
  926. lastWack = _mbsrchr (NewKeyName, '\\');
  927. if (lastWack) {
  928. parentKey = RegGetKeyFromCacheA (NewKeyName, lastWack, g_CreateSam, FALSE);
  929. if (parentKey) {
  930. NewKey = pCreateRegKeyWorkerA (parentKey, lastWack + 1 /* , */ DEBUG_TRACKING_ARGS);
  931. RegAddKeyToCacheA (NewKeyName, NewKey, g_CreateSam);
  932. return NewKey;
  933. }
  934. }
  935. //
  936. // Get the root
  937. //
  938. Parent = ConvertRootStringToKeyA (NewKeyName, &EndPos);
  939. if (!Parent) {
  940. return NULL;
  941. }
  942. Start = &NewKeyName[EndPos];
  943. if (!(*Start)) {
  944. OurRegOpenRootKeyA (Parent, NewKeyName/* , */ DEBUG_TRACKING_ARGS);
  945. return Parent;
  946. }
  947. //
  948. // Create each node until entire key exists
  949. //
  950. NewKey = NULL;
  951. do {
  952. //
  953. // Find end of this node
  954. //
  955. End = _mbschr (Start, '\\');
  956. if (!End) {
  957. End = GetEndOfStringA (Start);
  958. }
  959. //If a subkey name exceeds 256 WCHARS or 512 ANSI chars, then it's invalid (ie. RegCreateKey will fail).
  960. //So we should restrict the max number of chars to copy to 512, in this case.
  961. //I.e. End - Start <= 512
  962. if ((End - Start) > 512)
  963. {
  964. MYASSERT(FALSE);
  965. if ((End - Start ) > 768)
  966. {
  967. End = Start + 768;
  968. }
  969. //this is enough room to copy the string into RegKey, so that RegCreateKey will fail, but
  970. //not enough to overun the buffer
  971. }
  972. StringCopyABA (RegKey, Start, End);
  973. //
  974. // Try to open the key (unless it's the last in the string)
  975. //
  976. if (*End) { //lint !e613
  977. rc = OurRegOpenKeyExA (
  978. Parent,
  979. RegKey,
  980. 0,
  981. KEY_READ|KEY_CREATE_SUB_KEY,
  982. &NewKey
  983. DEBUG_TRACKING_ARGS
  984. );
  985. if (rc != ERROR_SUCCESS) {
  986. NewKey = NULL;
  987. }
  988. } else {
  989. NewKey = NULL;
  990. }
  991. //
  992. // If open failed, create the key
  993. //
  994. if (NewKey) {
  995. rc = ERROR_SUCCESS;
  996. } else {
  997. rc = OurRegCreateKeyExA (
  998. Parent,
  999. RegKey,
  1000. 0,
  1001. NULL,
  1002. 0,
  1003. g_CreateSam,
  1004. NULL,
  1005. &NewKey,
  1006. &DontCare
  1007. DEBUG_TRACKING_ARGS
  1008. );
  1009. }
  1010. if (CloseParent) {
  1011. CloseRegKey (Parent);
  1012. }
  1013. if (rc != ERROR_SUCCESS) {
  1014. SetLastError ((DWORD)rc);
  1015. return NULL;
  1016. }
  1017. Parent = NewKey;
  1018. CloseParent = TRUE;
  1019. //
  1020. // Go to next node
  1021. //
  1022. Start = End;
  1023. if (*Start) { //lint !e613
  1024. Start = _mbsinc (Start);
  1025. }
  1026. } while (*Start); //lint !e613
  1027. if (Parent) {
  1028. RegAddKeyToCacheA (NewKeyName, Parent, g_CreateSam);
  1029. RegRecordParentInCacheA (NewKeyName, lastWack);
  1030. }
  1031. return Parent;
  1032. }
  1033. HKEY
  1034. RealCreateRegKeyStrW (
  1035. IN PCWSTR NewKeyName
  1036. DEBUG_TRACKING_PARAMS
  1037. )
  1038. {
  1039. LONG rc;
  1040. DWORD DontCare;
  1041. WCHAR RegKey[MAX_REGISTRY_KEYW];
  1042. PCWSTR Start;
  1043. PCWSTR End;
  1044. HKEY Parent, NewKey;
  1045. BOOL CloseParent = FALSE;
  1046. DWORD EndPos;
  1047. PCWSTR lastWack;
  1048. HKEY parentKey;
  1049. //
  1050. // Attempt to use cache
  1051. //
  1052. NewKey = RegGetKeyFromCacheW (NewKeyName, NULL, g_CreateSam, TRUE);
  1053. if (NewKey) {
  1054. TRACK_KEYW (NewKey, NewKeyName);
  1055. return NewKey;
  1056. }
  1057. //
  1058. // Attempt to use cache for parent
  1059. //
  1060. lastWack = wcsrchr (NewKeyName, L'\\');
  1061. if (lastWack) {
  1062. parentKey = RegGetKeyFromCacheW (NewKeyName, lastWack, g_CreateSam, FALSE);
  1063. if (parentKey) {
  1064. NewKey = pCreateRegKeyWorkerW (parentKey, lastWack + 1 /* , */ DEBUG_TRACKING_ARGS);
  1065. RegAddKeyToCacheW (NewKeyName, NewKey, g_CreateSam);
  1066. return NewKey;
  1067. }
  1068. }
  1069. //
  1070. // Get the root
  1071. //
  1072. Parent = ConvertRootStringToKeyW (NewKeyName, &EndPos);
  1073. if (!Parent) {
  1074. return NULL;
  1075. }
  1076. Start = &NewKeyName[EndPos];
  1077. if (!(*Start)) {
  1078. OurRegOpenRootKeyW (Parent, NewKeyName/* , */ DEBUG_TRACKING_ARGS);
  1079. return Parent;
  1080. }
  1081. //
  1082. // Create each node until entire key exists
  1083. //
  1084. NewKey = NULL;
  1085. do {
  1086. //
  1087. // Find end of this node
  1088. //
  1089. End = wcschr (Start, '\\');
  1090. if (!End) {
  1091. End = GetEndOfStringW (Start);
  1092. }
  1093. //If a subkey name exceeds 256 WCHARS or 512 ANSI chars, then it's invalid (ie. RegCreateKey will fail).
  1094. //So we should restrict the max number of chars to copy to 256, in this case.
  1095. //I.e. End - Start <= 256 wchars
  1096. if ((End - Start) > 256)
  1097. {
  1098. MYASSERT(FALSE);
  1099. if ((End - Start ) > 384)
  1100. {
  1101. End = Start + 384;
  1102. }
  1103. //this is enough room to copy the string into RegKey, so that RegCreateKey will fail, but
  1104. //not enough to overun the buffer
  1105. }
  1106. StringCopyABW (RegKey, Start, End);
  1107. //
  1108. // Try to open the key (unless it's the last in the string)
  1109. //
  1110. if (*End) {
  1111. rc = OurRegOpenKeyExW (
  1112. Parent,
  1113. RegKey,
  1114. 0,
  1115. KEY_READ|KEY_CREATE_SUB_KEY,
  1116. &NewKey
  1117. DEBUG_TRACKING_ARGS
  1118. );
  1119. if (rc != ERROR_SUCCESS) {
  1120. NewKey = NULL;
  1121. }
  1122. } else {
  1123. NewKey = NULL;
  1124. }
  1125. //
  1126. // If open failed, create the key
  1127. //
  1128. if (NewKey) {
  1129. rc = ERROR_SUCCESS;
  1130. } else {
  1131. rc = OurRegCreateKeyExW (
  1132. Parent,
  1133. RegKey,
  1134. 0,
  1135. NULL,
  1136. 0,
  1137. g_CreateSam,
  1138. NULL,
  1139. &NewKey,
  1140. &DontCare
  1141. DEBUG_TRACKING_ARGS
  1142. );
  1143. }
  1144. if (CloseParent) {
  1145. CloseRegKey (Parent);
  1146. }
  1147. if (rc != ERROR_SUCCESS) {
  1148. SetLastError ((DWORD)rc);
  1149. return NULL;
  1150. }
  1151. Parent = NewKey;
  1152. CloseParent = TRUE;
  1153. //
  1154. // Go to next node
  1155. //
  1156. Start = End;
  1157. if (*Start) {
  1158. Start++;
  1159. }
  1160. } while (*Start);
  1161. if (Parent) {
  1162. RegAddKeyToCacheW (NewKeyName, Parent, g_CreateSam);
  1163. RegRecordParentInCacheW (NewKeyName, lastWack);
  1164. }
  1165. return Parent;
  1166. }
  1167. /*++
  1168. Routine Description:
  1169. OpenRegKeyA and OpenRegKeyW open a subkey.
  1170. Arguments:
  1171. ParentKey - Specifies a handle to the parent registry key to contain
  1172. the subkey.
  1173. KeyToOpen - Specifies the name of the subkey to open.
  1174. Return Value:
  1175. The handle to an open registry key upon success, or NULL if an
  1176. error occurred. Call GetLastError for a failure code.
  1177. --*/
  1178. HKEY
  1179. OpenRegKeyWorkerA (
  1180. IN HKEY ParentKey,
  1181. IN PCSTR KeyToOpen OPTIONAL
  1182. DEBUG_TRACKING_PARAMS
  1183. )
  1184. {
  1185. HKEY SubKey;
  1186. LONG rc;
  1187. rc = OurRegOpenKeyExA (
  1188. ParentKey,
  1189. KeyToOpen,
  1190. 0,
  1191. g_OpenSam,
  1192. &SubKey
  1193. DEBUG_TRACKING_ARGS
  1194. );
  1195. if (rc != ERROR_SUCCESS) {
  1196. SetLastError ((DWORD)rc);
  1197. return NULL;
  1198. }
  1199. return SubKey;
  1200. }
  1201. HKEY
  1202. RealOpenRegKeyA (
  1203. IN HKEY ParentKey,
  1204. IN PCSTR KeyToOpen OPTIONAL
  1205. DEBUG_TRACKING_PARAMS
  1206. )
  1207. {
  1208. HKEY result;
  1209. result = OpenRegKeyWorkerA (ParentKey, KeyToOpen /* , */ DEBUG_TRACKING_ARGS);
  1210. RegAddKeyToCacheA ("", result, g_OpenSam);
  1211. return result;
  1212. }
  1213. HKEY
  1214. OpenRegKeyWorkerW (
  1215. IN HKEY ParentKey,
  1216. IN PCWSTR KeyToOpen
  1217. DEBUG_TRACKING_PARAMS
  1218. )
  1219. {
  1220. LONG rc;
  1221. HKEY SubKey;
  1222. rc = OurRegOpenKeyExW (
  1223. ParentKey,
  1224. KeyToOpen,
  1225. 0,
  1226. g_OpenSam,
  1227. &SubKey
  1228. DEBUG_TRACKING_ARGS
  1229. );
  1230. if (rc != ERROR_SUCCESS) {
  1231. SetLastError ((DWORD)rc);
  1232. return NULL;
  1233. }
  1234. return SubKey;
  1235. }
  1236. HKEY
  1237. RealOpenRegKeyW (
  1238. IN HKEY ParentKey,
  1239. IN PCWSTR KeyToOpen OPTIONAL
  1240. DEBUG_TRACKING_PARAMS
  1241. )
  1242. {
  1243. HKEY result;
  1244. result = OpenRegKeyWorkerW (ParentKey, KeyToOpen /* , */ DEBUG_TRACKING_ARGS);
  1245. RegAddKeyToCacheW (L"", result, g_OpenSam);
  1246. return result;
  1247. }
  1248. LONG
  1249. CloseRegKeyWorker (
  1250. IN HKEY Key
  1251. )
  1252. {
  1253. LONG rc = ERROR_INVALID_HANDLE;
  1254. if (!Key) {
  1255. return ERROR_SUCCESS;
  1256. }
  1257. if (GetOffsetOfRootKey (Key)) {
  1258. return ERROR_SUCCESS;
  1259. }
  1260. __try {
  1261. rc = RegCloseKey (Key);
  1262. }
  1263. __except (TRUE) {
  1264. DEBUGMSG ((DBG_WHOOPS, "RegCloseKey threw an exception!"));
  1265. }
  1266. MYASSERT (rc == ERROR_SUCCESS);
  1267. return rc;
  1268. }
  1269. LONG
  1270. RealCloseRegKey (
  1271. IN HKEY Key
  1272. )
  1273. /*++
  1274. Routine Description:
  1275. RealCloseRegKey closes the reg handle supplied, unless the handle is
  1276. a pre-defined Win32 handle. The CloseRegKey macro resolves directly
  1277. to this function in the free build, and to OurCloseRegKey in the
  1278. checked build.
  1279. Arguments:
  1280. Key - Specifies the reg handle to close
  1281. Return Value:
  1282. A standard Win32 error code indicating outcome.
  1283. --*/
  1284. {
  1285. if (RegDecrementRefCount (Key)) {
  1286. //
  1287. // Key is in the cache; don't call CloseRegKeyWorker. This will
  1288. // be done by the cache code.
  1289. //
  1290. return ERROR_SUCCESS;
  1291. }
  1292. return CloseRegKeyWorker (Key);
  1293. }
  1294. /*++
  1295. Routine Description:
  1296. GetOffsetOfRootString returns a non-zero offset to the g_RegRoots table
  1297. below. The offset can be used with GetRootStringFromOffset and
  1298. GetRootKeyFromOffset.
  1299. Arguments:
  1300. RootString - A pointer to a string containing the path to a registry key
  1301. LengthPtr - A pointer to a variable that receives the length of the
  1302. registry root, including the joining backslash if it exists.
  1303. Return Value:
  1304. A non-zero offset to the g_RegRoots table, or zero if RootString does not
  1305. contain a registry root.
  1306. --*/
  1307. typedef struct {
  1308. PCSTR RootText;
  1309. PCWSTR WideRootText;
  1310. UINT TextLength;
  1311. HKEY RootKey;
  1312. } REGISTRYROOT, *PREGISTRYROOT;
  1313. static
  1314. REGISTRYROOT g_RegRoots[] = {
  1315. "HKR", L"HKR", 3, HKEY_ROOT,
  1316. "HKEY_ROOT", L"HKEY_ROOT", 9, HKEY_ROOT,
  1317. "HKLM", L"HKLM", 4, HKEY_LOCAL_MACHINE,
  1318. "HKEY_LOCAL_MACHINE", L"HKEY_LOCAL_MACHINE", 18, HKEY_LOCAL_MACHINE,
  1319. "HKU", L"HKU", 3, HKEY_USERS,
  1320. "HKEY_USERS", L"HKEY_USERS", 10, HKEY_USERS,
  1321. "HKCU", L"HKCU", 4, HKEY_CURRENT_USER,
  1322. "HKEY_CURRENT_USER", L"HKEY_CURRENT_USER", 17, HKEY_CURRENT_USER,
  1323. "HKCC", L"HKCC", 4, HKEY_CURRENT_CONFIG,
  1324. "HKEY_CURRENT_CONFIG", L"HKEY_CURRENT_CONFIG", 19, HKEY_CURRENT_CONFIG,
  1325. "HKCR", L"HKCR", 4, HKEY_CLASSES_ROOT,
  1326. "HKEY_CLASSES_ROOT", L"HKEY_CLASSES_ROOT", 17, HKEY_CLASSES_ROOT,
  1327. "HKDD", L"HKDD", 4, HKEY_DYN_DATA,
  1328. "HKEY_DYN_DATA", L"HKEY_DYN_DATA", 13, HKEY_DYN_DATA,
  1329. NULL, NULL, 0, NULL
  1330. };
  1331. #define REGROOTS 14
  1332. INT
  1333. GetOffsetOfRootStringA (
  1334. IN PCSTR RootString,
  1335. OUT PDWORD LengthPtr OPTIONAL
  1336. )
  1337. {
  1338. int i;
  1339. MBCHAR c;
  1340. for (i = 0 ; g_RegRoots[i].RootText ; i++) {
  1341. if (StringIMatchTcharCountA (
  1342. RootString,
  1343. g_RegRoots[i].RootText,
  1344. g_RegRoots[i].TextLength
  1345. )) {
  1346. c = _mbsgetc (RootString, g_RegRoots[i].TextLength);
  1347. if (c && c != '\\') {
  1348. continue;
  1349. }
  1350. if (LengthPtr) {
  1351. *LengthPtr = g_RegRoots[i].TextLength;
  1352. if (c) {
  1353. *LengthPtr += 1;
  1354. }
  1355. }
  1356. return i + 1;
  1357. }
  1358. }
  1359. return 0;
  1360. }
  1361. INT
  1362. GetOffsetOfRootStringW (
  1363. IN PCWSTR RootString,
  1364. OUT PDWORD LengthPtr OPTIONAL
  1365. )
  1366. {
  1367. int i;
  1368. WCHAR c;
  1369. for (i = 0 ; g_RegRoots[i].RootText ; i++) {
  1370. if (!_wcsnicmp (RootString, g_RegRoots[i].WideRootText,
  1371. g_RegRoots[i].TextLength)
  1372. ) {
  1373. c = _wcsgetc (RootString, g_RegRoots[i].TextLength);
  1374. if (c && c != L'\\') {
  1375. continue;
  1376. }
  1377. if (LengthPtr) {
  1378. *LengthPtr = g_RegRoots[i].TextLength;
  1379. if (c) {
  1380. *LengthPtr += 1;
  1381. }
  1382. }
  1383. return i + 1;
  1384. }
  1385. }
  1386. return 0;
  1387. }
  1388. /*++
  1389. Routine Description:
  1390. GetOffsetOfRootKey returns a non-zero offset to the g_RegRoots table
  1391. corresponding to the root that matches the supplied HKEY. This offset
  1392. can be used with GetRootStringFromOffset and GetRootKeyFromOffset.
  1393. Arguments:
  1394. RootKey - Supplies the handle to locate in g_RegRoots table
  1395. Return Value:
  1396. A non-zero offset to the g_RegRoots table, or zero if the handle is not
  1397. a registry root.
  1398. --*/
  1399. INT
  1400. GetOffsetOfRootKey (
  1401. IN HKEY RootKey
  1402. )
  1403. {
  1404. INT i;
  1405. if (RootKey == g_Root) {
  1406. return 1;
  1407. }
  1408. for (i = 0 ; g_RegRoots[i].RootText ; i++) {
  1409. if (g_RegRoots[i].RootKey == RootKey) {
  1410. return i + 1;
  1411. }
  1412. }
  1413. return 0;
  1414. }
  1415. /*++
  1416. Routine Description:
  1417. GetRootStringFromOffset and GetRootKeyFromOffset return a pointer to a
  1418. static string or HKEY, respectively. If the offset supplied is invalid,
  1419. these functions return NULL.
  1420. Arguments:
  1421. i - The offset as returned by GetOffsetOfRootString or GetOffsetOfRootKey
  1422. Return Value:
  1423. A pointer to a static string/HKEY, or NULL if offset is invalid
  1424. --*/
  1425. PCSTR
  1426. GetRootStringFromOffsetA (
  1427. IN INT i
  1428. )
  1429. {
  1430. if (i < 1 || i > REGROOTS) {
  1431. return NULL;
  1432. }
  1433. return g_RegRoots[i - 1].RootText;
  1434. }
  1435. PCWSTR
  1436. GetRootStringFromOffsetW (
  1437. IN INT i
  1438. )
  1439. {
  1440. if (i < 1 || i > REGROOTS) {
  1441. return NULL;
  1442. }
  1443. return g_RegRoots[i - 1].WideRootText;
  1444. }
  1445. HKEY
  1446. GetRootKeyFromOffset (
  1447. IN INT i
  1448. )
  1449. {
  1450. HKEY Ret;
  1451. if (i < 1 || i > REGROOTS) {
  1452. return NULL;
  1453. }
  1454. Ret = g_RegRoots[i - 1].RootKey;
  1455. if (Ret == HKEY_ROOT) {
  1456. Ret = g_Root;
  1457. }
  1458. return Ret;
  1459. }
  1460. /*++
  1461. Routine Description:
  1462. ConvertRootStringToKey converts a registry key path's root to an HKEY.
  1463. Arguments:
  1464. RegPath - A pointer to a registry string that has a root at the begining
  1465. LengthPtr - An optional pointer to a variable that receives the length of
  1466. the root, including the joining backslash if it exists.
  1467. Return Value:
  1468. A handle to the registry key, or NULL if RegPath does not have a root
  1469. --*/
  1470. HKEY
  1471. ConvertRootStringToKeyA (
  1472. PCSTR RegPath,
  1473. PDWORD LengthPtr OPTIONAL
  1474. )
  1475. {
  1476. return GetRootKeyFromOffset (GetOffsetOfRootStringA (RegPath, LengthPtr));
  1477. }
  1478. HKEY
  1479. ConvertRootStringToKeyW (
  1480. PCWSTR RegPath,
  1481. PDWORD LengthPtr OPTIONAL
  1482. )
  1483. {
  1484. return GetRootKeyFromOffset (GetOffsetOfRootStringW (RegPath, LengthPtr));
  1485. }
  1486. /*++
  1487. Routine Description:
  1488. ConvertKeyToRootString converts a root HKEY to a registry root string
  1489. Arguments:
  1490. RegRoot - A handle to a registry root
  1491. Return Value:
  1492. A pointer to a static string, or NULL if RegRoot is not a valid registry
  1493. root handle
  1494. --*/
  1495. PCSTR
  1496. ConvertKeyToRootStringA (
  1497. HKEY RegRoot
  1498. )
  1499. {
  1500. return GetRootStringFromOffsetA (GetOffsetOfRootKey (RegRoot));
  1501. }
  1502. PCWSTR
  1503. ConvertKeyToRootStringW (
  1504. HKEY RegRoot
  1505. )
  1506. {
  1507. return GetRootStringFromOffsetW (GetOffsetOfRootKey (RegRoot));
  1508. }
  1509. /*++
  1510. Routine Description:
  1511. CreateEncodedRegistryStringEx is used to create a registry string in the format commonly
  1512. expected by w95upg reg routines. This format is:
  1513. EncodedKey\[EncodedValue]
  1514. Encoding is used to safely represent "special" characters
  1515. (such as MBS chars and certain punctuation marks.)
  1516. The [EncodedValue] part will exist only if Value is non null.
  1517. Arguments:
  1518. Key - Contains an unencoded registry key.
  1519. Value - Optionally contains an unencoded registry value.
  1520. Tree - Specifies that the registry key refers to the entire key
  1521. Return Value:
  1522. Returns a pointer to the encoded registry string, or NULL if there was an error.
  1523. --*/
  1524. PCSTR
  1525. CreateEncodedRegistryStringExA (
  1526. IN PCSTR Key,
  1527. IN PCSTR Value, OPTIONAL
  1528. IN BOOL Tree
  1529. )
  1530. {
  1531. PSTR rEncodedString = NULL;
  1532. DWORD requiredSize;
  1533. PSTR end;
  1534. //
  1535. // Determine required size and allocate buffer large enough to hold
  1536. // the encoded string.
  1537. //
  1538. requiredSize = (strlen(Key)*6 + (Value ? strlen(Value)*6 : 0) + 10) * sizeof(CHAR);
  1539. rEncodedString = AllocPathStringA(requiredSize);
  1540. //
  1541. // Encode the key portion of the string.
  1542. //
  1543. EncodeRuleCharsA(rEncodedString, requiredSize / sizeof(CHAR), Key);
  1544. //
  1545. // Finally, if a value exists, append it in encoded form. If a value does not exist,
  1546. // then add an '*' to the line.
  1547. //
  1548. if (Value) {
  1549. StringCopyA (AppendWackA (rEncodedString), "[");
  1550. end = GetEndOfStringA (rEncodedString);
  1551. EncodeRuleCharsA(end, requiredSize / sizeof(CHAR) - (end - rEncodedString) - 1, Value);
  1552. StringCatA(end, "]");
  1553. } else if (Tree) {
  1554. StringCopyA (AppendWackA (rEncodedString), "*");
  1555. }
  1556. return rEncodedString;
  1557. }
  1558. PCWSTR
  1559. CreateEncodedRegistryStringExW (
  1560. IN PCWSTR Key,
  1561. IN PCWSTR Value, OPTIONAL
  1562. IN BOOL Tree
  1563. )
  1564. {
  1565. PWSTR rEncodedString = NULL;
  1566. DWORD requiredSize;
  1567. PWSTR end;
  1568. //
  1569. // Determine required size and allocate buffer large enough to hold
  1570. // the encoded string.
  1571. //
  1572. requiredSize = (wcslen(Key)*6 + (Value ? wcslen(Value)*6 : 0) + 10) * sizeof(WCHAR);
  1573. rEncodedString = AllocPathStringW(requiredSize);
  1574. //
  1575. // Encode the key portion of the string.
  1576. //
  1577. EncodeRuleCharsW(rEncodedString, requiredSize / sizeof(WCHAR), Key);
  1578. //
  1579. // Finally, if a value exists, append it in encoded form.
  1580. // If a value doesn't exist, add na '*' to the line.
  1581. //
  1582. if (Value) {
  1583. StringCopyW (AppendWackW (rEncodedString), L"[");
  1584. end = GetEndOfStringW (rEncodedString);
  1585. EncodeRuleCharsW(end, requiredSize / sizeof(WCHAR) - (end - rEncodedString) - 1, Value);
  1586. StringCatW(end, L"]");
  1587. } else if (Tree) {
  1588. StringCopyW (AppendWackW (rEncodedString), L"*");
  1589. }
  1590. return rEncodedString;
  1591. }
  1592. /*++
  1593. Routine Description:
  1594. FreeEncodedRegistryString frees the memory allocated by a call to CreateEncodedRegistryString.
  1595. Arguments:
  1596. None.
  1597. Return Value:
  1598. None.
  1599. --*/
  1600. VOID
  1601. FreeEncodedRegistryStringA (
  1602. IN OUT PCSTR RegString
  1603. )
  1604. {
  1605. FreePathStringA(RegString);
  1606. }
  1607. VOID
  1608. FreeEncodedRegistryStringW (
  1609. IN OUT PCWSTR RegString
  1610. )
  1611. {
  1612. FreePathStringW(RegString);
  1613. }