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.

1218 lines
27 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. regenum.c
  5. Abstract:
  6. Implements utilties to enumerate the registry.
  7. Author:
  8. Jim Schmidt (jimschm) 20-Mar-1997
  9. Revisions:
  10. <alias> <date> <comment>
  11. --*/
  12. #include "pch.h"
  13. #include "migutilp.h"
  14. #include "regp.h"
  15. #define DBG_REG "Reg"
  16. //
  17. // Private prototypes
  18. //
  19. BOOL
  20. pPopRegKeyInfoA (
  21. IN PREGTREE_ENUMA EnumPtr
  22. );
  23. BOOL
  24. pPopRegKeyInfoW (
  25. IN PREGTREE_ENUMW EnumPtr
  26. );
  27. /*++
  28. Routine Description:
  29. EnumFirstRegKeyA and EnumFirstRegKeyW begin an enumeration of registry
  30. subkeys. They initialize the registy enumeration structure and
  31. call the registry APIs to enumerate subkeys of the specified key handle.
  32. Arguments:
  33. EnumPtr - Receives the updated state of enumeration. The structure
  34. can be accessed directly. It points to a REGKEY_ENUM structure
  35. in memory.
  36. Key - Specifies the handle of the registry key to enumerate.
  37. Return Value:
  38. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  39. Call GetLastError for the failure code.
  40. --*/
  41. BOOL
  42. EnumFirstRegKeyA (
  43. OUT PREGKEY_ENUMA EnumPtr,
  44. IN HKEY hKey
  45. )
  46. {
  47. ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMA));
  48. EnumPtr->KeyHandle = hKey;
  49. return EnumNextRegKeyA (EnumPtr);
  50. }
  51. BOOL
  52. EnumFirstRegKeyW (
  53. OUT PREGKEY_ENUMW EnumPtr,
  54. IN HKEY hKey
  55. )
  56. {
  57. ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMW));
  58. EnumPtr->KeyHandle = hKey;
  59. return EnumNextRegKeyW (EnumPtr);
  60. }
  61. /*++
  62. Routine Description:
  63. EnumFirstRegKeyStrA and EnumFirstRegKeyStrW start an enumeration of
  64. subkeys within the given key. In these functions, the key is specified
  65. via a string instead of an HKEY value.
  66. Arguments:
  67. EnumPtr - Receives the updated state of enumeration. The structure
  68. can be accessed directly. It points to a REGKEY_ENUM structure
  69. in memory.
  70. RegKey - Specifies the full path of the registry key to enumerate.
  71. Return Value:
  72. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  73. Call GetLastError for the failure code.
  74. --*/
  75. BOOL
  76. RealEnumFirstRegKeyStrA (
  77. OUT PREGKEY_ENUMA EnumPtr,
  78. IN PCSTR RegKey
  79. DEBUG_TRACKING_PARAMS
  80. )
  81. {
  82. HKEY Key;
  83. BOOL b;
  84. Key = RealOpenRegKeyStrA (RegKey /* , */ DEBUG_TRACKING_ARGS);
  85. if (!Key) {
  86. return FALSE;
  87. }
  88. b = EnumFirstRegKeyA (EnumPtr, Key);
  89. if (!b) {
  90. CloseRegKey (Key);
  91. } else {
  92. EnumPtr->OpenedByEnum = TRUE;
  93. }
  94. return b;
  95. }
  96. BOOL
  97. RealEnumFirstRegKeyStrW (
  98. IN PREGKEY_ENUMW EnumPtr,
  99. IN PCWSTR RegKey
  100. DEBUG_TRACKING_PARAMS
  101. )
  102. {
  103. HKEY Key;
  104. BOOL b;
  105. Key = RealOpenRegKeyStrW (RegKey /* , */ DEBUG_TRACKING_ARGS);
  106. if (!Key) {
  107. return FALSE;
  108. }
  109. b = EnumFirstRegKeyW (EnumPtr, Key);
  110. if (!b) {
  111. CloseRegKey (Key);
  112. } else {
  113. EnumPtr->OpenedByEnum = TRUE;
  114. }
  115. return b;
  116. }
  117. /*++
  118. Routine Description:
  119. AbortRegKeyEnumA and AbortRegKeyEnumW release all resources associated
  120. with a registry subkey enumeration. Call this function to stop the
  121. enumeration before it completes by itself.
  122. Arguments:
  123. EnumPtr - Specifies the enumeration to stop. Receives the updated
  124. state of enumeration.
  125. Return Value:
  126. none
  127. --*/
  128. VOID
  129. AbortRegKeyEnumA (
  130. IN OUT PREGKEY_ENUMA EnumPtr
  131. )
  132. {
  133. if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
  134. CloseRegKey (EnumPtr->KeyHandle);
  135. EnumPtr->KeyHandle = NULL;
  136. }
  137. }
  138. VOID
  139. AbortRegKeyEnumW (
  140. IN OUT PREGKEY_ENUMW EnumPtr
  141. )
  142. {
  143. if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
  144. CloseRegKey (EnumPtr->KeyHandle);
  145. EnumPtr->KeyHandle = NULL;
  146. }
  147. }
  148. /*++
  149. Routine Description:
  150. EnumNextRegKeyA and EnumNextRegKeyW continue an enumeration started by
  151. one of the subkey enumeration routines above. If all items have been
  152. enumerated, this function cleans up all resources and returns FALSE.
  153. Arguments:
  154. EnumPtr - Specifies the enumeration to continue. Receives the updated
  155. state of enumeration. The structure can be accessed directly.
  156. Return Value:
  157. TRUE if successful, or FALSE if an error or if no more subkeys are available.
  158. Call GetLastError for the failure code.
  159. --*/
  160. BOOL
  161. EnumNextRegKeyA (
  162. IN OUT PREGKEY_ENUMA EnumPtr
  163. )
  164. {
  165. LONG rc;
  166. rc = RegEnumKeyA (
  167. EnumPtr->KeyHandle,
  168. EnumPtr->Index,
  169. EnumPtr->SubKeyName,
  170. MAX_REGISTRY_KEYA
  171. );
  172. if (rc != ERROR_SUCCESS) {
  173. if (EnumPtr->OpenedByEnum) {
  174. CloseRegKey (EnumPtr->KeyHandle);
  175. EnumPtr->KeyHandle = NULL;
  176. }
  177. if (rc == ERROR_NO_MORE_ITEMS) {
  178. SetLastError (ERROR_SUCCESS);
  179. } else {
  180. SetLastError (rc);
  181. }
  182. return FALSE;
  183. }
  184. EnumPtr->Index += 1;
  185. return TRUE;
  186. }
  187. BOOL
  188. EnumNextRegKeyW (
  189. IN OUT PREGKEY_ENUMW EnumPtr
  190. )
  191. {
  192. LONG rc;
  193. rc = RegEnumKeyW (
  194. EnumPtr->KeyHandle,
  195. EnumPtr->Index,
  196. EnumPtr->SubKeyName,
  197. MAX_REGISTRY_KEYW
  198. );
  199. if (rc != ERROR_SUCCESS) {
  200. if (EnumPtr->OpenedByEnum) {
  201. CloseRegKey (EnumPtr->KeyHandle);
  202. EnumPtr->KeyHandle = NULL;
  203. }
  204. if (rc == ERROR_NO_MORE_ITEMS) {
  205. SetLastError (ERROR_SUCCESS);
  206. } else {
  207. SetLastError (rc);
  208. }
  209. return FALSE;
  210. }
  211. EnumPtr->Index += 1;
  212. return TRUE;
  213. }
  214. BOOL
  215. pPushRegKeyInfoA (
  216. IN PREGTREE_ENUMA EnumPtr,
  217. IN PCSTR KeyName
  218. )
  219. {
  220. PREGKEYINFOA RetVal;
  221. PSTR p;
  222. RetVal = (PREGKEYINFOA) PoolMemGetAlignedMemory (
  223. EnumPtr->EnumPool,
  224. sizeof (REGKEYINFOA)
  225. );
  226. if (!RetVal) {
  227. return FALSE;
  228. }
  229. //
  230. // Initialize struct to zero
  231. //
  232. ZeroMemory (RetVal, sizeof (REGKEYINFOA));
  233. //
  234. // Link parent and child pointers
  235. //
  236. RetVal->Parent = EnumPtr->CurrentKey;
  237. if (EnumPtr->CurrentKey) {
  238. EnumPtr->CurrentKey->Child = RetVal;
  239. }
  240. EnumPtr->CurrentKey = RetVal;
  241. //
  242. // Prepare full key path by appending the key name to the existing
  243. // base
  244. //
  245. RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
  246. p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
  247. //We must have enough space for the backslash & nul byte.
  248. if (EnumPtr->FullKeyNameBytes && (MAX_REGISTRY_KEYA > EnumPtr->FullKeyNameBytes + 1)) {
  249. StringCopyA (p, "\\");
  250. EnumPtr->FullKeyNameBytes += ByteCountA (p);
  251. p = _mbsinc (p);
  252. }
  253. //We must make sure that the EnumPtr->FullKeyName buffer is large enough to hold the
  254. //full key name, since we have not allowed enough space for a "maliciously" created key name.
  255. //In theory, a key name can be arbitrarily long, but its subkey names are limited to 512 bytes storage space.
  256. MYASSERT(MAX_REGISTRY_KEYA > EnumPtr->FullKeyNameBytes + ByteCountA (KeyName));
  257. _mbssafecpy (p, KeyName, MAX_REGISTRY_KEYA - EnumPtr->FullKeyNameBytes);
  258. EnumPtr->FullKeyNameBytes = ByteCountA (EnumPtr->FullKeyName);
  259. //
  260. // Save the key name independent of the full registry path.
  261. // Also open the key.
  262. //
  263. _mbssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYA);
  264. RetVal->KeyHandle = OpenRegKeyStrA (EnumPtr->FullKeyName);
  265. if (!RetVal->KeyHandle) {
  266. pPopRegKeyInfoA (EnumPtr);
  267. return FALSE;
  268. }
  269. return TRUE;
  270. }
  271. BOOL
  272. pPushRegKeyInfoW (
  273. IN PREGTREE_ENUMW EnumPtr,
  274. IN PCWSTR KeyName
  275. )
  276. {
  277. PREGKEYINFOW RetVal;
  278. PWSTR p;
  279. RetVal = (PREGKEYINFOW) PoolMemGetAlignedMemory (
  280. EnumPtr->EnumPool,
  281. sizeof (REGKEYINFOW)
  282. );
  283. if (!RetVal) {
  284. return FALSE;
  285. }
  286. //
  287. // Initialize struct to zero
  288. //
  289. ZeroMemory (RetVal, sizeof (REGKEYINFOW));
  290. //
  291. // Link parent and child pointers
  292. //
  293. RetVal->Parent = EnumPtr->CurrentKey;
  294. if (EnumPtr->CurrentKey) {
  295. EnumPtr->CurrentKey->Child = RetVal;
  296. }
  297. EnumPtr->CurrentKey = RetVal;
  298. //
  299. // Prepare full key path by appending the key name to the existing
  300. // base
  301. //
  302. RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
  303. p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
  304. //We must have enough space for the backslash & nul byte.
  305. if (EnumPtr->FullKeyNameBytes
  306. && (MAX_REGISTRY_KEYW > (EnumPtr->FullKeyNameBytes / sizeof (WCHAR)) + 1))
  307. {
  308. StringCopyW (p, L"\\");
  309. EnumPtr->FullKeyNameBytes += ByteCountW (p);
  310. p++;
  311. }
  312. //We must make sure that the EnumPtr->FullKeyName buffer is large enough to hold the
  313. //full key name, since we have not allowed enough space for a "maliciously" created key name.
  314. //In theory, a key name can be arbitrarily long, but its subkey names are limited to 512 bytes storage space.
  315. MYASSERT(MAX_REGISTRY_KEYW > (EnumPtr->FullKeyNameBytes + ByteCountW (KeyName)) / sizeof (WCHAR));
  316. _wcssafecpy (p, KeyName, MAX_REGISTRY_KEYW - (EnumPtr->FullKeyNameBytes / sizeof (WCHAR)));
  317. EnumPtr->FullKeyNameBytes = ByteCountW (EnumPtr->FullKeyName);
  318. //
  319. // Save the key name independent of the full registry path.
  320. // Also open the key.
  321. //
  322. _wcssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYW);
  323. RetVal->KeyHandle = OpenRegKeyStrW (EnumPtr->FullKeyName);
  324. if (!RetVal->KeyHandle) {
  325. pPopRegKeyInfoW (EnumPtr);
  326. return FALSE;
  327. }
  328. return TRUE;
  329. }
  330. BOOL
  331. pPopRegKeyInfoA (
  332. IN PREGTREE_ENUMA EnumPtr
  333. )
  334. {
  335. PREGKEYINFOA FreeMe;
  336. PSTR p;
  337. FreeMe = EnumPtr->CurrentKey;
  338. //
  339. // Skip if nothing was ever pushed
  340. //
  341. if (!FreeMe) {
  342. return FALSE;
  343. }
  344. //
  345. // Trim the full key string
  346. //
  347. EnumPtr->CurrentKey = FreeMe->Parent;
  348. EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
  349. p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
  350. *p = 0;
  351. //
  352. // Adjust the linkage
  353. //
  354. if (EnumPtr->CurrentKey) {
  355. EnumPtr->CurrentKey->Child = NULL;
  356. }
  357. //
  358. // Clean up resources
  359. //
  360. if (FreeMe->KeyHandle) {
  361. CloseRegKey (FreeMe->KeyHandle);
  362. }
  363. AbortRegKeyEnumA (&FreeMe->KeyEnum);
  364. PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
  365. //
  366. // Return FALSE if last item was poped
  367. //
  368. return EnumPtr->CurrentKey != NULL;
  369. }
  370. BOOL
  371. pPopRegKeyInfoW (
  372. IN PREGTREE_ENUMW EnumPtr
  373. )
  374. {
  375. PREGKEYINFOW FreeMe;
  376. PWSTR p;
  377. FreeMe = EnumPtr->CurrentKey;
  378. //
  379. // Skip if nothing was ever pushed
  380. //
  381. if (!FreeMe) {
  382. return FALSE;
  383. }
  384. //
  385. // Trim the full key string
  386. //
  387. EnumPtr->CurrentKey = FreeMe->Parent;
  388. EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
  389. p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
  390. *p = 0;
  391. //
  392. // Adjust the linkage
  393. //
  394. if (EnumPtr->CurrentKey) {
  395. EnumPtr->CurrentKey->Child = NULL;
  396. }
  397. //
  398. // Clean up resources
  399. //
  400. if (FreeMe->KeyHandle) {
  401. CloseRegKey (FreeMe->KeyHandle);
  402. }
  403. AbortRegKeyEnumW (&FreeMe->KeyEnum);
  404. PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
  405. //
  406. // Return FALSE if last item was poped
  407. //
  408. return EnumPtr->CurrentKey != NULL;
  409. }
  410. BOOL
  411. RealEnumFirstRegKeyInTreeA (
  412. OUT PREGTREE_ENUMA EnumPtr,
  413. IN PCSTR BaseKeyStr
  414. )
  415. {
  416. ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMA));
  417. //
  418. // Allocate pool for enum structs
  419. //
  420. EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTreeA");
  421. if (!EnumPtr->EnumPool) {
  422. return FALSE;
  423. }
  424. PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
  425. PoolMemDisableTracking (EnumPtr->EnumPool);
  426. //
  427. // Push base key on the enum stack
  428. //
  429. if (!pPushRegKeyInfoA (EnumPtr, BaseKeyStr)) {
  430. DEBUGMSG ((DBG_REG, "EnumFirstRegKeyInTreeA failed to push base key"));
  431. AbortRegKeyTreeEnumA (EnumPtr);
  432. return FALSE;
  433. }
  434. EnumPtr->EnumBaseBytes = ByteCountA (BaseKeyStr);
  435. //
  436. // Set state so EnumNextRegKeyInTree knows what to do
  437. //
  438. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  439. return TRUE;
  440. }
  441. BOOL
  442. RealEnumFirstRegKeyInTreeW (
  443. OUT PREGTREE_ENUMW EnumPtr,
  444. IN PCWSTR BaseKeyStr
  445. )
  446. {
  447. ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMW));
  448. //
  449. // Allocate pool for enum structs
  450. //
  451. EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTreeW");
  452. if (!EnumPtr->EnumPool) {
  453. return FALSE;
  454. }
  455. PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
  456. PoolMemDisableTracking (EnumPtr->EnumPool);
  457. //
  458. // Push base key on the enum stack
  459. //
  460. if (!pPushRegKeyInfoW (EnumPtr, BaseKeyStr)) {
  461. DEBUGMSG ((DBG_REG, "EnumFirstRegKeyInTreeW failed to push base key"));
  462. AbortRegKeyTreeEnumW (EnumPtr);
  463. return FALSE;
  464. }
  465. EnumPtr->EnumBaseBytes = ByteCountW (BaseKeyStr);
  466. //
  467. // Set state so EnumNextRegKeyInTree knows what to do
  468. //
  469. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  470. return TRUE;
  471. }
  472. BOOL
  473. RealEnumNextRegKeyInTreeA (
  474. IN OUT PREGTREE_ENUMA EnumPtr
  475. )
  476. {
  477. if (EnumPtr->State == NO_MORE_ITEMS) {
  478. return FALSE;
  479. }
  480. for (;;) {
  481. switch (EnumPtr->State) {
  482. case ENUMERATE_SUBKEY_BEGIN:
  483. //
  484. // Start enumeration
  485. //
  486. if (EnumFirstRegKeyA (
  487. &EnumPtr->CurrentKey->KeyEnum,
  488. EnumPtr->CurrentKey->KeyHandle
  489. )) {
  490. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  491. } else {
  492. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  493. }
  494. break;
  495. case ENUMERATE_SUBKEY_NEXT:
  496. //
  497. // Continue enumerations
  498. //
  499. if (EnumNextRegKeyA (&EnumPtr->CurrentKey->KeyEnum)) {
  500. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  501. } else {
  502. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  503. }
  504. break;
  505. case ENUMERATE_SUBKEY_DONE:
  506. //
  507. // Enumeration of this key is done; pop and continue.
  508. //
  509. if (!pPopRegKeyInfoA (EnumPtr)) {
  510. EnumPtr->State = NO_MORE_ITEMS;
  511. AbortRegKeyTreeEnumA (EnumPtr);
  512. } else {
  513. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  514. }
  515. break;
  516. case ENUMERATE_SUBKEY_RETURN:
  517. //
  518. // Return enumerated item to caller
  519. //
  520. if (!pPushRegKeyInfoA (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
  521. DEBUGMSGA ((
  522. DBG_REG,
  523. "RealEnumNextRegKeyInTreeA failed to push sub key %s",
  524. EnumPtr->CurrentKey->KeyEnum.SubKeyName
  525. ));
  526. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  527. break;
  528. }
  529. if (!EnumPtr->FirstEnumerated) {
  530. EnumPtr->FirstEnumerated = TRUE;
  531. EnumPtr->EnumBaseBytes += sizeof (CHAR);
  532. }
  533. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  534. return TRUE;
  535. default:
  536. MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
  537. return FALSE;
  538. }
  539. }
  540. }
  541. BOOL
  542. RealEnumNextRegKeyInTreeW (
  543. IN OUT PREGTREE_ENUMW EnumPtr
  544. )
  545. {
  546. if (EnumPtr->State == NO_MORE_ITEMS) {
  547. return FALSE;
  548. }
  549. for (;;) {
  550. switch (EnumPtr->State) {
  551. case ENUMERATE_SUBKEY_BEGIN:
  552. //
  553. // Start enumeration
  554. //
  555. if (EnumFirstRegKeyW (
  556. &EnumPtr->CurrentKey->KeyEnum,
  557. EnumPtr->CurrentKey->KeyHandle
  558. )) {
  559. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  560. } else {
  561. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  562. }
  563. break;
  564. case ENUMERATE_SUBKEY_NEXT:
  565. //
  566. // Continue enumerations
  567. //
  568. if (EnumNextRegKeyW (&EnumPtr->CurrentKey->KeyEnum)) {
  569. EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
  570. } else {
  571. EnumPtr->State = ENUMERATE_SUBKEY_DONE;
  572. }
  573. break;
  574. case ENUMERATE_SUBKEY_DONE:
  575. //
  576. // Enumeration of this key is done; pop and continue.
  577. //
  578. if (!pPopRegKeyInfoW (EnumPtr)) {
  579. EnumPtr->State = NO_MORE_ITEMS;
  580. AbortRegKeyTreeEnumW (EnumPtr);
  581. } else {
  582. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  583. }
  584. break;
  585. case ENUMERATE_SUBKEY_RETURN:
  586. //
  587. // Return enumerated item to caller
  588. //
  589. if (!pPushRegKeyInfoW (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
  590. DEBUGMSGW ((
  591. DBG_REG,
  592. "RealEnumNextRegKeyInTreeW failed to push sub key %s",
  593. EnumPtr->CurrentKey->KeyEnum.SubKeyName
  594. ));
  595. EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
  596. break;
  597. }
  598. if (!EnumPtr->FirstEnumerated) {
  599. EnumPtr->FirstEnumerated = TRUE;
  600. EnumPtr->EnumBaseBytes += sizeof (WCHAR);
  601. }
  602. EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
  603. return TRUE;
  604. default:
  605. MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
  606. return FALSE;
  607. }
  608. }
  609. }
  610. VOID
  611. AbortRegKeyTreeEnumA (
  612. IN OUT PREGTREE_ENUMA EnumPtr
  613. )
  614. {
  615. //
  616. // Free all resources
  617. //
  618. while (pPopRegKeyInfoA (EnumPtr)) {
  619. }
  620. PoolMemDestroyPool (EnumPtr->EnumPool);
  621. }
  622. VOID
  623. AbortRegKeyTreeEnumW (
  624. IN OUT PREGTREE_ENUMW EnumPtr
  625. )
  626. {
  627. //
  628. // Free all resources
  629. //
  630. while (pPopRegKeyInfoW (EnumPtr)) {
  631. }
  632. PoolMemDestroyPool (EnumPtr->EnumPool);
  633. }
  634. /*++
  635. Routine Description:
  636. EnumFirstRegValueA and EnumerateFirstRegvalueW enumerate the first registry
  637. value name in the specified subkey.
  638. Arguments:
  639. EnumPtr - Receives the updated state of enumeration. The structure
  640. can be accessed directly.
  641. hKey - Specifies handle of registry subkey to enumerate.
  642. Return Value:
  643. TRUE if successful, or FALSE if an error or if no more values are available.
  644. Call GetLastError for the failure code.
  645. --*/
  646. BOOL
  647. EnumFirstRegValueA (
  648. IN PREGVALUE_ENUMA EnumPtr,
  649. IN HKEY hKey
  650. )
  651. {
  652. ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMA));
  653. EnumPtr->KeyHandle = hKey;
  654. return EnumNextRegValueA (EnumPtr);
  655. }
  656. BOOL
  657. EnumFirstRegValueW (
  658. IN PREGVALUE_ENUMW EnumPtr,
  659. IN HKEY hKey
  660. )
  661. {
  662. ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMW));
  663. EnumPtr->KeyHandle = hKey;
  664. return EnumNextRegValueW (EnumPtr);
  665. }
  666. /*++
  667. Routine Description:
  668. EnumNextRegValueA and EnumNextRegValueW continue the enumeration started
  669. by EnumFirstRegValueA/W. The enumeration structure is updated to
  670. reflect the next value name in the subkey being enumerated.
  671. Arguments:
  672. EnumPtr - Specifies the registry subkey and enumeration position.
  673. Receives the updated state of enumeration. The structure
  674. can be accessed directly.
  675. Return Value:
  676. TRUE if successful, or FALSE if an error or if no more values are available.
  677. Call GetLastError for the failure code.
  678. --*/
  679. BOOL
  680. EnumNextRegValueA (
  681. IN OUT PREGVALUE_ENUMA EnumPtr
  682. )
  683. {
  684. LONG rc;
  685. DWORD ValueNameSize;
  686. ValueNameSize = MAX_REGISTRY_VALUE_NAMEA;
  687. rc = RegEnumValueA (
  688. EnumPtr->KeyHandle,
  689. EnumPtr->Index,
  690. EnumPtr->ValueName,
  691. &ValueNameSize,
  692. NULL,
  693. &EnumPtr->Type,
  694. NULL,
  695. &EnumPtr->DataSize
  696. );
  697. if (rc == ERROR_NO_MORE_ITEMS) {
  698. SetLastError (ERROR_SUCCESS);
  699. return FALSE;
  700. } else if (rc != ERROR_SUCCESS) {
  701. SetLastError (rc);
  702. return FALSE;
  703. }
  704. EnumPtr->Index += 1;
  705. return TRUE;
  706. }
  707. BOOL
  708. EnumNextRegValueW (
  709. IN OUT PREGVALUE_ENUMW EnumPtr
  710. )
  711. {
  712. LONG rc;
  713. DWORD ValueNameSize;
  714. ValueNameSize = MAX_REGISTRY_VALUE_NAMEW;
  715. rc = RegEnumValueW (
  716. EnumPtr->KeyHandle,
  717. EnumPtr->Index,
  718. EnumPtr->ValueName,
  719. &ValueNameSize,
  720. NULL,
  721. &EnumPtr->Type,
  722. NULL,
  723. &EnumPtr->DataSize
  724. );
  725. if (rc == ERROR_NO_MORE_ITEMS) {
  726. SetLastError (ERROR_SUCCESS);
  727. return FALSE;
  728. } else if (rc != ERROR_SUCCESS) {
  729. SetLastError (rc);
  730. return FALSE;
  731. }
  732. EnumPtr->Index += 1;
  733. return TRUE;
  734. }
  735. /*++
  736. Routine Description:
  737. DecodeRegistryString turns an encoded string back into a key, value name
  738. and tree flag.
  739. The caller must pass in buffers at least as big as MAX_REGISTRY_KEY and
  740. MAX_REGISTRY_VALUE_NAME.
  741. Arguments:
  742. RegString - Specifies the encoded registry string that contains a key name,
  743. and an optional value name or tree flag.
  744. KeyBuf - Optionally receives the key name (points to a buffer of size MAX_REGISTRY_KEY)
  745. ValueBuf - Optionally receives the value name (points to a buffer of
  746. size MAX_REGISTRY_VALUE_NAME)
  747. TreeFlag - Optionally receives the tree flag, TRUE if the encoded string indicates a
  748. registry key tree, FALSE otherwise.
  749. Return Value:
  750. TRUE if the encoded string contained a value, FALSE if it contained just a
  751. key or key tree.
  752. --*/
  753. BOOL
  754. DecodeRegistryStringA (
  755. IN PCSTR RegString,
  756. OUT PSTR KeyBuf, OPTIONAL
  757. OUT PSTR ValueBuf, OPTIONAL
  758. OUT PBOOL TreeFlag OPTIONAL
  759. )
  760. {
  761. CHAR TempKeyBuf[MAX_REGISTRY_KEY];
  762. PSTR End;
  763. CHAR TempValueNameBuf[MAX_REGISTRY_VALUE_NAME];
  764. BOOL TempTreeFlag = FALSE;
  765. MBCHAR ch;
  766. PSTR p;
  767. BOOL b = FALSE;
  768. //
  769. // Walk through encoded string, pulling out key name
  770. //
  771. TempKeyBuf[0] = 0;
  772. TempValueNameBuf[0] = 0;
  773. End = TempKeyBuf + ARRAYSIZE(TempKeyBuf) - 2;
  774. p = TempKeyBuf;
  775. while (*RegString && *RegString != '*' && *RegString != '[') {
  776. ch = GetNextRuleCharA (&RegString, NULL);
  777. *((PWORD) p) = (WORD)ch;
  778. p = _mbsinc (p);
  779. if (p >= End) {
  780. RegString = GetEndOfStringA (RegString);
  781. break;
  782. }
  783. }
  784. *p = 0;
  785. p = (PSTR) SkipSpaceRA (TempKeyBuf, p);
  786. *(_mbsinc (p)) = 0;
  787. if (*RegString == '*' && _mbsnextc (p) == '\\') {
  788. //
  789. // If a tree, stop here
  790. //
  791. TempTreeFlag = TRUE;
  792. *p = 0;
  793. } else if (*RegString == '[') {
  794. //
  795. // If a value name, parse it
  796. //
  797. RegString++;
  798. End = TempValueNameBuf + ARRAYSIZE(TempValueNameBuf) - 2;
  799. p = TempValueNameBuf;
  800. while (*RegString && *RegString != ']') {
  801. ch = GetNextRuleCharA (&RegString, NULL);
  802. *((PWORD) p) = (WORD)ch;
  803. p = _mbsinc (p);
  804. if (p >= End) {
  805. RegString = GetEndOfStringA (RegString);
  806. break;
  807. }
  808. }
  809. *p = 0;
  810. p = (PSTR) SkipSpaceRA (TempValueNameBuf, p);
  811. if (p) // Guard against empty or all-whitespace value name.
  812. *(p + 1) = 0;
  813. RemoveWackAtEndA (TempKeyBuf);
  814. b = TRUE;
  815. }
  816. if (KeyBuf) {
  817. StringCopyA (KeyBuf, TempKeyBuf);
  818. }
  819. if (ValueBuf) {
  820. StringCopyA (ValueBuf, TempValueNameBuf);
  821. }
  822. if (TreeFlag) {
  823. *TreeFlag = TempTreeFlag;
  824. }
  825. return b;
  826. }
  827. BOOL
  828. DecodeRegistryStringW (
  829. IN PCWSTR RegString,
  830. OUT PWSTR KeyBuf, OPTIONAL
  831. OUT PWSTR ValueBuf, OPTIONAL
  832. OUT PBOOL TreeFlag OPTIONAL
  833. )
  834. {
  835. WCHAR TempKeyBuf[MAX_REGISTRY_KEY];
  836. PWSTR End;
  837. WCHAR TempValueNameBuf[MAX_REGISTRY_VALUE_NAME];
  838. BOOL TempTreeFlag = FALSE;
  839. WCHAR ch;
  840. PWSTR p;
  841. BOOL b = FALSE;
  842. //
  843. // Walk through encoded string, pulling out key name
  844. //
  845. TempKeyBuf[0] = 0;
  846. TempValueNameBuf[0] = 0;
  847. End = TempKeyBuf + ARRAYSIZE(TempKeyBuf) - 2;
  848. p = TempKeyBuf;
  849. while (*RegString && *RegString != L'*' && *RegString != L'[') {
  850. ch = GetNextRuleCharW (&RegString, NULL);
  851. *((PWORD) p) = ch;
  852. p++;
  853. if (p >= End) {
  854. RegString = GetEndOfStringW (RegString);
  855. break;
  856. }
  857. }
  858. *p = 0;
  859. p = (PWSTR) SkipSpaceRW (TempKeyBuf, p);
  860. if (!p) {
  861. return FALSE;
  862. }
  863. *(p + 1) = 0;
  864. if (*RegString == L'*' && *p == L'\\') {
  865. //
  866. // If a tree, stop here
  867. //
  868. TempTreeFlag = TRUE;
  869. *p = 0;
  870. } else if (*RegString == L'[') {
  871. //
  872. // If a value name, parse it
  873. //
  874. RegString++;
  875. End = TempValueNameBuf + ARRAYSIZE(TempValueNameBuf) - 2;
  876. p = TempValueNameBuf;
  877. while (*RegString && *RegString != L']') {
  878. ch = GetNextRuleCharW (&RegString, NULL);
  879. *((PWORD) p) = ch;
  880. p++;
  881. if (p >= End) {
  882. RegString = GetEndOfStringW (RegString);
  883. break;
  884. }
  885. }
  886. *p = 0;
  887. p = (PWSTR) SkipSpaceRW (TempValueNameBuf, p);
  888. if (p) { // Guard against empty or all-whitespace value name.
  889. *(p + 1) = 0;
  890. }
  891. RemoveWackAtEndW (TempKeyBuf);
  892. b = TRUE;
  893. }
  894. if (KeyBuf) {
  895. StringCopyW (KeyBuf, TempKeyBuf);
  896. }
  897. if (ValueBuf) {
  898. StringCopyW (ValueBuf, TempValueNameBuf);
  899. }
  900. if (TreeFlag) {
  901. *TreeFlag = TempTreeFlag;
  902. }
  903. return b;
  904. }