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.

2796 lines
78 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. regenum.c
  5. Abstract:
  6. Implements a set of APIs to enumerate the local registry using Win32 APIs.
  7. Author:
  8. 20-Oct-1999 Ovidiu Temereanca (ovidiut) - File creation.
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. #include "reg.h"
  14. //
  15. // Includes
  16. //
  17. // None
  18. #define DBG_REGENUM "RegEnum"
  19. //
  20. // Strings
  21. //
  22. #define S_REGENUM "REGENUM"
  23. //
  24. // Constants
  25. //
  26. // None
  27. //
  28. // Macros
  29. //
  30. #define pAllocateMemory(Size) PmGetMemory (g_RegEnumPool,Size)
  31. #define pFreeMemory(Buffer) if (Buffer) PmReleaseMemory (g_RegEnumPool, (PVOID)Buffer)
  32. //
  33. // Types
  34. //
  35. // None
  36. //
  37. // Globals
  38. //
  39. PMHANDLE g_RegEnumPool;
  40. //
  41. // Macro expansion list
  42. //
  43. // None
  44. //
  45. // Private function prototypes
  46. //
  47. // None
  48. //
  49. // Macro expansion definition
  50. //
  51. // None
  52. //
  53. // Code
  54. //
  55. BOOL
  56. RegEnumInitialize (
  57. VOID
  58. )
  59. /*++
  60. Routine Description:
  61. RegEnumInitialize initializes this library.
  62. Arguments:
  63. none
  64. Return Value:
  65. TRUE if the init was successful.
  66. FALSE if not. GetLastError() returns extended error info.
  67. --*/
  68. {
  69. g_RegEnumPool = PmCreateNamedPool (S_REGENUM);
  70. return g_RegEnumPool != NULL;
  71. }
  72. VOID
  73. RegEnumTerminate (
  74. VOID
  75. )
  76. /*++
  77. Routine Description:
  78. RegEnumTerminate is called to free resources used by this lib.
  79. Arguments:
  80. none
  81. Return Value:
  82. none
  83. --*/
  84. {
  85. DumpOpenKeys ();
  86. if (g_RegEnumPool) {
  87. PmDestroyPool (g_RegEnumPool);
  88. g_RegEnumPool = NULL;
  89. }
  90. }
  91. BOOL
  92. RegEnumDefaultCallbackA (
  93. IN PREGNODEA RegNode OPTIONAL
  94. )
  95. {
  96. return TRUE;
  97. }
  98. BOOL
  99. RegEnumDefaultCallbackW (
  100. IN PREGNODEW RegNode OPTIONAL
  101. )
  102. {
  103. return TRUE;
  104. }
  105. INT g_RootEnumIndexTable [] = { 2, 4, 6, 8, -1};
  106. BOOL
  107. EnumFirstRegRootA (
  108. OUT PREGROOT_ENUMA EnumPtr
  109. )
  110. {
  111. EnumPtr->Index = 0;
  112. return EnumNextRegRootA (EnumPtr);
  113. }
  114. BOOL
  115. EnumFirstRegRootW (
  116. OUT PREGROOT_ENUMW EnumPtr
  117. )
  118. {
  119. EnumPtr->Index = 0;
  120. return EnumNextRegRootW (EnumPtr);
  121. }
  122. BOOL
  123. EnumNextRegRootA (
  124. IN OUT PREGROOT_ENUMA EnumPtr
  125. )
  126. {
  127. INT i;
  128. LONG result;
  129. i = g_RootEnumIndexTable [EnumPtr->Index];
  130. while (i >= 0) {
  131. EnumPtr->RegRootName = GetRootStringFromOffsetA (i);
  132. EnumPtr->RegRootHandle = GetRootKeyFromOffset(i);
  133. EnumPtr->Index++;
  134. result = RegQueryInfoKey (
  135. EnumPtr->RegRootHandle,
  136. NULL,
  137. NULL,
  138. NULL,
  139. NULL,
  140. NULL,
  141. NULL,
  142. NULL,
  143. NULL,
  144. NULL,
  145. NULL,
  146. NULL
  147. );
  148. if (result == ERROR_SUCCESS) {
  149. return TRUE;
  150. }
  151. i = g_RootEnumIndexTable [EnumPtr->Index];
  152. }
  153. return FALSE;
  154. }
  155. BOOL
  156. EnumNextRegRootW (
  157. IN OUT PREGROOT_ENUMW EnumPtr
  158. )
  159. {
  160. INT i;
  161. LONG result;
  162. i = g_RootEnumIndexTable [EnumPtr->Index];
  163. while (i >= 0) {
  164. EnumPtr->RegRootName = GetRootStringFromOffsetW (i);
  165. EnumPtr->RegRootHandle = GetRootKeyFromOffset(i);
  166. EnumPtr->Index++;
  167. result = RegQueryInfoKey (
  168. EnumPtr->RegRootHandle,
  169. NULL,
  170. NULL,
  171. NULL,
  172. NULL,
  173. NULL,
  174. NULL,
  175. NULL,
  176. NULL,
  177. NULL,
  178. NULL,
  179. NULL
  180. );
  181. if (result == ERROR_SUCCESS) {
  182. return TRUE;
  183. }
  184. i = g_RootEnumIndexTable [EnumPtr->Index];
  185. }
  186. return FALSE;
  187. }
  188. /*++
  189. Routine Description:
  190. pGetRegEnumInfo is a private function that validates and translates the enumeration info
  191. in an internal form that's more accessible to the enum routines
  192. Arguments:
  193. RegEnumInfo - Receives the enum info
  194. EncodedRegPattern - Specifies the encoded pattern (encoded as defined by the
  195. ObjectString functions)
  196. EnumKeyNames - Specifies TRUE if key names should be returned during the enumeration
  197. (if they match the pattern); a key name is returned before any of its
  198. subkeys or values
  199. ContainersFirst - Specifies TRUE if keys should be returned before any of its
  200. values or subkeys; used only if EnumKeyNames is TRUE
  201. ValuesFirst - Specifies TRUE if a key's values should be returned before key's subkeys;
  202. this parameter decides the enum order between values and subkeys
  203. for each key
  204. DepthFirst - Specifies TRUE if the current subkey of any key should be fully enumerated
  205. before going to the next subkey; this parameter decides if the tree
  206. traversal is depth-first (TRUE) or width-first (FALSE)
  207. MaxSubLevel - Specifies the maximum level of a key that is to be enumerated, relative to
  208. the root; if -1, all sub-levels are enumerated
  209. UseExclusions - Specifies TRUE if exclusion APIs should be used to determine if certain
  210. keys/values are excluded from enumeration; this slows down the speed
  211. ReadValueData - Specifies TRUE if data associated with values should also be returned
  212. Return Value:
  213. TRUE if all params are valid; in this case, RegEnumInfo is filled with the corresponding
  214. info.
  215. FALSE otherwise.
  216. --*/
  217. BOOL
  218. pGetRegEnumInfoA (
  219. OUT PREGENUMINFOA RegEnumInfo,
  220. IN PCSTR EncodedRegPattern,
  221. IN BOOL EnumKeyNames,
  222. IN BOOL ContainersFirst,
  223. IN BOOL ValuesFirst,
  224. IN BOOL DepthFirst,
  225. IN DWORD MaxSubLevel,
  226. IN BOOL UseExclusions,
  227. IN BOOL ReadValueData
  228. )
  229. {
  230. RegEnumInfo->RegPattern = ObsCreateParsedPatternA (EncodedRegPattern);
  231. if (!RegEnumInfo->RegPattern) {
  232. DEBUGMSGA ((DBG_ERROR, "pGetRegEnumInfoA: bad EncodedRegPattern: %s", EncodedRegPattern));
  233. return FALSE;
  234. }
  235. if (RegEnumInfo->RegPattern->ExactRoot) {
  236. if (!GetNodePatternMinMaxLevelsA (
  237. RegEnumInfo->RegPattern->ExactRoot,
  238. NULL,
  239. &RegEnumInfo->RootLevel,
  240. NULL
  241. )) {
  242. return FALSE;
  243. }
  244. } else {
  245. RegEnumInfo->RootLevel = 1;
  246. }
  247. if (!RegEnumInfo->RegPattern->Leaf) {
  248. //
  249. // no value pattern specified; assume only keynames will be returned
  250. // overwrite caller's setting
  251. //
  252. DEBUGMSGA ((
  253. DBG_REGENUM,
  254. "pGetRegEnumInfoA: no value pattern specified; forcing EnumDirNames to TRUE"
  255. ));
  256. EnumKeyNames = TRUE;
  257. }
  258. if (EnumKeyNames) {
  259. RegEnumInfo->Flags |= REIF_RETURN_KEYS;
  260. }
  261. if (ContainersFirst) {
  262. RegEnumInfo->Flags |= REIF_CONTAINERS_FIRST;
  263. }
  264. if (ValuesFirst) {
  265. RegEnumInfo->Flags |= REIF_VALUES_FIRST;
  266. }
  267. if (DepthFirst) {
  268. RegEnumInfo->Flags |= REIF_DEPTH_FIRST;
  269. }
  270. if (UseExclusions) {
  271. RegEnumInfo->Flags |= REIF_USE_EXCLUSIONS;
  272. }
  273. if (ReadValueData) {
  274. RegEnumInfo->Flags |= REIF_READ_VALUE_DATA;
  275. }
  276. RegEnumInfo->MaxSubLevel = min (MaxSubLevel, RegEnumInfo->RegPattern->MaxSubLevel);
  277. return TRUE;
  278. }
  279. BOOL
  280. pGetRegEnumInfoW (
  281. OUT PREGENUMINFOW RegEnumInfo,
  282. IN PCWSTR EncodedRegPattern,
  283. IN BOOL EnumKeyNames,
  284. IN BOOL ContainersFirst,
  285. IN BOOL ValuesFirst,
  286. IN BOOL DepthFirst,
  287. IN DWORD MaxSubLevel,
  288. IN BOOL UseExclusions,
  289. IN BOOL ReadValueData
  290. )
  291. {
  292. RegEnumInfo->RegPattern = ObsCreateParsedPatternW (EncodedRegPattern);
  293. if (!RegEnumInfo->RegPattern) {
  294. DEBUGMSGW ((DBG_ERROR, "pGetRegEnumInfoW: bad EncodedRegPattern: %s", EncodedRegPattern));
  295. return FALSE;
  296. }
  297. if (RegEnumInfo->RegPattern->ExactRoot) {
  298. if (!GetNodePatternMinMaxLevelsW (
  299. RegEnumInfo->RegPattern->ExactRoot, //lint !e64
  300. NULL,
  301. &RegEnumInfo->RootLevel,
  302. NULL
  303. )) { //lint !e64
  304. return FALSE;
  305. }
  306. } else {
  307. RegEnumInfo->RootLevel = 1;
  308. }
  309. if (!RegEnumInfo->RegPattern->Leaf) {
  310. //
  311. // no value pattern specified; assume only keynames will be returned
  312. // overwrite caller's setting
  313. //
  314. DEBUGMSGW ((
  315. DBG_REGENUM,
  316. "pGetRegEnumInfoW: no value pattern specified; forcing EnumDirNames to TRUE"
  317. ));
  318. EnumKeyNames = TRUE;
  319. }
  320. if (EnumKeyNames) {
  321. RegEnumInfo->Flags |= REIF_RETURN_KEYS;
  322. }
  323. if (ContainersFirst) {
  324. RegEnumInfo->Flags |= REIF_CONTAINERS_FIRST;
  325. }
  326. if (ValuesFirst) {
  327. RegEnumInfo->Flags |= REIF_VALUES_FIRST;
  328. }
  329. if (DepthFirst) {
  330. RegEnumInfo->Flags |= REIF_DEPTH_FIRST;
  331. }
  332. if (UseExclusions) {
  333. RegEnumInfo->Flags |= REIF_USE_EXCLUSIONS;
  334. }
  335. if (ReadValueData) {
  336. RegEnumInfo->Flags |= REIF_READ_VALUE_DATA;
  337. }
  338. RegEnumInfo->MaxSubLevel = min (MaxSubLevel, RegEnumInfo->RegPattern->MaxSubLevel);
  339. return TRUE;
  340. }
  341. /*++
  342. Routine Description:
  343. pGetRegNodeInfo retrieves information about a key, using its name
  344. Arguments:
  345. RegNode - Receives information about this key
  346. ReadData - Specifies if the data associated with this value should be read
  347. Return Value:
  348. TRUE if info was successfully read, FALSE otherwise.
  349. --*/
  350. BOOL
  351. pGetRegNodeInfoA (
  352. IN OUT PREGNODEA RegNode,
  353. IN BOOL ReadData
  354. )
  355. {
  356. LONG rc;
  357. rc = RegQueryInfoKeyA (
  358. RegNode->KeyHandle,
  359. NULL,
  360. NULL,
  361. NULL,
  362. &RegNode->SubKeyCount,
  363. &RegNode->SubKeyLengthMax,
  364. NULL,
  365. &RegNode->ValueCount,
  366. &RegNode->ValueLengthMax,
  367. ReadData ? &RegNode->ValueDataSizeMax : NULL,
  368. NULL,
  369. NULL
  370. );
  371. if (rc != ERROR_SUCCESS) {
  372. return FALSE;
  373. }
  374. if (RegNode->SubKeyCount) {
  375. if (RegNode->SubKeyLengthMax) {
  376. //
  377. // add space for the NULL
  378. //
  379. RegNode->SubKeyLengthMax++;
  380. } else {
  381. //
  382. // OS bug
  383. //
  384. RegNode->SubKeyLengthMax = MAX_REGISTRY_KEYA;
  385. }
  386. RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (MBCHAR));
  387. }
  388. if (RegNode->ValueCount) {
  389. //
  390. // add space for the NULL
  391. //
  392. RegNode->ValueLengthMax++;
  393. RegNode->ValueName = pAllocateMemory (RegNode->ValueLengthMax * DWSIZEOF (MBCHAR));
  394. if (ReadData) {
  395. RegNode->ValueDataSizeMax++;
  396. RegNode->ValueData = pAllocateMemory (RegNode->ValueDataSizeMax);
  397. }
  398. RegNode->Flags |= RNF_VALUENAME_INVALID | RNF_VALUEDATA_INVALID;
  399. }
  400. return TRUE;
  401. }
  402. BOOL
  403. pGetRegNodeInfoW (
  404. IN OUT PREGNODEW RegNode,
  405. IN BOOL ReadData
  406. )
  407. {
  408. LONG rc;
  409. rc = RegQueryInfoKeyW (
  410. RegNode->KeyHandle,
  411. NULL,
  412. NULL,
  413. NULL,
  414. &RegNode->SubKeyCount,
  415. &RegNode->SubKeyLengthMax,
  416. NULL,
  417. &RegNode->ValueCount,
  418. &RegNode->ValueLengthMax,
  419. ReadData ? &RegNode->ValueDataSizeMax : NULL,
  420. NULL,
  421. NULL
  422. );
  423. if (rc != ERROR_SUCCESS) {
  424. return FALSE;
  425. }
  426. if (RegNode->SubKeyCount) {
  427. if (RegNode->SubKeyLengthMax) {
  428. //
  429. // add space for the NULL
  430. //
  431. RegNode->SubKeyLengthMax++;
  432. } else {
  433. //
  434. // OS bug
  435. //
  436. RegNode->SubKeyLengthMax = MAX_REGISTRY_KEYW;
  437. }
  438. RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (WCHAR));
  439. }
  440. if (RegNode->ValueCount) {
  441. //
  442. // add space for the NULL
  443. //
  444. RegNode->ValueLengthMax++;
  445. RegNode->ValueName = pAllocateMemory (RegNode->ValueLengthMax * DWSIZEOF (WCHAR));
  446. if (ReadData) {
  447. RegNode->ValueDataSizeMax++;
  448. RegNode->ValueData = pAllocateMemory (RegNode->ValueDataSizeMax);
  449. }
  450. RegNode->Flags |= RNF_VALUENAME_INVALID | RNF_VALUEDATA_INVALID;
  451. }
  452. return TRUE;
  453. }
  454. /*++
  455. Routine Description:
  456. pGetCurrentRegNode returns the current reg node to be enumerated, based on DepthFirst flag
  457. Arguments:
  458. RegEnum - Specifies the context
  459. LastCreated - Specifies TRUE if the last created node is to be retrieved, regardless of
  460. DepthFirst flag
  461. Return Value:
  462. The current node if any or NULL if none remaining.
  463. --*/
  464. PREGNODEA
  465. pGetCurrentRegNodeA (
  466. IN PREGTREE_ENUMA RegEnum,
  467. IN BOOL LastCreated
  468. )
  469. {
  470. PGROWBUFFER gb = &RegEnum->RegNodes;
  471. if (gb->End - gb->UserIndex < DWSIZEOF (REGNODEA)) {
  472. return NULL;
  473. }
  474. if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) {
  475. return (PREGNODEA)(gb->Buf + gb->End) - 1;
  476. } else {
  477. return (PREGNODEA)(gb->Buf + gb->UserIndex);
  478. }
  479. }
  480. PREGNODEW
  481. pGetCurrentRegNodeW (
  482. IN PREGTREE_ENUMW RegEnum,
  483. IN BOOL LastCreated
  484. )
  485. {
  486. PGROWBUFFER gb = &RegEnum->RegNodes;
  487. if (gb->End - gb->UserIndex < DWSIZEOF (REGNODEW)) {
  488. return NULL;
  489. }
  490. if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) {
  491. return (PREGNODEW)(gb->Buf + gb->End) - 1;
  492. } else {
  493. return (PREGNODEW)(gb->Buf + gb->UserIndex);
  494. }
  495. }
  496. /*++
  497. Routine Description:
  498. pDeleteRegNode frees the resources associated with the current reg node and destroys it
  499. Arguments:
  500. RegEnum - Specifies the context
  501. LastCreated - Specifies TRUE if the last created node is to be deleted, regardless of
  502. DepthFirst flag
  503. Return Value:
  504. TRUE if there was a node to delete, FALSE if no more nodes
  505. --*/
  506. BOOL
  507. pDeleteRegNodeA (
  508. IN OUT PREGTREE_ENUMA RegEnum,
  509. IN BOOL LastCreated
  510. )
  511. {
  512. PREGNODEA regNode;
  513. PGROWBUFFER gb = &RegEnum->RegNodes;
  514. regNode = pGetCurrentRegNodeA (RegEnum, LastCreated);
  515. if (!regNode) {
  516. return FALSE;
  517. }
  518. if (regNode->KeyHandle) {
  519. CloseRegKey (regNode->KeyHandle);
  520. }
  521. if (regNode->KeyName) {
  522. FreePathStringExA (g_RegEnumPool, regNode->KeyName);
  523. }
  524. if (regNode->SubKeyName) {
  525. pFreeMemory (regNode->SubKeyName);
  526. }
  527. if (regNode->ValueName) {
  528. pFreeMemory (regNode->ValueName);
  529. }
  530. if (regNode->ValueData) {
  531. pFreeMemory (regNode->ValueData);
  532. }
  533. if (RegEnum->LastNode == regNode) {
  534. RegEnum->LastNode = NULL;
  535. }
  536. //
  537. // delete node
  538. //
  539. if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) {
  540. gb->End -= DWSIZEOF (REGNODEA);
  541. } else {
  542. gb->UserIndex += DWSIZEOF (REGNODEA);
  543. //
  544. // reset list
  545. //
  546. if (gb->Size - gb->End < DWSIZEOF (REGNODEA)) {
  547. MoveMemory (gb->Buf, gb->Buf + gb->UserIndex, gb->End - gb->UserIndex);
  548. gb->End -= gb->UserIndex;
  549. gb->UserIndex = 0;
  550. }
  551. }
  552. return TRUE;
  553. }
  554. BOOL
  555. pDeleteRegNodeW (
  556. IN OUT PREGTREE_ENUMW RegEnum,
  557. IN BOOL LastCreated
  558. )
  559. {
  560. PREGNODEW regNode;
  561. PGROWBUFFER gb = &RegEnum->RegNodes;
  562. regNode = pGetCurrentRegNodeW (RegEnum, LastCreated);
  563. if (!regNode) {
  564. return FALSE;
  565. }
  566. if (regNode->KeyHandle) {
  567. CloseRegKey (regNode->KeyHandle);
  568. }
  569. if (regNode->KeyName) {
  570. FreePathStringExW (g_RegEnumPool, regNode->KeyName);
  571. }
  572. if (regNode->SubKeyName) {
  573. pFreeMemory (regNode->SubKeyName);
  574. }
  575. if (regNode->ValueName) {
  576. pFreeMemory (regNode->ValueName);
  577. }
  578. if (regNode->ValueData) {
  579. pFreeMemory (regNode->ValueData);
  580. }
  581. if (RegEnum->LastNode == regNode) {
  582. RegEnum->LastNode = NULL;
  583. }
  584. //
  585. // delete node
  586. //
  587. if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) {
  588. gb->End -= DWSIZEOF (REGNODEW);
  589. } else {
  590. gb->UserIndex += DWSIZEOF (REGNODEW);
  591. //
  592. // reset list
  593. //
  594. if (gb->Size - gb->End < DWSIZEOF (REGNODEW)) {
  595. MoveMemory (gb->Buf, gb->Buf + gb->UserIndex, gb->End - gb->UserIndex);
  596. gb->End -= gb->UserIndex;
  597. gb->UserIndex = 0;
  598. }
  599. }
  600. return TRUE;
  601. }
  602. /*++
  603. Routine Description:
  604. pCreateRegNode creates a new node given a context, a key name or a parent node
  605. Arguments:
  606. RegEnum - Specifies the context
  607. KeyName - Specifies the key name of the new node; may be NULL only if ParentNode is not NULL
  608. ParentNode - Specifies a pointer to the parent node of the new node; a pointer to the node
  609. is required because the parent node location in memory may change as a result
  610. of the growbuffer changing buffer location when it grows;
  611. may be NULL only if KeyName is not;
  612. Ignore - Receives a meaningful value only if NULL is returned (no node created);
  613. if TRUE upon return, the failure of node creation should be ignored
  614. Return Value:
  615. A pointer to the new node or NULL if no node was created
  616. --*/
  617. PREGNODEA
  618. pCreateRegNodeA (
  619. IN OUT PREGTREE_ENUMA RegEnum,
  620. IN PCSTR KeyName, OPTIONAL
  621. IN PREGNODEA* ParentNode, OPTIONAL
  622. IN PBOOL Ignore OPTIONAL
  623. )
  624. {
  625. PREGNODEA newNode;
  626. PSTR newKeyName;
  627. REGSAM prevMode;
  628. PSEGMENTA FirstSegment;
  629. LONG offset = 0;
  630. if (KeyName) {
  631. newKeyName = DuplicateTextExA (g_RegEnumPool, KeyName, 0, NULL);
  632. } else {
  633. MYASSERT (ParentNode);
  634. newKeyName = JoinPathsInPoolExA ((
  635. g_RegEnumPool,
  636. (*ParentNode)->KeyName,
  637. (*ParentNode)->SubKeyName,
  638. NULL
  639. ));
  640. //
  641. // check if this starting path may match the pattern before continuing
  642. //
  643. FirstSegment = RegEnum->RegEnumInfo.RegPattern->NodePattern->Pattern->Segment;
  644. if (FirstSegment->Type == SEGMENTTYPE_EXACTMATCH &&
  645. !StringIMatchByteCountA (
  646. FirstSegment->Exact.LowerCasePhrase,
  647. newKeyName,
  648. FirstSegment->Exact.PhraseBytes
  649. )) {
  650. DEBUGMSGA ((
  651. DBG_REGENUM,
  652. "Skipping tree %s\\* because it cannot match the pattern",
  653. newKeyName
  654. ));
  655. FreeTextExA (g_RegEnumPool, newKeyName);
  656. if (Ignore) {
  657. *Ignore = TRUE;
  658. }
  659. return NULL;
  660. }
  661. }
  662. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  663. //
  664. // look if this key and the whole subtree are excluded; if so, soft block creation of node
  665. //
  666. if (ElIsTreeExcluded2A (ELT_REGISTRY, newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf)) {
  667. DEBUGMSGA ((
  668. DBG_REGENUM,
  669. "Skipping tree %s\\%s because it's excluded",
  670. newKeyName,
  671. RegEnum->RegEnumInfo.RegPattern->Leaf
  672. ));
  673. FreeTextExA (g_RegEnumPool, newKeyName);
  674. if (Ignore) {
  675. *Ignore = TRUE;
  676. }
  677. return NULL;
  678. }
  679. }
  680. if (ParentNode) {
  681. //
  682. // remember current offset
  683. //
  684. offset = (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf);
  685. }
  686. //
  687. // allocate space for the new node in the growbuffer
  688. //
  689. newNode = (PREGNODEA) GbGrow (&RegEnum->RegNodes, DWSIZEOF (REGNODEA));
  690. if (!newNode) {
  691. FreeTextExA (g_RegEnumPool, newKeyName);
  692. goto fail;
  693. }
  694. if (ParentNode) {
  695. //
  696. // check if the buffer moved
  697. //
  698. if (offset != (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf)) {
  699. //
  700. // adjust the parent position
  701. //
  702. *ParentNode = (PREGNODEA)(RegEnum->RegNodes.Buf + offset);
  703. }
  704. }
  705. //
  706. // initialize the newly created node
  707. //
  708. ZeroMemory (newNode, DWSIZEOF (REGNODEA));
  709. newNode->KeyName = newKeyName;
  710. prevMode = SetRegOpenAccessMode (KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
  711. if (ParentNode) {
  712. newNode->KeyHandle = OpenRegKeyA ((*ParentNode)->KeyHandle, (*ParentNode)->SubKeyName);
  713. newNode->Flags |= RNF_RETURN_KEYS;
  714. } else {
  715. newNode->KeyHandle = OpenRegKeyStrA (newNode->KeyName);
  716. if ((RegEnum->RegEnumInfo.RegPattern->Leaf == NULL) &&
  717. (RegEnum->RegEnumInfo.RegPattern->ExactRoot) &&
  718. (!WildCharsPatternA (RegEnum->RegEnumInfo.RegPattern->NodePattern))
  719. ) {
  720. newNode->Flags |= DNF_RETURN_DIRNAME;
  721. }
  722. }
  723. SetRegOpenAccessMode (prevMode);
  724. if (!newNode->KeyHandle) {
  725. DEBUGMSGA ((
  726. DBG_REGENUM,
  727. "pCreateRegNodeA: Cannot open registry key: %s; rc=%lu",
  728. newNode->KeyName,
  729. GetLastError()
  730. ));
  731. goto fail;
  732. }
  733. if (!pGetRegNodeInfoA (newNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  734. DEBUGMSGA ((
  735. DBG_REGENUM,
  736. "pCreateRegNodeA: Cannot get info for key: %s; rc=%lu",
  737. newNode->KeyName,
  738. GetLastError()
  739. ));
  740. goto fail;
  741. }
  742. newNode->EnumState = RNS_ENUM_INIT;
  743. if ((RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTNODE | OBSPF_NODEISROOTPLUSSTAR)) ||
  744. TestParsedPatternA (RegEnum->RegEnumInfo.RegPattern->NodePattern, newKeyName)
  745. ) {
  746. newNode->Flags |= RNF_KEYNAME_MATCHES;
  747. }
  748. if (ParentNode) {
  749. newNode->SubLevel = (*ParentNode)->SubLevel + 1;
  750. } else {
  751. newNode->SubLevel = 0;
  752. }
  753. return newNode;
  754. fail:
  755. if (Ignore) {
  756. if (RegEnum->RegEnumInfo.CallbackOnError) {
  757. *Ignore = (*RegEnum->RegEnumInfo.CallbackOnError)(newNode);
  758. } else {
  759. *Ignore = FALSE;
  760. }
  761. }
  762. if (newNode) {
  763. pDeleteRegNodeA (RegEnum, TRUE);
  764. }
  765. return NULL;
  766. }
  767. PREGNODEW
  768. pCreateRegNodeW (
  769. IN OUT PREGTREE_ENUMW RegEnum,
  770. IN PCWSTR KeyName, OPTIONAL
  771. IN PREGNODEW* ParentNode, OPTIONAL
  772. OUT PBOOL Ignore OPTIONAL
  773. )
  774. {
  775. PREGNODEW newNode;
  776. PWSTR newKeyName;
  777. REGSAM prevMode;
  778. PSEGMENTW FirstSegment;
  779. LONG offset = 0;
  780. if (KeyName) {
  781. newKeyName = DuplicateTextExW (g_RegEnumPool, KeyName, 0, NULL);
  782. } else {
  783. MYASSERT (ParentNode);
  784. newKeyName = JoinPathsInPoolExW ((
  785. g_RegEnumPool,
  786. (*ParentNode)->KeyName,
  787. (*ParentNode)->SubKeyName,
  788. NULL
  789. ));
  790. //
  791. // check if this starting path may match the pattern before continuing
  792. //
  793. FirstSegment = RegEnum->RegEnumInfo.RegPattern->NodePattern->Pattern->Segment;
  794. if (FirstSegment->Type == SEGMENTTYPE_EXACTMATCH &&
  795. !StringIMatchByteCountW (
  796. FirstSegment->Exact.LowerCasePhrase,
  797. newKeyName,
  798. FirstSegment->Exact.PhraseBytes
  799. )) { //lint !e64
  800. DEBUGMSGW ((
  801. DBG_REGENUM,
  802. "Skipping tree %s\\* because it cannot match the pattern",
  803. newKeyName
  804. ));
  805. FreeTextExW (g_RegEnumPool, newKeyName);
  806. if (Ignore) {
  807. *Ignore = TRUE;
  808. }
  809. return NULL;
  810. }
  811. }
  812. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  813. //
  814. // look if this key and the whole subtree are excluded; if so, soft block creation of node
  815. //
  816. if (ElIsTreeExcluded2W (ELT_REGISTRY, newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { //lint !e64
  817. DEBUGMSGW ((
  818. DBG_REGENUM,
  819. "Skipping tree %s\\%s because it's excluded",
  820. newKeyName,
  821. RegEnum->RegEnumInfo.RegPattern->Leaf
  822. ));
  823. FreeTextExW (g_RegEnumPool, newKeyName);
  824. if (Ignore) {
  825. *Ignore = TRUE;
  826. }
  827. return NULL;
  828. }
  829. }
  830. if (ParentNode) {
  831. //
  832. // remember current offset
  833. //
  834. offset = (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf);
  835. }
  836. //
  837. // allocate space for the new node in the growbuffer
  838. //
  839. newNode = (PREGNODEW) GbGrow (&RegEnum->RegNodes, DWSIZEOF (REGNODEW));
  840. if (!newNode) {
  841. FreeTextExW (g_RegEnumPool, newKeyName);
  842. goto fail;
  843. }
  844. if (ParentNode) {
  845. //
  846. // check if the buffer moved
  847. //
  848. if (offset != (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf)) {
  849. //
  850. // adjust the parent position
  851. //
  852. *ParentNode = (PREGNODEW)(RegEnum->RegNodes.Buf + offset);
  853. }
  854. }
  855. //
  856. // initialize the newly created node
  857. //
  858. ZeroMemory (newNode, DWSIZEOF (REGNODEW));
  859. newNode->KeyName = newKeyName;
  860. prevMode = SetRegOpenAccessMode (KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
  861. if (ParentNode) {
  862. newNode->KeyHandle = OpenRegKeyW ((*ParentNode)->KeyHandle, (*ParentNode)->SubKeyName);
  863. newNode->Flags |= RNF_RETURN_KEYS;
  864. } else {
  865. newNode->KeyHandle = OpenRegKeyStrW (newNode->KeyName);
  866. if ((RegEnum->RegEnumInfo.RegPattern->Leaf == NULL) &&
  867. (RegEnum->RegEnumInfo.RegPattern->ExactRoot) &&
  868. (!WildCharsPatternW (RegEnum->RegEnumInfo.RegPattern->NodePattern))
  869. ) {
  870. newNode->Flags |= DNF_RETURN_DIRNAME;
  871. }
  872. }
  873. SetRegOpenAccessMode (prevMode);
  874. if (!newNode->KeyHandle) {
  875. DEBUGMSGW ((
  876. DBG_REGENUM,
  877. "pCreateRegNodeW: Cannot open registry key: %s; rc=%lu",
  878. newNode->KeyName,
  879. GetLastError()
  880. ));
  881. goto fail;
  882. }
  883. if (!pGetRegNodeInfoW (newNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  884. DEBUGMSGW ((
  885. DBG_REGENUM,
  886. "pCreateRegNodeW: Cannot get info for key: %s; rc=%lu",
  887. newNode->KeyName,
  888. GetLastError()
  889. ));
  890. goto fail;
  891. }
  892. newNode->EnumState = RNS_ENUM_INIT;
  893. if ((RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTNODE | OBSPF_NODEISROOTPLUSSTAR)) ||
  894. TestParsedPatternW (RegEnum->RegEnumInfo.RegPattern->NodePattern, newKeyName)
  895. ) {
  896. newNode->Flags |= RNF_KEYNAME_MATCHES;
  897. }
  898. if (ParentNode) {
  899. newNode->SubLevel = (*ParentNode)->SubLevel + 1;
  900. } else {
  901. newNode->SubLevel = 0;
  902. }
  903. return newNode;
  904. fail:
  905. if (Ignore) {
  906. if (RegEnum->RegEnumInfo.CallbackOnError) {
  907. *Ignore = (*RegEnum->RegEnumInfo.CallbackOnError)(newNode);
  908. } else {
  909. *Ignore = FALSE;
  910. }
  911. }
  912. if (newNode) {
  913. pDeleteRegNodeW (RegEnum, TRUE);
  914. }
  915. return NULL;
  916. }
  917. /*++
  918. Routine Description:
  919. pEnumFirstRegRoot enumerates the first root that matches caller's conditions
  920. Arguments:
  921. RegEnum - Specifies the context; receives updated info
  922. Return Value:
  923. TRUE if a root node was created; FALSE if not
  924. --*/
  925. BOOL
  926. pEnumFirstRegRootA (
  927. IN OUT PREGTREE_ENUMA RegEnum
  928. )
  929. {
  930. PCSTR root;
  931. BOOL ignore;
  932. root = RegEnum->RegEnumInfo.RegPattern->ExactRoot;
  933. if (root) {
  934. if (pCreateRegNodeA (RegEnum, root, NULL, NULL)) {
  935. RegEnum->RootState = RES_ROOT_DONE;
  936. return TRUE;
  937. }
  938. } else {
  939. RegEnum->RootEnum = pAllocateMemory (DWSIZEOF (REGROOT_ENUMA));
  940. if (!EnumFirstRegRootA (RegEnum->RootEnum)) {
  941. return FALSE;
  942. }
  943. do {
  944. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  945. if (ElIsTreeExcluded2A (ELT_REGISTRY, RegEnum->RootEnum->RegRootName, RegEnum->RegEnumInfo.RegPattern->Leaf)) {
  946. DEBUGMSGA ((DBG_REGENUM, "pEnumFirstRegRootA: Root is excluded: %s", RegEnum->RootEnum->RegRootName));
  947. continue;
  948. }
  949. }
  950. if (!pCreateRegNodeA (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) {
  951. if (ignore) {
  952. continue;
  953. }
  954. break;
  955. }
  956. RegEnum->RootState = RES_ROOT_NEXT;
  957. return TRUE;
  958. } while (EnumNextRegRootA (RegEnum->RootEnum));
  959. pFreeMemory (RegEnum->RootEnum);
  960. RegEnum->RootEnum = NULL;
  961. }
  962. return FALSE;
  963. }
  964. BOOL
  965. pEnumFirstRegRootW (
  966. IN OUT PREGTREE_ENUMW RegEnum
  967. )
  968. {
  969. PCWSTR root;
  970. BOOL ignore;
  971. root = RegEnum->RegEnumInfo.RegPattern->ExactRoot; //lint !e64
  972. if (root) {
  973. if (pCreateRegNodeW (RegEnum, root, NULL, NULL)) {
  974. RegEnum->RootState = RES_ROOT_DONE;
  975. return TRUE;
  976. }
  977. } else {
  978. RegEnum->RootEnum = pAllocateMemory (DWSIZEOF (REGROOT_ENUMW));
  979. if (!EnumFirstRegRootW (RegEnum->RootEnum)) {
  980. return FALSE;
  981. }
  982. do {
  983. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  984. if (ElIsTreeExcluded2W (ELT_REGISTRY, RegEnum->RootEnum->RegRootName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { //lint !e64
  985. DEBUGMSGW ((DBG_REGENUM, "pEnumFirstRegRootW: Root is excluded: %s", RegEnum->RootEnum->RegRootName));
  986. continue;
  987. }
  988. }
  989. if (!pCreateRegNodeW (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) {
  990. if (ignore) {
  991. continue;
  992. }
  993. break;
  994. }
  995. RegEnum->RootState = RES_ROOT_NEXT;
  996. return TRUE;
  997. } while (EnumNextRegRootW (RegEnum->RootEnum));
  998. pFreeMemory (RegEnum->RootEnum);
  999. RegEnum->RootEnum = NULL;
  1000. }
  1001. return FALSE;
  1002. }
  1003. /*++
  1004. Routine Description:
  1005. pEnumNextRegRoot enumerates the next root that matches caller's conditions
  1006. Arguments:
  1007. RegEnum - Specifies the context; receives updated info
  1008. Return Value:
  1009. TRUE if a root node was created; FALSE if not
  1010. --*/
  1011. BOOL
  1012. pEnumNextRegRootA (
  1013. IN OUT PREGTREE_ENUMA RegEnum
  1014. )
  1015. {
  1016. BOOL ignore;
  1017. while (EnumNextRegRootA (RegEnum->RootEnum)) {
  1018. if (pCreateRegNodeA (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) {
  1019. return TRUE;
  1020. }
  1021. if (!ignore) {
  1022. break;
  1023. }
  1024. }
  1025. RegEnum->RootState = RES_ROOT_DONE;
  1026. return FALSE;
  1027. }
  1028. BOOL
  1029. pEnumNextRegRootW (
  1030. IN OUT PREGTREE_ENUMW RegEnum
  1031. )
  1032. {
  1033. BOOL ignore;
  1034. while (EnumNextRegRootW (RegEnum->RootEnum)) {
  1035. if (pCreateRegNodeW (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) {
  1036. return TRUE;
  1037. }
  1038. if (!ignore) {
  1039. break;
  1040. }
  1041. }
  1042. RegEnum->RootState = RES_ROOT_DONE;
  1043. return FALSE;
  1044. }
  1045. /*++
  1046. Routine Description:
  1047. pEnumNextValue enumerates the next value that matches caller's conditions
  1048. Arguments:
  1049. RegNode - Specifies the node and the current context; receives updated info
  1050. ReadData - Specifies if the data associated with this value should be read
  1051. Return Value:
  1052. TRUE if a new value was found; FALSE if not
  1053. --*/
  1054. BOOL
  1055. pEnumNextValueA (
  1056. IN OUT PREGNODEA RegNode,
  1057. IN BOOL ReadData
  1058. )
  1059. {
  1060. LONG rc;
  1061. DWORD valueNameLength;
  1062. if (RegNode->ValueIndex == 0) {
  1063. SetLastError (ERROR_SUCCESS);
  1064. return FALSE;
  1065. }
  1066. RegNode->ValueIndex--;
  1067. valueNameLength = RegNode->ValueLengthMax;
  1068. if (ReadData) {
  1069. RegNode->ValueDataSize = RegNode->ValueDataSizeMax;
  1070. }
  1071. rc = RegEnumValueA (
  1072. RegNode->KeyHandle,
  1073. RegNode->ValueIndex,
  1074. RegNode->ValueName,
  1075. &valueNameLength,
  1076. NULL,
  1077. &RegNode->ValueType,
  1078. ReadData ? RegNode->ValueData : NULL,
  1079. ReadData ? &RegNode->ValueDataSize : NULL
  1080. );
  1081. if (rc != ERROR_SUCCESS) {
  1082. SetLastError (rc == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : (DWORD)rc);
  1083. return FALSE;
  1084. }
  1085. RegNode->Flags &= ~RNF_VALUENAME_INVALID;
  1086. if (ReadData) {
  1087. RegNode->Flags &= ~RNF_VALUEDATA_INVALID;
  1088. }
  1089. return TRUE;
  1090. }
  1091. BOOL
  1092. pEnumNextValueW (
  1093. IN OUT PREGNODEW RegNode,
  1094. IN BOOL ReadData
  1095. )
  1096. {
  1097. LONG rc;
  1098. DWORD valueNameLength;
  1099. if (RegNode->ValueIndex == 0) {
  1100. SetLastError (ERROR_SUCCESS);
  1101. return FALSE;
  1102. }
  1103. RegNode->ValueIndex--;
  1104. valueNameLength = RegNode->ValueLengthMax;
  1105. if (ReadData) {
  1106. RegNode->ValueDataSize = RegNode->ValueDataSizeMax;
  1107. }
  1108. rc = RegEnumValueW (
  1109. RegNode->KeyHandle,
  1110. RegNode->ValueIndex,
  1111. RegNode->ValueName,
  1112. &valueNameLength,
  1113. NULL,
  1114. &RegNode->ValueType,
  1115. ReadData ? RegNode->ValueData : NULL,
  1116. ReadData ? &RegNode->ValueDataSize : NULL
  1117. );
  1118. if (rc != ERROR_SUCCESS) {
  1119. SetLastError (rc == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : (DWORD)rc);
  1120. return FALSE;
  1121. }
  1122. RegNode->Flags &= ~RNF_VALUENAME_INVALID;
  1123. if (ReadData) {
  1124. RegNode->Flags &= ~RNF_VALUEDATA_INVALID;
  1125. }
  1126. return TRUE;
  1127. }
  1128. /*++
  1129. Routine Description:
  1130. pEnumFirstValue enumerates the first value that matches caller's conditions
  1131. Arguments:
  1132. RegNode - Specifies the node and the current context; receives updated info
  1133. ReadData - Specifies if the data associated with this value should be read
  1134. Return Value:
  1135. TRUE if a first value was found; FALSE if not
  1136. --*/
  1137. BOOL
  1138. pEnumFirstValueA (
  1139. IN OUT PREGNODEA RegNode,
  1140. IN BOOL ReadData
  1141. )
  1142. {
  1143. RegNode->ValueIndex = RegNode->ValueCount;
  1144. return pEnumNextValueA (RegNode, ReadData);
  1145. }
  1146. BOOL
  1147. pEnumFirstValueW (
  1148. OUT PREGNODEW RegNode,
  1149. IN BOOL ReadData
  1150. )
  1151. {
  1152. RegNode->ValueIndex = RegNode->ValueCount;
  1153. return pEnumNextValueW (RegNode, ReadData);
  1154. }
  1155. /*++
  1156. Routine Description:
  1157. pEnumNextSubKey enumerates the next subkey that matches caller's conditions
  1158. Arguments:
  1159. RegNode - Specifies the node and the current context; receives updated info
  1160. Return Value:
  1161. TRUE if a new subkey was found; FALSE if not
  1162. --*/
  1163. BOOL
  1164. pEnumNextSubKeyA (
  1165. IN OUT PREGNODEA RegNode
  1166. )
  1167. {
  1168. LONG rc;
  1169. RegNode->SubKeyIndex++;
  1170. do {
  1171. rc = RegEnumKeyA (
  1172. RegNode->KeyHandle,
  1173. RegNode->SubKeyIndex - 1,
  1174. RegNode->SubKeyName,
  1175. RegNode->SubKeyLengthMax
  1176. );
  1177. if (rc == ERROR_NO_MORE_ITEMS) {
  1178. SetLastError (ERROR_SUCCESS);
  1179. return FALSE;
  1180. }
  1181. if (rc == ERROR_MORE_DATA) {
  1182. //
  1183. // double the current buffer size
  1184. //
  1185. MYASSERT (RegNode->SubKeyName);
  1186. pFreeMemory (RegNode->SubKeyName);
  1187. RegNode->SubKeyLengthMax *= 2;
  1188. RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (MBCHAR));
  1189. }
  1190. } while (rc == ERROR_MORE_DATA);
  1191. return rc == ERROR_SUCCESS;
  1192. }
  1193. BOOL
  1194. pEnumNextSubKeyW (
  1195. IN OUT PREGNODEW RegNode
  1196. )
  1197. {
  1198. LONG rc;
  1199. RegNode->SubKeyIndex++;
  1200. do {
  1201. rc = RegEnumKeyW (
  1202. RegNode->KeyHandle,
  1203. RegNode->SubKeyIndex - 1,
  1204. RegNode->SubKeyName,
  1205. RegNode->SubKeyLengthMax
  1206. );
  1207. if (rc == ERROR_NO_MORE_ITEMS) {
  1208. SetLastError (ERROR_SUCCESS);
  1209. return FALSE;
  1210. }
  1211. if (rc == ERROR_MORE_DATA) {
  1212. //
  1213. // double the current buffer size
  1214. //
  1215. MYASSERT (RegNode->SubKeyName);
  1216. pFreeMemory (RegNode->SubKeyName);
  1217. RegNode->SubKeyLengthMax *= 2;
  1218. RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (WCHAR));
  1219. }
  1220. } while (rc == ERROR_MORE_DATA);
  1221. return rc == ERROR_SUCCESS;
  1222. }
  1223. /*++
  1224. Routine Description:
  1225. pEnumFirstSubKey enumerates the first subkey that matches caller's conditions
  1226. Arguments:
  1227. RegNode - Specifies the node and the current context; receives updated info
  1228. Return Value:
  1229. TRUE if a first subkey was found; FALSE if not
  1230. --*/
  1231. BOOL
  1232. pEnumFirstSubKeyA (
  1233. IN OUT PREGNODEA RegNode
  1234. )
  1235. {
  1236. RegNode->SubKeyIndex = 0;
  1237. return pEnumNextSubKeyA (RegNode);
  1238. }
  1239. BOOL
  1240. pEnumFirstSubKeyW (
  1241. OUT PREGNODEW RegNode
  1242. )
  1243. {
  1244. RegNode->SubKeyIndex = 0;
  1245. return pEnumNextSubKeyW (RegNode);
  1246. }
  1247. /*++
  1248. Routine Description:
  1249. pEnumNextRegObjectInTree is a private function that enumerates the next node matching
  1250. the specified criteria; it's implemented as a state machine that travels the keys/values
  1251. as specified the the caller; it doesn't check if they actually match the patterns
  1252. Arguments:
  1253. RegEnum - Specifies the current enum context; receives updated info
  1254. CurrentKeyNode - Receives the key node that is currently processed, if success is returned
  1255. Return Value:
  1256. TRUE if a next match was found; FALSE if no more keys/values match
  1257. --*/
  1258. BOOL
  1259. pEnumNextRegObjectInTreeA (
  1260. IN OUT PREGTREE_ENUMA RegEnum,
  1261. OUT PREGNODEA* CurrentKeyNode
  1262. )
  1263. {
  1264. PREGNODEA currentNode;
  1265. PREGNODEA newNode;
  1266. PCSTR valueName;
  1267. BOOL ignore;
  1268. LONG rc;
  1269. while ((currentNode = pGetCurrentRegNodeA (RegEnum, FALSE)) != NULL) {
  1270. *CurrentKeyNode = currentNode;
  1271. switch (currentNode->EnumState) {
  1272. case RNS_VALUE_FIRST:
  1273. if (RegEnum->ControlFlags & RECF_SKIPVALUES) {
  1274. RegEnum->ControlFlags &= ~RECF_SKIPVALUES;
  1275. currentNode->EnumState = RNS_VALUE_DONE;
  1276. break;
  1277. }
  1278. if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTLEAF) {
  1279. BOOL readData = RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA;
  1280. valueName = RegEnum->RegEnumInfo.RegPattern->Leaf;
  1281. MYASSERT (valueName);
  1282. currentNode->EnumState = RNS_VALUE_DONE;
  1283. currentNode->ValueDataSize = currentNode->ValueDataSizeMax;
  1284. rc = RegQueryValueExA (
  1285. currentNode->KeyHandle,
  1286. valueName,
  1287. NULL,
  1288. &currentNode->ValueType,
  1289. readData ? currentNode->ValueData : NULL,
  1290. readData ? &currentNode->ValueDataSize : NULL
  1291. );
  1292. if (rc == ERROR_SUCCESS) {
  1293. if (SizeOfStringA (valueName) <=
  1294. currentNode->ValueLengthMax * DWSIZEOF (MBCHAR)
  1295. ) {
  1296. StringCopyA (currentNode->ValueName, valueName);
  1297. currentNode->Flags &= ~RNF_VALUENAME_INVALID;
  1298. if (readData) {
  1299. currentNode->Flags &= ~RNF_VALUEDATA_INVALID;
  1300. }
  1301. return TRUE;
  1302. }
  1303. }
  1304. } else {
  1305. if (pEnumFirstValueA (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  1306. currentNode->EnumState = RNS_VALUE_NEXT;
  1307. return TRUE;
  1308. }
  1309. currentNode->EnumState = RNS_VALUE_DONE;
  1310. }
  1311. break;
  1312. case RNS_VALUE_NEXT:
  1313. if (RegEnum->ControlFlags & RECF_SKIPVALUES) {
  1314. RegEnum->ControlFlags &= ~RECF_SKIPVALUES;
  1315. currentNode->EnumState = RNS_VALUE_DONE;
  1316. break;
  1317. }
  1318. if (pEnumNextValueA (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  1319. return TRUE;
  1320. }
  1321. //
  1322. // no more values for this one, go to the next
  1323. //
  1324. currentNode->EnumState = RNS_VALUE_DONE;
  1325. //
  1326. // fall through
  1327. //
  1328. case RNS_VALUE_DONE:
  1329. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) || !currentNode->SubKeyCount) {
  1330. //
  1331. // done with this node
  1332. //
  1333. currentNode->EnumState = RNS_ENUM_DONE;
  1334. break;
  1335. }
  1336. //
  1337. // now enum subkeys
  1338. //
  1339. currentNode->EnumState = RNS_SUBKEY_FIRST;
  1340. //
  1341. // fall through
  1342. //
  1343. case RNS_SUBKEY_FIRST:
  1344. if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) {
  1345. RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS;
  1346. currentNode->EnumState = RNS_SUBKEY_DONE;
  1347. break;
  1348. }
  1349. //
  1350. // check new node's level; if too large, quit
  1351. //
  1352. if (currentNode->SubLevel >= RegEnum->RegEnumInfo.MaxSubLevel) {
  1353. currentNode->EnumState = RNS_SUBKEY_DONE;
  1354. break;
  1355. }
  1356. if (!pEnumFirstSubKeyA (currentNode)) {
  1357. currentNode->EnumState = RNS_SUBKEY_DONE;
  1358. break;
  1359. }
  1360. currentNode->EnumState = RNS_SUBKEY_NEXT;
  1361. newNode = pCreateRegNodeA (RegEnum, NULL, &currentNode, &ignore);
  1362. if (newNode) {
  1363. //
  1364. // now look at the new node
  1365. //
  1366. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1367. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1368. newNode->Flags &= ~RNF_RETURN_KEYS;
  1369. *CurrentKeyNode = newNode;
  1370. return TRUE;
  1371. }
  1372. }
  1373. break;
  1374. }
  1375. if (!ignore) {
  1376. //
  1377. // abort enum
  1378. //
  1379. DEBUGMSGA ((
  1380. DBG_ERROR,
  1381. "Error encountered enumerating registry; aborting enumeration"
  1382. ));
  1383. RegEnum->RootState = RES_ROOT_DONE;
  1384. return FALSE;
  1385. }
  1386. //
  1387. // fall through
  1388. //
  1389. case RNS_SUBKEY_NEXT:
  1390. if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) {
  1391. RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS;
  1392. currentNode->EnumState = RNS_SUBKEY_DONE;
  1393. break;
  1394. }
  1395. if (pEnumNextSubKeyA (currentNode)) {
  1396. newNode = pCreateRegNodeA (RegEnum, NULL, &currentNode, &ignore);
  1397. if (newNode) {
  1398. //
  1399. // look at the new node first
  1400. //
  1401. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1402. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1403. newNode->Flags &= ~RNF_RETURN_KEYS;
  1404. *CurrentKeyNode = newNode;
  1405. return TRUE;
  1406. }
  1407. }
  1408. break;
  1409. }
  1410. if (!ignore) {
  1411. //
  1412. // abort enum
  1413. //
  1414. DEBUGMSGA ((
  1415. DBG_ERROR,
  1416. "Error encountered enumerating registry; aborting enumeration"
  1417. ));
  1418. RegEnum->RootState = RES_ROOT_DONE;
  1419. return FALSE;
  1420. }
  1421. //
  1422. // continue with next subkey
  1423. //
  1424. break;
  1425. }
  1426. //
  1427. // this node is done
  1428. //
  1429. currentNode->EnumState = RNS_SUBKEY_DONE;
  1430. //
  1431. // fall through
  1432. //
  1433. case RNS_SUBKEY_DONE:
  1434. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1435. //
  1436. // now enum values
  1437. //
  1438. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1439. currentNode->EnumState = RNS_VALUE_FIRST;
  1440. break;
  1441. }
  1442. }
  1443. //
  1444. // done with this node
  1445. //
  1446. currentNode->EnumState = RNS_ENUM_DONE;
  1447. //
  1448. // fall through
  1449. //
  1450. case RNS_ENUM_DONE:
  1451. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1452. if (!(RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST)) {
  1453. if (currentNode->Flags & RNF_RETURN_KEYS) {
  1454. currentNode->Flags &= ~RNF_RETURN_KEYS;
  1455. //
  1456. // set additional data before returning
  1457. //
  1458. if (currentNode->ValueName) {
  1459. pFreeMemory (currentNode->ValueName);
  1460. currentNode->ValueName = NULL;
  1461. currentNode->Flags |= RNF_VALUENAME_INVALID;
  1462. }
  1463. return TRUE;
  1464. }
  1465. }
  1466. }
  1467. pDeleteRegNodeA (RegEnum, FALSE);
  1468. break;
  1469. case RNS_ENUM_INIT:
  1470. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1471. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1472. if (currentNode->Flags & RNF_RETURN_KEYS) {
  1473. currentNode->Flags &= ~RNF_RETURN_KEYS;
  1474. return TRUE;
  1475. }
  1476. }
  1477. }
  1478. if (RegEnum->ControlFlags & RECF_SKIPKEY) {
  1479. RegEnum->ControlFlags &= ~RECF_SKIPKEY;
  1480. currentNode->EnumState = RNS_ENUM_DONE;
  1481. break;
  1482. }
  1483. if ((RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1484. //
  1485. // enum values
  1486. //
  1487. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1488. currentNode->EnumState = RNS_VALUE_FIRST;
  1489. break;
  1490. }
  1491. }
  1492. if (currentNode->SubKeyCount) {
  1493. //
  1494. // enum keys
  1495. //
  1496. if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTNODE) {
  1497. currentNode->EnumState = RNS_SUBKEY_DONE;
  1498. } else {
  1499. currentNode->EnumState = RNS_SUBKEY_FIRST;
  1500. }
  1501. break;
  1502. }
  1503. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1504. //
  1505. // enum values
  1506. //
  1507. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1508. currentNode->EnumState = RNS_VALUE_FIRST;
  1509. break;
  1510. }
  1511. }
  1512. currentNode->EnumState = RNS_ENUM_DONE;
  1513. break;
  1514. default:
  1515. MYASSERT (FALSE); //lint !e506
  1516. }
  1517. }
  1518. return FALSE;
  1519. }
  1520. BOOL
  1521. pEnumNextRegObjectInTreeW (
  1522. IN OUT PREGTREE_ENUMW RegEnum,
  1523. OUT PREGNODEW* CurrentKeyNode
  1524. )
  1525. {
  1526. PREGNODEW currentNode;
  1527. PREGNODEW newNode;
  1528. PCWSTR valueName;
  1529. BOOL ignore;
  1530. LONG rc;
  1531. while ((currentNode = pGetCurrentRegNodeW (RegEnum, FALSE)) != NULL) {
  1532. *CurrentKeyNode = currentNode;
  1533. switch (currentNode->EnumState) {
  1534. case RNS_VALUE_FIRST:
  1535. if (RegEnum->ControlFlags & RECF_SKIPVALUES) {
  1536. RegEnum->ControlFlags &= ~RECF_SKIPVALUES;
  1537. currentNode->EnumState = RNS_VALUE_DONE;
  1538. break;
  1539. }
  1540. if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTLEAF) {
  1541. BOOL readData = RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA;
  1542. valueName = RegEnum->RegEnumInfo.RegPattern->Leaf;
  1543. MYASSERT (valueName);
  1544. currentNode->EnumState = RNS_VALUE_DONE;
  1545. currentNode->ValueDataSize = currentNode->ValueDataSizeMax;
  1546. rc = RegQueryValueExW (
  1547. currentNode->KeyHandle,
  1548. valueName,
  1549. NULL,
  1550. &currentNode->ValueType,
  1551. readData ? currentNode->ValueData : NULL,
  1552. readData ? &currentNode->ValueDataSize : NULL
  1553. );
  1554. if (rc == ERROR_SUCCESS) {
  1555. if (SizeOfStringW (valueName) <=
  1556. currentNode->ValueLengthMax * DWSIZEOF (WCHAR)
  1557. ) {
  1558. StringCopyW (currentNode->ValueName, valueName);
  1559. currentNode->Flags &= ~RNF_VALUENAME_INVALID;
  1560. if (readData) {
  1561. currentNode->Flags &= ~RNF_VALUEDATA_INVALID;
  1562. }
  1563. return TRUE;
  1564. }
  1565. }
  1566. } else {
  1567. if (pEnumFirstValueW (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  1568. currentNode->EnumState = RNS_VALUE_NEXT;
  1569. return TRUE;
  1570. }
  1571. currentNode->EnumState = RNS_VALUE_DONE;
  1572. }
  1573. break;
  1574. case RNS_VALUE_NEXT:
  1575. if (RegEnum->ControlFlags & RECF_SKIPVALUES) {
  1576. RegEnum->ControlFlags &= ~RECF_SKIPVALUES;
  1577. currentNode->EnumState = RNS_VALUE_DONE;
  1578. break;
  1579. }
  1580. if (pEnumNextValueW (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) {
  1581. return TRUE;
  1582. }
  1583. //
  1584. // no more values for this one, go to the next
  1585. //
  1586. currentNode->EnumState = RNS_VALUE_DONE;
  1587. //
  1588. // fall through
  1589. //
  1590. case RNS_VALUE_DONE:
  1591. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) || !currentNode->SubKeyCount) {
  1592. //
  1593. // done with this node
  1594. //
  1595. currentNode->EnumState = RNS_ENUM_DONE;
  1596. break;
  1597. }
  1598. //
  1599. // now enum subkeys
  1600. //
  1601. currentNode->EnumState = RNS_SUBKEY_FIRST;
  1602. //
  1603. // fall through
  1604. //
  1605. case RNS_SUBKEY_FIRST:
  1606. if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) {
  1607. RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS;
  1608. currentNode->EnumState = RNS_SUBKEY_DONE;
  1609. break;
  1610. }
  1611. //
  1612. // check new node's level; if too large, quit
  1613. //
  1614. if (currentNode->SubLevel >= RegEnum->RegEnumInfo.MaxSubLevel) {
  1615. currentNode->EnumState = RNS_SUBKEY_DONE;
  1616. break;
  1617. }
  1618. if (!pEnumFirstSubKeyW (currentNode)) {
  1619. currentNode->EnumState = RNS_SUBKEY_DONE;
  1620. break;
  1621. }
  1622. currentNode->EnumState = RNS_SUBKEY_NEXT;
  1623. newNode = pCreateRegNodeW (RegEnum, NULL, &currentNode, &ignore);
  1624. if (newNode) {
  1625. //
  1626. // now look at the new node
  1627. //
  1628. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1629. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1630. newNode->Flags &= ~RNF_RETURN_KEYS;
  1631. *CurrentKeyNode = newNode;
  1632. return TRUE;
  1633. }
  1634. }
  1635. break;
  1636. }
  1637. if (!ignore) {
  1638. //
  1639. // abort enum
  1640. //
  1641. DEBUGMSGW ((
  1642. DBG_ERROR,
  1643. "Error encountered enumerating registry; aborting enumeration"
  1644. ));
  1645. RegEnum->RootState = RES_ROOT_DONE;
  1646. return FALSE;
  1647. }
  1648. //
  1649. // fall through
  1650. //
  1651. case RNS_SUBKEY_NEXT:
  1652. if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) {
  1653. RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS;
  1654. currentNode->EnumState = RNS_SUBKEY_DONE;
  1655. break;
  1656. }
  1657. if (pEnumNextSubKeyW (currentNode)) {
  1658. newNode = pCreateRegNodeW (RegEnum, NULL, &currentNode, &ignore);
  1659. if (newNode) {
  1660. //
  1661. // look at the new node first
  1662. //
  1663. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1664. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1665. newNode->Flags &= ~RNF_RETURN_KEYS;
  1666. *CurrentKeyNode = newNode;
  1667. return TRUE;
  1668. }
  1669. }
  1670. break;
  1671. }
  1672. if (!ignore) {
  1673. //
  1674. // abort enum
  1675. //
  1676. DEBUGMSGW ((
  1677. DBG_ERROR,
  1678. "Error encountered enumerating registry; aborting enumeration"
  1679. ));
  1680. RegEnum->RootState = RES_ROOT_DONE;
  1681. return FALSE;
  1682. }
  1683. //
  1684. // continue with next subkey
  1685. //
  1686. break;
  1687. }
  1688. //
  1689. // this node is done
  1690. //
  1691. currentNode->EnumState = RNS_SUBKEY_DONE;
  1692. //
  1693. // fall through
  1694. //
  1695. case RNS_SUBKEY_DONE:
  1696. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1697. //
  1698. // now enum values
  1699. //
  1700. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1701. currentNode->EnumState = RNS_VALUE_FIRST;
  1702. break;
  1703. }
  1704. }
  1705. //
  1706. // done with this node
  1707. //
  1708. currentNode->EnumState = RNS_ENUM_DONE;
  1709. //
  1710. // fall through
  1711. //
  1712. case RNS_ENUM_DONE:
  1713. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1714. if (!(RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST)) {
  1715. if (currentNode->Flags & RNF_RETURN_KEYS) {
  1716. currentNode->Flags &= ~RNF_RETURN_KEYS;
  1717. //
  1718. // set additional data before returning
  1719. //
  1720. if (currentNode->ValueName) {
  1721. pFreeMemory (currentNode->ValueName);
  1722. currentNode->ValueName = NULL;
  1723. currentNode->Flags |= RNF_VALUENAME_INVALID;
  1724. }
  1725. return TRUE;
  1726. }
  1727. }
  1728. }
  1729. pDeleteRegNodeW (RegEnum, FALSE);
  1730. break;
  1731. case RNS_ENUM_INIT:
  1732. if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) {
  1733. if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) {
  1734. if (currentNode->Flags & RNF_RETURN_KEYS) {
  1735. currentNode->Flags &= ~RNF_RETURN_KEYS;
  1736. return TRUE;
  1737. }
  1738. }
  1739. }
  1740. if (RegEnum->ControlFlags & RECF_SKIPKEY) {
  1741. RegEnum->ControlFlags &= ~RECF_SKIPKEY;
  1742. currentNode->EnumState = RNS_ENUM_DONE;
  1743. break;
  1744. }
  1745. if ((RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1746. //
  1747. // enum values
  1748. //
  1749. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1750. currentNode->EnumState = RNS_VALUE_FIRST;
  1751. break;
  1752. }
  1753. }
  1754. if (currentNode->SubKeyCount) {
  1755. //
  1756. // enum keys
  1757. //
  1758. if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTNODE) {
  1759. currentNode->EnumState = RNS_SUBKEY_DONE;
  1760. } else {
  1761. currentNode->EnumState = RNS_SUBKEY_FIRST;
  1762. }
  1763. break;
  1764. }
  1765. if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) {
  1766. //
  1767. // enum values
  1768. //
  1769. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) {
  1770. currentNode->EnumState = RNS_VALUE_FIRST;
  1771. break;
  1772. }
  1773. }
  1774. currentNode->EnumState = RNS_ENUM_DONE;
  1775. break;
  1776. default:
  1777. MYASSERT (FALSE); //lint !e506
  1778. }
  1779. }
  1780. return FALSE;
  1781. }
  1782. /*++
  1783. Routine Description:
  1784. EnumFirstRegObjectInTreeEx enumerates registry keys, and optionally values, that match the
  1785. specified criteria
  1786. Arguments:
  1787. RegEnum - Receives the enum context info; this will be used in subsequent calls to
  1788. EnumNextRegObjectInTree
  1789. EncodedRegPattern - Specifies the encoded key pattern (encoded as defined by the
  1790. ParsedPattern functions)
  1791. EncodedValuePattern - Specifies the encoded value pattern (encoded as defined by the
  1792. ParsedPattern functions); optional; NULL means no values
  1793. should be returned (only look for keys)
  1794. EnumKeyNames - Specifies TRUE if key names should be returned during the enumeration
  1795. (if they match the pattern); a key name is returned before any of its
  1796. subkeys or values
  1797. ContainersFirst - Specifies TRUE if keys should be returned before any of its
  1798. values or subkeys; used only if EnumKeyNames is TRUE
  1799. ValuesFirst - Specifies TRUE if a key's values should be returned before key's subkeys;
  1800. this parameter decides the enum order between values and subkeys
  1801. for each key
  1802. DepthFirst - Specifies TRUE if the current subkey of any key should be fully enumerated
  1803. before going to the next subkey; this parameter decides if the tree
  1804. traversal is depth-first (TRUE) or width-first (FALSE)
  1805. MaxSubLevel - Specifies the maximum sub-level of a key that is to be enumerated,
  1806. relative to the root; if 0, only the root is enumerated;
  1807. if -1, all sub-levels are enumerated
  1808. UseExclusions - Specifies TRUE if exclusion APIs should be used to determine if certain
  1809. keys/values are excluded from enumeration; this slows down the speed
  1810. ReadValueData - Specifies TRUE if data associated with values should also be returned
  1811. CallbackOnError - Specifies a pointer to a callback function that will be called during
  1812. enumeration if an error occurs; if the callback is defined and it
  1813. returns FALSE, the enumeration is aborted, otherwise it will continue
  1814. ignoring the error
  1815. Return Value:
  1816. TRUE if a first match is found.
  1817. FALSE otherwise.
  1818. --*/
  1819. BOOL
  1820. EnumFirstRegObjectInTreeExA (
  1821. OUT PREGTREE_ENUMA RegEnum,
  1822. IN PCSTR EncodedRegPattern,
  1823. IN BOOL EnumKeyNames,
  1824. IN BOOL ContainersFirst,
  1825. IN BOOL ValuesFirst,
  1826. IN BOOL DepthFirst,
  1827. IN DWORD MaxSubLevel,
  1828. IN BOOL UseExclusions,
  1829. IN BOOL ReadValueData,
  1830. IN RPE_ERROR_CALLBACKA CallbackOnError OPTIONAL
  1831. )
  1832. {
  1833. MYASSERT (RegEnum && EncodedRegPattern && *EncodedRegPattern);
  1834. ZeroMemory (RegEnum, DWSIZEOF (REGTREE_ENUMA)); //lint !e613 !e668
  1835. //
  1836. // first try to get reg enum info in internal format
  1837. //
  1838. if (!pGetRegEnumInfoA (
  1839. &RegEnum->RegEnumInfo,
  1840. EncodedRegPattern,
  1841. EnumKeyNames,
  1842. ContainersFirst,
  1843. ValuesFirst,
  1844. DepthFirst,
  1845. MaxSubLevel,
  1846. UseExclusions,
  1847. ReadValueData
  1848. )) { //lint !e613
  1849. AbortRegObjectInTreeEnumA (RegEnum);
  1850. return FALSE;
  1851. }
  1852. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { //lint !e613
  1853. //
  1854. // next check if the starting key is in an excluded tree
  1855. //
  1856. if (ElIsObsPatternExcludedA (ELT_REGISTRY, RegEnum->RegEnumInfo.RegPattern)) { //lint !e613
  1857. DEBUGMSGA ((
  1858. DBG_REGENUM,
  1859. "EnumFirstRegObjectInTreeExA: Root is excluded: %s",
  1860. EncodedRegPattern
  1861. ));
  1862. AbortRegObjectInTreeEnumA (RegEnum);
  1863. return FALSE;
  1864. }
  1865. }
  1866. if (!pEnumFirstRegRootA (RegEnum)) {
  1867. AbortRegObjectInTreeEnumA (RegEnum);
  1868. return FALSE;
  1869. }
  1870. /*lint -e(613)*/RegEnum->RegEnumInfo.CallbackOnError = CallbackOnError;
  1871. return EnumNextRegObjectInTreeA (RegEnum);
  1872. }
  1873. BOOL
  1874. EnumFirstRegObjectInTreeExW (
  1875. OUT PREGTREE_ENUMW RegEnum,
  1876. IN PCWSTR EncodedRegPattern,
  1877. IN BOOL EnumKeyNames,
  1878. IN BOOL ContainersFirst,
  1879. IN BOOL ValuesFirst,
  1880. IN BOOL DepthFirst,
  1881. IN DWORD MaxSubLevel,
  1882. IN BOOL UseExclusions,
  1883. IN BOOL ReadValueData,
  1884. IN RPE_ERROR_CALLBACKW CallbackOnError OPTIONAL
  1885. )
  1886. {
  1887. MYASSERT (RegEnum && EncodedRegPattern && *EncodedRegPattern);
  1888. ZeroMemory (RegEnum, DWSIZEOF (REGTREE_ENUMW)); //lint !e613 !e668
  1889. //
  1890. // first try to get reg enum info in internal format
  1891. //
  1892. if (!pGetRegEnumInfoW (
  1893. &RegEnum->RegEnumInfo,
  1894. EncodedRegPattern,
  1895. EnumKeyNames,
  1896. ContainersFirst,
  1897. ValuesFirst,
  1898. DepthFirst,
  1899. MaxSubLevel,
  1900. UseExclusions,
  1901. ReadValueData
  1902. )) { //lint !e613
  1903. AbortRegObjectInTreeEnumW (RegEnum);
  1904. return FALSE;
  1905. }
  1906. if (/*lint -e(613)*/RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  1907. //
  1908. // next check if the starting key is in an excluded tree
  1909. //
  1910. if (ElIsObsPatternExcludedW (ELT_REGISTRY, /*lint -e(613)*/RegEnum->RegEnumInfo.RegPattern)) {
  1911. DEBUGMSGW ((
  1912. DBG_REGENUM,
  1913. "EnumFirstRegObjectInTreeExW: Root is excluded: %s",
  1914. EncodedRegPattern
  1915. ));
  1916. AbortRegObjectInTreeEnumW (RegEnum);
  1917. return FALSE;
  1918. }
  1919. }
  1920. if (!pEnumFirstRegRootW (RegEnum)) {
  1921. AbortRegObjectInTreeEnumW (RegEnum);
  1922. return FALSE;
  1923. }
  1924. /*lint -e(613)*/RegEnum->RegEnumInfo.CallbackOnError = CallbackOnError;
  1925. return EnumNextRegObjectInTreeW (RegEnum);
  1926. }
  1927. /*++
  1928. Routine Description:
  1929. EnumNextRegObjectInTree enumerates the next node matching the criteria specified in
  1930. RegEnum; this is filled on the call to EnumFirstRegObjectInTreeEx;
  1931. Arguments:
  1932. RegEnum - Specifies the current enum context; receives updated info
  1933. Return Value:
  1934. TRUE if a next match was found; FALSE if no more keys/values match
  1935. --*/
  1936. BOOL
  1937. EnumNextRegObjectInTreeA (
  1938. IN OUT PREGTREE_ENUMA RegEnum
  1939. )
  1940. {
  1941. PREGNODEA currentNode;
  1942. BOOL success;
  1943. MYASSERT (RegEnum);
  1944. do {
  1945. if (RegEnum->EncodedFullName) {
  1946. ObsFreeA (RegEnum->EncodedFullName);
  1947. RegEnum->EncodedFullName = NULL;
  1948. }
  1949. while (TRUE) {
  1950. if (RegEnum->LastWackPtr) {
  1951. *RegEnum->LastWackPtr = '\\';
  1952. RegEnum->LastWackPtr = NULL;
  1953. }
  1954. if (!pEnumNextRegObjectInTreeA (RegEnum, &currentNode)) {
  1955. break;
  1956. }
  1957. MYASSERT (currentNode && currentNode->KeyName);
  1958. //
  1959. // check if this object matches the pattern
  1960. //
  1961. if (!(currentNode->Flags & RNF_KEYNAME_MATCHES)) { //lint !e613
  1962. continue;
  1963. }
  1964. RegEnum->CurrentKeyHandle = /*lint -e(613)*/currentNode->KeyHandle;
  1965. RegEnum->CurrentLevel = RegEnum->RegEnumInfo.RootLevel + /*lint -e(613)*/currentNode->SubLevel;
  1966. if ((!currentNode->ValueName) || (currentNode->Flags & RNF_VALUENAME_INVALID)) {
  1967. RegEnum->Location = /*lint -e(613)*/currentNode->KeyName;
  1968. RegEnum->LastWackPtr = _mbsrchr (RegEnum->Location, '\\');
  1969. if (!RegEnum->LastWackPtr) {
  1970. RegEnum->Name = RegEnum->Location;
  1971. } else {
  1972. RegEnum->Name = _mbsinc (RegEnum->LastWackPtr);
  1973. if (!RegEnum->Name) {
  1974. RegEnum->Name = RegEnum->Location;
  1975. }
  1976. }
  1977. RegEnum->CurrentValueData = NULL;
  1978. RegEnum->CurrentValueDataSize = 0;
  1979. RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType;
  1980. RegEnum->Attributes = REG_ATTRIBUTE_KEY;
  1981. //
  1982. // prepare full path buffer
  1983. //
  1984. StringCopyA (RegEnum->NativeFullName, RegEnum->Location);
  1985. RegEnum->LastNode = currentNode;
  1986. RegEnum->RegNameAppendPos = NULL;
  1987. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  1988. if (ElIsExcluded2A (ELT_REGISTRY, RegEnum->Location, NULL)) {
  1989. DEBUGMSGA ((
  1990. DBG_REGENUM,
  1991. "EnumNextRegObjectInTreeA: RegKey %s was found, but it's excluded",
  1992. RegEnum->Location
  1993. ));
  1994. continue;
  1995. }
  1996. }
  1997. RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExA (
  1998. RegEnum->Location,
  1999. NULL,
  2000. TRUE
  2001. );
  2002. } else {
  2003. RegEnum->Location = /*lint -e(613)*/currentNode->KeyName;
  2004. RegEnum->Name = /*lint -e(613)*/currentNode->ValueName;
  2005. RegEnum->CurrentValueData = /*lint -e(613)*/currentNode->ValueData;
  2006. RegEnum->CurrentValueDataSize = currentNode->ValueDataSize;
  2007. RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType;
  2008. if (RegEnum->LastNode != currentNode) {
  2009. RegEnum->LastNode = currentNode;
  2010. //
  2011. // prepare full path buffer
  2012. //
  2013. RegEnum->NativeFullName[0] = 0;
  2014. RegEnum->RegNameAppendPos = StringCatA (RegEnum->NativeFullName, RegEnum->Location);
  2015. RegEnum->RegNameAppendPos = StringCatA (RegEnum->RegNameAppendPos, "\\[");
  2016. } else if (!RegEnum->RegNameAppendPos) {
  2017. RegEnum->RegNameAppendPos = GetEndOfStringA (RegEnum->NativeFullName);
  2018. RegEnum->RegNameAppendPos = StringCatA (RegEnum->RegNameAppendPos, "\\[");
  2019. }
  2020. MYASSERT (RegEnum->Name);
  2021. if ((RegEnum->RegNameAppendPos + SizeOfStringA (RegEnum->Name) / DWSIZEOF(CHAR))>
  2022. (RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(CHAR))) {
  2023. DEBUGMSGA ((
  2024. DBG_ERROR,
  2025. "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's path is too long",
  2026. RegEnum->Location,
  2027. RegEnum->Name
  2028. ));
  2029. continue;
  2030. }
  2031. StringCopyA (RegEnum->RegNameAppendPos, RegEnum->Name);
  2032. StringCatA (RegEnum->RegNameAppendPos, "]");
  2033. RegEnum->Attributes = REG_ATTRIBUTE_VALUE;
  2034. //
  2035. // now test if the value matches
  2036. //
  2037. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTLEAF | OBSPF_OPTIONALLEAF)) &&
  2038. !TestParsedPatternA (
  2039. RegEnum->RegEnumInfo.RegPattern->LeafPattern,
  2040. RegEnum->Name
  2041. )
  2042. ) {
  2043. continue;
  2044. }
  2045. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  2046. //
  2047. // check if this object is excluded
  2048. //
  2049. if (RegEnum->Name && ElIsExcluded2A (ELT_REGISTRY, NULL, RegEnum->Name)) {
  2050. DEBUGMSGA ((
  2051. DBG_REGENUM,
  2052. "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded by value name",
  2053. RegEnum->Location,
  2054. RegEnum->Name
  2055. ));
  2056. continue;
  2057. }
  2058. if (ElIsExcluded2A (ELT_REGISTRY, RegEnum->Location, RegEnum->Name)) {
  2059. DEBUGMSGA ((
  2060. DBG_REGENUM,
  2061. "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded",
  2062. RegEnum->Location,
  2063. RegEnum->Name
  2064. ));
  2065. continue;
  2066. }
  2067. }
  2068. RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExA (
  2069. RegEnum->Location,
  2070. RegEnum->Name,
  2071. TRUE
  2072. );
  2073. }
  2074. if (RegEnum->LastWackPtr) {
  2075. *RegEnum->LastWackPtr = 0;
  2076. }
  2077. return TRUE;
  2078. }
  2079. //
  2080. // try the next root
  2081. //
  2082. if (RegEnum->RootState == RES_ROOT_DONE) {
  2083. break;
  2084. }
  2085. MYASSERT (RegEnum->RootState == RES_ROOT_NEXT);
  2086. MYASSERT (RegEnum->RootEnum);
  2087. success = pEnumNextRegRootA (RegEnum);
  2088. } while (success);
  2089. AbortRegObjectInTreeEnumA (RegEnum);
  2090. return FALSE;
  2091. }
  2092. BOOL
  2093. EnumNextRegObjectInTreeW (
  2094. IN OUT PREGTREE_ENUMW RegEnum
  2095. )
  2096. {
  2097. PREGNODEW currentNode;
  2098. BOOL success;
  2099. MYASSERT (RegEnum);
  2100. do {
  2101. if (RegEnum->EncodedFullName) {
  2102. ObsFreeW (RegEnum->EncodedFullName);
  2103. RegEnum->EncodedFullName = NULL;
  2104. }
  2105. while (TRUE) {
  2106. if (RegEnum->LastWackPtr) {
  2107. *RegEnum->LastWackPtr = L'\\';
  2108. RegEnum->LastWackPtr = NULL;
  2109. }
  2110. if (!pEnumNextRegObjectInTreeW (RegEnum, &currentNode)) {
  2111. break;
  2112. }
  2113. MYASSERT (currentNode && currentNode->KeyName);
  2114. //
  2115. // check if this object matches the pattern
  2116. //
  2117. if (!(currentNode->Flags & RNF_KEYNAME_MATCHES)) { //lint !e613
  2118. continue;
  2119. }
  2120. RegEnum->CurrentKeyHandle = /*lint -e(613)*/currentNode->KeyHandle;
  2121. RegEnum->CurrentLevel = RegEnum->RegEnumInfo.RootLevel + /*lint -e(613)*/currentNode->SubLevel;
  2122. if ((!currentNode->ValueName) || (currentNode->Flags & RNF_VALUENAME_INVALID)) {
  2123. RegEnum->Location = /*lint -e(613)*/currentNode->KeyName;
  2124. RegEnum->LastWackPtr = wcsrchr (RegEnum->Location, L'\\');
  2125. if (!RegEnum->LastWackPtr) {
  2126. RegEnum->Name = RegEnum->Location;
  2127. } else {
  2128. RegEnum->Name = RegEnum->LastWackPtr + 1;
  2129. if (!RegEnum->Name) {
  2130. RegEnum->Name = RegEnum->Location;
  2131. }
  2132. }
  2133. RegEnum->CurrentValueData = NULL;
  2134. RegEnum->CurrentValueDataSize = 0;
  2135. RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType;
  2136. RegEnum->Attributes = REG_ATTRIBUTE_KEY;
  2137. //
  2138. // prepare full path buffer
  2139. //
  2140. StringCopyW (RegEnum->NativeFullName, RegEnum->Location);
  2141. RegEnum->LastNode = currentNode;
  2142. RegEnum->RegNameAppendPos = NULL;
  2143. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  2144. if (ElIsExcluded2W (ELT_REGISTRY, RegEnum->Location, NULL)) {
  2145. DEBUGMSGW ((
  2146. DBG_REGENUM,
  2147. "EnumNextRegObjectInTreeA: RegKey %s was found, but it's excluded",
  2148. RegEnum->Location
  2149. ));
  2150. continue;
  2151. }
  2152. }
  2153. RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExW (
  2154. RegEnum->Location,
  2155. NULL,
  2156. TRUE
  2157. );
  2158. } else {
  2159. RegEnum->Location = /*lint -e(613)*/currentNode->KeyName;
  2160. RegEnum->Name = /*lint -e(613)*/currentNode->ValueName;
  2161. RegEnum->CurrentValueData = /*lint -e(613)*/currentNode->ValueData;
  2162. RegEnum->CurrentValueDataSize = currentNode->ValueDataSize;
  2163. RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType;
  2164. if (RegEnum->LastNode != currentNode) {
  2165. RegEnum->LastNode = currentNode;
  2166. //
  2167. // prepare full path buffer
  2168. //
  2169. RegEnum->NativeFullName[0] = 0;
  2170. RegEnum->RegNameAppendPos = StringCatW (RegEnum->NativeFullName, RegEnum->Location);
  2171. RegEnum->RegNameAppendPos = StringCatW (RegEnum->RegNameAppendPos, L"\\[");
  2172. } else if (!RegEnum->RegNameAppendPos) {
  2173. RegEnum->RegNameAppendPos = GetEndOfStringW (RegEnum->NativeFullName);
  2174. RegEnum->RegNameAppendPos = StringCatW (RegEnum->RegNameAppendPos, L"\\[");
  2175. }
  2176. MYASSERT (RegEnum->Name);
  2177. {
  2178. UINT size1 = 0;
  2179. UINT size2 = 0;
  2180. INT size3 = 0;
  2181. size1 = (UINT)(RegEnum->RegNameAppendPos + SizeOfStringW (RegEnum->Name) / DWSIZEOF(WCHAR));
  2182. size2 = (UINT)(RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(WCHAR));
  2183. size3 = size2 - size1;
  2184. }
  2185. if ((RegEnum->RegNameAppendPos + SizeOfStringW (RegEnum->Name) / DWSIZEOF(WCHAR))>
  2186. (RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(WCHAR))) {
  2187. DEBUGMSGW ((
  2188. DBG_ERROR,
  2189. "EnumNextRegObjectInTreeW: RegKey %s [%s] was found, but it's path is too long",
  2190. RegEnum->Location,
  2191. RegEnum->Name
  2192. ));
  2193. continue;
  2194. }
  2195. StringCopyW (RegEnum->RegNameAppendPos, RegEnum->Name);
  2196. StringCatW (RegEnum->RegNameAppendPos, L"]");
  2197. RegEnum->Attributes = REG_ATTRIBUTE_VALUE;
  2198. //
  2199. // now test if the value matches
  2200. //
  2201. if (!(RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTLEAF | OBSPF_OPTIONALLEAF)) &&
  2202. !TestParsedPatternW (
  2203. RegEnum->RegEnumInfo.RegPattern->LeafPattern,
  2204. RegEnum->Name
  2205. )
  2206. ) {
  2207. continue;
  2208. }
  2209. if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) {
  2210. //
  2211. // check if this object is excluded
  2212. //
  2213. if (RegEnum->Name && ElIsExcluded2W (ELT_REGISTRY, NULL, RegEnum->Name)) {
  2214. DEBUGMSGW ((
  2215. DBG_REGENUM,
  2216. "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded by value name",
  2217. RegEnum->Location,
  2218. RegEnum->Name
  2219. ));
  2220. continue;
  2221. }
  2222. if (ElIsExcluded2W (ELT_REGISTRY, RegEnum->Location, RegEnum->Name)) {
  2223. DEBUGMSGW ((
  2224. DBG_REGENUM,
  2225. "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded",
  2226. RegEnum->Location,
  2227. RegEnum->Name
  2228. ));
  2229. continue;
  2230. }
  2231. }
  2232. RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExW (
  2233. RegEnum->Location,
  2234. RegEnum->Name,
  2235. TRUE
  2236. );
  2237. }
  2238. if (RegEnum->LastWackPtr) {
  2239. *RegEnum->LastWackPtr = 0;
  2240. }
  2241. return TRUE;
  2242. }
  2243. //
  2244. // try the next root
  2245. //
  2246. if (RegEnum->RootState == RES_ROOT_DONE) {
  2247. break;
  2248. }
  2249. MYASSERT (RegEnum->RootState == RES_ROOT_NEXT);
  2250. MYASSERT (RegEnum->RootEnum);
  2251. success = pEnumNextRegRootW (RegEnum);
  2252. } while (success);
  2253. AbortRegObjectInTreeEnumW (RegEnum);
  2254. return FALSE;
  2255. }
  2256. /*++
  2257. Routine Description:
  2258. AbortRegObjectInTreeEnum aborts the enumeration, freeing all resources allocated
  2259. Arguments:
  2260. RegEnum - Specifies the current enum context; receives a "clean" context
  2261. Return Value:
  2262. none
  2263. --*/
  2264. VOID
  2265. AbortRegObjectInTreeEnumA (
  2266. IN OUT PREGTREE_ENUMA RegEnum
  2267. )
  2268. {
  2269. while (pDeleteRegNodeA (RegEnum, TRUE)) {
  2270. }
  2271. GbFree (&RegEnum->RegNodes);
  2272. if (RegEnum->EncodedFullName) {
  2273. ObsFreeA (RegEnum->EncodedFullName);
  2274. RegEnum->EncodedFullName = NULL;
  2275. }
  2276. if (RegEnum->RegEnumInfo.RegPattern) {
  2277. ObsDestroyParsedPatternA (RegEnum->RegEnumInfo.RegPattern);
  2278. RegEnum->RegEnumInfo.RegPattern = NULL;
  2279. }
  2280. if (RegEnum->RootEnum) {
  2281. pFreeMemory (RegEnum->RootEnum);
  2282. RegEnum->RootEnum = NULL;
  2283. }
  2284. }
  2285. VOID
  2286. AbortRegObjectInTreeEnumW (
  2287. IN OUT PREGTREE_ENUMW RegEnum
  2288. )
  2289. {
  2290. while (pDeleteRegNodeW (RegEnum, TRUE)) {
  2291. }
  2292. GbFree (&RegEnum->RegNodes);
  2293. if (RegEnum->EncodedFullName) {
  2294. ObsFreeW (RegEnum->EncodedFullName);
  2295. RegEnum->EncodedFullName = NULL;
  2296. }
  2297. if (RegEnum->RegEnumInfo.RegPattern) {
  2298. ObsDestroyParsedPatternW (RegEnum->RegEnumInfo.RegPattern);
  2299. RegEnum->RegEnumInfo.RegPattern = NULL;
  2300. }
  2301. if (RegEnum->RootEnum) {
  2302. pFreeMemory (RegEnum->RootEnum);
  2303. RegEnum->RootEnum = NULL;
  2304. }
  2305. }