/*++ Copyright (c) 1999 Microsoft Corporation Module Name: regenum.c Abstract: Implements a set of APIs to enumerate the local registry using Win32 APIs. Author: 20-Oct-1999 Ovidiu Temereanca (ovidiut) - File creation. Revision History: --*/ #include "pch.h" #include "reg.h" // // Includes // // None #define DBG_REGENUM "RegEnum" // // Strings // #define S_REGENUM "REGENUM" // // Constants // // None // // Macros // #define pAllocateMemory(Size) PmGetMemory (g_RegEnumPool,Size) #define pFreeMemory(Buffer) if (Buffer) PmReleaseMemory (g_RegEnumPool, (PVOID)Buffer) // // Types // // None // // Globals // PMHANDLE g_RegEnumPool; // // Macro expansion list // // None // // Private function prototypes // // None // // Macro expansion definition // // None // // Code // BOOL RegEnumInitialize ( VOID ) /*++ Routine Description: RegEnumInitialize initializes this library. Arguments: none Return Value: TRUE if the init was successful. FALSE if not. GetLastError() returns extended error info. --*/ { g_RegEnumPool = PmCreateNamedPool (S_REGENUM); return g_RegEnumPool != NULL; } VOID RegEnumTerminate ( VOID ) /*++ Routine Description: RegEnumTerminate is called to free resources used by this lib. Arguments: none Return Value: none --*/ { DumpOpenKeys (); if (g_RegEnumPool) { PmDestroyPool (g_RegEnumPool); g_RegEnumPool = NULL; } } BOOL RegEnumDefaultCallbackA ( IN PREGNODEA RegNode OPTIONAL ) { return TRUE; } BOOL RegEnumDefaultCallbackW ( IN PREGNODEW RegNode OPTIONAL ) { return TRUE; } INT g_RootEnumIndexTable [] = { 2, 4, 6, 8, -1}; BOOL EnumFirstRegRootA ( OUT PREGROOT_ENUMA EnumPtr ) { EnumPtr->Index = 0; return EnumNextRegRootA (EnumPtr); } BOOL EnumFirstRegRootW ( OUT PREGROOT_ENUMW EnumPtr ) { EnumPtr->Index = 0; return EnumNextRegRootW (EnumPtr); } BOOL EnumNextRegRootA ( IN OUT PREGROOT_ENUMA EnumPtr ) { INT i; LONG result; i = g_RootEnumIndexTable [EnumPtr->Index]; while (i >= 0) { EnumPtr->RegRootName = GetRootStringFromOffsetA (i); EnumPtr->RegRootHandle = GetRootKeyFromOffset(i); EnumPtr->Index++; result = RegQueryInfoKey ( EnumPtr->RegRootHandle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); if (result == ERROR_SUCCESS) { return TRUE; } i = g_RootEnumIndexTable [EnumPtr->Index]; } return FALSE; } BOOL EnumNextRegRootW ( IN OUT PREGROOT_ENUMW EnumPtr ) { INT i; LONG result; i = g_RootEnumIndexTable [EnumPtr->Index]; while (i >= 0) { EnumPtr->RegRootName = GetRootStringFromOffsetW (i); EnumPtr->RegRootHandle = GetRootKeyFromOffset(i); EnumPtr->Index++; result = RegQueryInfoKey ( EnumPtr->RegRootHandle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); if (result == ERROR_SUCCESS) { return TRUE; } i = g_RootEnumIndexTable [EnumPtr->Index]; } return FALSE; } /*++ Routine Description: pGetRegEnumInfo is a private function that validates and translates the enumeration info in an internal form that's more accessible to the enum routines Arguments: RegEnumInfo - Receives the enum info EncodedRegPattern - Specifies the encoded pattern (encoded as defined by the ObjectString functions) EnumKeyNames - Specifies TRUE if key names should be returned during the enumeration (if they match the pattern); a key name is returned before any of its subkeys or values ContainersFirst - Specifies TRUE if keys should be returned before any of its values or subkeys; used only if EnumKeyNames is TRUE ValuesFirst - Specifies TRUE if a key's values should be returned before key's subkeys; this parameter decides the enum order between values and subkeys for each key DepthFirst - Specifies TRUE if the current subkey of any key should be fully enumerated before going to the next subkey; this parameter decides if the tree traversal is depth-first (TRUE) or width-first (FALSE) MaxSubLevel - Specifies the maximum level of a key that is to be enumerated, relative to the root; if -1, all sub-levels are enumerated UseExclusions - Specifies TRUE if exclusion APIs should be used to determine if certain keys/values are excluded from enumeration; this slows down the speed ReadValueData - Specifies TRUE if data associated with values should also be returned Return Value: TRUE if all params are valid; in this case, RegEnumInfo is filled with the corresponding info. FALSE otherwise. --*/ BOOL pGetRegEnumInfoA ( OUT PREGENUMINFOA RegEnumInfo, IN PCSTR EncodedRegPattern, IN BOOL EnumKeyNames, IN BOOL ContainersFirst, IN BOOL ValuesFirst, IN BOOL DepthFirst, IN DWORD MaxSubLevel, IN BOOL UseExclusions, IN BOOL ReadValueData ) { RegEnumInfo->RegPattern = ObsCreateParsedPatternA (EncodedRegPattern); if (!RegEnumInfo->RegPattern) { DEBUGMSGA ((DBG_ERROR, "pGetRegEnumInfoA: bad EncodedRegPattern: %s", EncodedRegPattern)); return FALSE; } if (RegEnumInfo->RegPattern->ExactRoot) { if (!GetNodePatternMinMaxLevelsA ( RegEnumInfo->RegPattern->ExactRoot, NULL, &RegEnumInfo->RootLevel, NULL )) { return FALSE; } } else { RegEnumInfo->RootLevel = 1; } if (!RegEnumInfo->RegPattern->Leaf) { // // no value pattern specified; assume only keynames will be returned // overwrite caller's setting // DEBUGMSGA (( DBG_REGENUM, "pGetRegEnumInfoA: no value pattern specified; forcing EnumDirNames to TRUE" )); EnumKeyNames = TRUE; } if (EnumKeyNames) { RegEnumInfo->Flags |= REIF_RETURN_KEYS; } if (ContainersFirst) { RegEnumInfo->Flags |= REIF_CONTAINERS_FIRST; } if (ValuesFirst) { RegEnumInfo->Flags |= REIF_VALUES_FIRST; } if (DepthFirst) { RegEnumInfo->Flags |= REIF_DEPTH_FIRST; } if (UseExclusions) { RegEnumInfo->Flags |= REIF_USE_EXCLUSIONS; } if (ReadValueData) { RegEnumInfo->Flags |= REIF_READ_VALUE_DATA; } RegEnumInfo->MaxSubLevel = min (MaxSubLevel, RegEnumInfo->RegPattern->MaxSubLevel); return TRUE; } BOOL pGetRegEnumInfoW ( OUT PREGENUMINFOW RegEnumInfo, IN PCWSTR EncodedRegPattern, IN BOOL EnumKeyNames, IN BOOL ContainersFirst, IN BOOL ValuesFirst, IN BOOL DepthFirst, IN DWORD MaxSubLevel, IN BOOL UseExclusions, IN BOOL ReadValueData ) { RegEnumInfo->RegPattern = ObsCreateParsedPatternW (EncodedRegPattern); if (!RegEnumInfo->RegPattern) { DEBUGMSGW ((DBG_ERROR, "pGetRegEnumInfoW: bad EncodedRegPattern: %s", EncodedRegPattern)); return FALSE; } if (RegEnumInfo->RegPattern->ExactRoot) { if (!GetNodePatternMinMaxLevelsW ( RegEnumInfo->RegPattern->ExactRoot, //lint !e64 NULL, &RegEnumInfo->RootLevel, NULL )) { //lint !e64 return FALSE; } } else { RegEnumInfo->RootLevel = 1; } if (!RegEnumInfo->RegPattern->Leaf) { // // no value pattern specified; assume only keynames will be returned // overwrite caller's setting // DEBUGMSGW (( DBG_REGENUM, "pGetRegEnumInfoW: no value pattern specified; forcing EnumDirNames to TRUE" )); EnumKeyNames = TRUE; } if (EnumKeyNames) { RegEnumInfo->Flags |= REIF_RETURN_KEYS; } if (ContainersFirst) { RegEnumInfo->Flags |= REIF_CONTAINERS_FIRST; } if (ValuesFirst) { RegEnumInfo->Flags |= REIF_VALUES_FIRST; } if (DepthFirst) { RegEnumInfo->Flags |= REIF_DEPTH_FIRST; } if (UseExclusions) { RegEnumInfo->Flags |= REIF_USE_EXCLUSIONS; } if (ReadValueData) { RegEnumInfo->Flags |= REIF_READ_VALUE_DATA; } RegEnumInfo->MaxSubLevel = min (MaxSubLevel, RegEnumInfo->RegPattern->MaxSubLevel); return TRUE; } /*++ Routine Description: pGetRegNodeInfo retrieves information about a key, using its name Arguments: RegNode - Receives information about this key ReadData - Specifies if the data associated with this value should be read Return Value: TRUE if info was successfully read, FALSE otherwise. --*/ BOOL pGetRegNodeInfoA ( IN OUT PREGNODEA RegNode, IN BOOL ReadData ) { LONG rc; rc = RegQueryInfoKeyA ( RegNode->KeyHandle, NULL, NULL, NULL, &RegNode->SubKeyCount, &RegNode->SubKeyLengthMax, NULL, &RegNode->ValueCount, &RegNode->ValueLengthMax, ReadData ? &RegNode->ValueDataSizeMax : NULL, NULL, NULL ); if (rc != ERROR_SUCCESS) { return FALSE; } if (RegNode->SubKeyCount) { if (RegNode->SubKeyLengthMax) { // // add space for the NULL // RegNode->SubKeyLengthMax++; } else { // // OS bug // RegNode->SubKeyLengthMax = MAX_REGISTRY_KEYA; } RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (MBCHAR)); } if (RegNode->ValueCount) { // // add space for the NULL // RegNode->ValueLengthMax++; RegNode->ValueName = pAllocateMemory (RegNode->ValueLengthMax * DWSIZEOF (MBCHAR)); if (ReadData) { RegNode->ValueDataSizeMax++; RegNode->ValueData = pAllocateMemory (RegNode->ValueDataSizeMax); } RegNode->Flags |= RNF_VALUENAME_INVALID | RNF_VALUEDATA_INVALID; } return TRUE; } BOOL pGetRegNodeInfoW ( IN OUT PREGNODEW RegNode, IN BOOL ReadData ) { LONG rc; rc = RegQueryInfoKeyW ( RegNode->KeyHandle, NULL, NULL, NULL, &RegNode->SubKeyCount, &RegNode->SubKeyLengthMax, NULL, &RegNode->ValueCount, &RegNode->ValueLengthMax, ReadData ? &RegNode->ValueDataSizeMax : NULL, NULL, NULL ); if (rc != ERROR_SUCCESS) { return FALSE; } if (RegNode->SubKeyCount) { if (RegNode->SubKeyLengthMax) { // // add space for the NULL // RegNode->SubKeyLengthMax++; } else { // // OS bug // RegNode->SubKeyLengthMax = MAX_REGISTRY_KEYW; } RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (WCHAR)); } if (RegNode->ValueCount) { // // add space for the NULL // RegNode->ValueLengthMax++; RegNode->ValueName = pAllocateMemory (RegNode->ValueLengthMax * DWSIZEOF (WCHAR)); if (ReadData) { RegNode->ValueDataSizeMax++; RegNode->ValueData = pAllocateMemory (RegNode->ValueDataSizeMax); } RegNode->Flags |= RNF_VALUENAME_INVALID | RNF_VALUEDATA_INVALID; } return TRUE; } /*++ Routine Description: pGetCurrentRegNode returns the current reg node to be enumerated, based on DepthFirst flag Arguments: RegEnum - Specifies the context LastCreated - Specifies TRUE if the last created node is to be retrieved, regardless of DepthFirst flag Return Value: The current node if any or NULL if none remaining. --*/ PREGNODEA pGetCurrentRegNodeA ( IN PREGTREE_ENUMA RegEnum, IN BOOL LastCreated ) { PGROWBUFFER gb = &RegEnum->RegNodes; if (gb->End - gb->UserIndex < DWSIZEOF (REGNODEA)) { return NULL; } if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) { return (PREGNODEA)(gb->Buf + gb->End) - 1; } else { return (PREGNODEA)(gb->Buf + gb->UserIndex); } } PREGNODEW pGetCurrentRegNodeW ( IN PREGTREE_ENUMW RegEnum, IN BOOL LastCreated ) { PGROWBUFFER gb = &RegEnum->RegNodes; if (gb->End - gb->UserIndex < DWSIZEOF (REGNODEW)) { return NULL; } if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) { return (PREGNODEW)(gb->Buf + gb->End) - 1; } else { return (PREGNODEW)(gb->Buf + gb->UserIndex); } } /*++ Routine Description: pDeleteRegNode frees the resources associated with the current reg node and destroys it Arguments: RegEnum - Specifies the context LastCreated - Specifies TRUE if the last created node is to be deleted, regardless of DepthFirst flag Return Value: TRUE if there was a node to delete, FALSE if no more nodes --*/ BOOL pDeleteRegNodeA ( IN OUT PREGTREE_ENUMA RegEnum, IN BOOL LastCreated ) { PREGNODEA regNode; PGROWBUFFER gb = &RegEnum->RegNodes; regNode = pGetCurrentRegNodeA (RegEnum, LastCreated); if (!regNode) { return FALSE; } if (regNode->KeyHandle) { CloseRegKey (regNode->KeyHandle); } if (regNode->KeyName) { FreePathStringExA (g_RegEnumPool, regNode->KeyName); } if (regNode->SubKeyName) { pFreeMemory (regNode->SubKeyName); } if (regNode->ValueName) { pFreeMemory (regNode->ValueName); } if (regNode->ValueData) { pFreeMemory (regNode->ValueData); } if (RegEnum->LastNode == regNode) { RegEnum->LastNode = NULL; } // // delete node // if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) { gb->End -= DWSIZEOF (REGNODEA); } else { gb->UserIndex += DWSIZEOF (REGNODEA); // // reset list // if (gb->Size - gb->End < DWSIZEOF (REGNODEA)) { MoveMemory (gb->Buf, gb->Buf + gb->UserIndex, gb->End - gb->UserIndex); gb->End -= gb->UserIndex; gb->UserIndex = 0; } } return TRUE; } BOOL pDeleteRegNodeW ( IN OUT PREGTREE_ENUMW RegEnum, IN BOOL LastCreated ) { PREGNODEW regNode; PGROWBUFFER gb = &RegEnum->RegNodes; regNode = pGetCurrentRegNodeW (RegEnum, LastCreated); if (!regNode) { return FALSE; } if (regNode->KeyHandle) { CloseRegKey (regNode->KeyHandle); } if (regNode->KeyName) { FreePathStringExW (g_RegEnumPool, regNode->KeyName); } if (regNode->SubKeyName) { pFreeMemory (regNode->SubKeyName); } if (regNode->ValueName) { pFreeMemory (regNode->ValueName); } if (regNode->ValueData) { pFreeMemory (regNode->ValueData); } if (RegEnum->LastNode == regNode) { RegEnum->LastNode = NULL; } // // delete node // if (LastCreated || (RegEnum->RegEnumInfo.Flags & REIF_DEPTH_FIRST)) { gb->End -= DWSIZEOF (REGNODEW); } else { gb->UserIndex += DWSIZEOF (REGNODEW); // // reset list // if (gb->Size - gb->End < DWSIZEOF (REGNODEW)) { MoveMemory (gb->Buf, gb->Buf + gb->UserIndex, gb->End - gb->UserIndex); gb->End -= gb->UserIndex; gb->UserIndex = 0; } } return TRUE; } /*++ Routine Description: pCreateRegNode creates a new node given a context, a key name or a parent node Arguments: RegEnum - Specifies the context KeyName - Specifies the key name of the new node; may be NULL only if ParentNode is not NULL ParentNode - Specifies a pointer to the parent node of the new node; a pointer to the node is required because the parent node location in memory may change as a result of the growbuffer changing buffer location when it grows; may be NULL only if KeyName is not; Ignore - Receives a meaningful value only if NULL is returned (no node created); if TRUE upon return, the failure of node creation should be ignored Return Value: A pointer to the new node or NULL if no node was created --*/ PREGNODEA pCreateRegNodeA ( IN OUT PREGTREE_ENUMA RegEnum, IN PCSTR KeyName, OPTIONAL IN PREGNODEA* ParentNode, OPTIONAL IN PBOOL Ignore OPTIONAL ) { PREGNODEA newNode; PSTR newKeyName; REGSAM prevMode; PSEGMENTA FirstSegment; LONG offset = 0; if (KeyName) { newKeyName = DuplicateTextExA (g_RegEnumPool, KeyName, 0, NULL); } else { MYASSERT (ParentNode); newKeyName = JoinPathsInPoolExA (( g_RegEnumPool, (*ParentNode)->KeyName, (*ParentNode)->SubKeyName, NULL )); // // check if this starting path may match the pattern before continuing // FirstSegment = RegEnum->RegEnumInfo.RegPattern->NodePattern->Pattern->Segment; if (FirstSegment->Type == SEGMENTTYPE_EXACTMATCH && !StringIMatchByteCountA ( FirstSegment->Exact.LowerCasePhrase, newKeyName, FirstSegment->Exact.PhraseBytes )) { DEBUGMSGA (( DBG_REGENUM, "Skipping tree %s\\* because it cannot match the pattern", newKeyName )); FreeTextExA (g_RegEnumPool, newKeyName); if (Ignore) { *Ignore = TRUE; } return NULL; } } if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { // // look if this key and the whole subtree are excluded; if so, soft block creation of node // if (ElIsTreeExcluded2A (ELT_REGISTRY, newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { DEBUGMSGA (( DBG_REGENUM, "Skipping tree %s\\%s because it's excluded", newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf )); FreeTextExA (g_RegEnumPool, newKeyName); if (Ignore) { *Ignore = TRUE; } return NULL; } } if (ParentNode) { // // remember current offset // offset = (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf); } // // allocate space for the new node in the growbuffer // newNode = (PREGNODEA) GbGrow (&RegEnum->RegNodes, DWSIZEOF (REGNODEA)); if (!newNode) { FreeTextExA (g_RegEnumPool, newKeyName); goto fail; } if (ParentNode) { // // check if the buffer moved // if (offset != (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf)) { // // adjust the parent position // *ParentNode = (PREGNODEA)(RegEnum->RegNodes.Buf + offset); } } // // initialize the newly created node // ZeroMemory (newNode, DWSIZEOF (REGNODEA)); newNode->KeyName = newKeyName; prevMode = SetRegOpenAccessMode (KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS); if (ParentNode) { newNode->KeyHandle = OpenRegKeyA ((*ParentNode)->KeyHandle, (*ParentNode)->SubKeyName); newNode->Flags |= RNF_RETURN_KEYS; } else { newNode->KeyHandle = OpenRegKeyStrA (newNode->KeyName); if ((RegEnum->RegEnumInfo.RegPattern->Leaf == NULL) && (RegEnum->RegEnumInfo.RegPattern->ExactRoot) && (!WildCharsPatternA (RegEnum->RegEnumInfo.RegPattern->NodePattern)) ) { newNode->Flags |= DNF_RETURN_DIRNAME; } } SetRegOpenAccessMode (prevMode); if (!newNode->KeyHandle) { DEBUGMSGA (( DBG_REGENUM, "pCreateRegNodeA: Cannot open registry key: %s; rc=%lu", newNode->KeyName, GetLastError() )); goto fail; } if (!pGetRegNodeInfoA (newNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { DEBUGMSGA (( DBG_REGENUM, "pCreateRegNodeA: Cannot get info for key: %s; rc=%lu", newNode->KeyName, GetLastError() )); goto fail; } newNode->EnumState = RNS_ENUM_INIT; if ((RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTNODE | OBSPF_NODEISROOTPLUSSTAR)) || TestParsedPatternA (RegEnum->RegEnumInfo.RegPattern->NodePattern, newKeyName) ) { newNode->Flags |= RNF_KEYNAME_MATCHES; } if (ParentNode) { newNode->SubLevel = (*ParentNode)->SubLevel + 1; } else { newNode->SubLevel = 0; } return newNode; fail: if (Ignore) { if (RegEnum->RegEnumInfo.CallbackOnError) { *Ignore = (*RegEnum->RegEnumInfo.CallbackOnError)(newNode); } else { *Ignore = FALSE; } } if (newNode) { pDeleteRegNodeA (RegEnum, TRUE); } return NULL; } PREGNODEW pCreateRegNodeW ( IN OUT PREGTREE_ENUMW RegEnum, IN PCWSTR KeyName, OPTIONAL IN PREGNODEW* ParentNode, OPTIONAL OUT PBOOL Ignore OPTIONAL ) { PREGNODEW newNode; PWSTR newKeyName; REGSAM prevMode; PSEGMENTW FirstSegment; LONG offset = 0; if (KeyName) { newKeyName = DuplicateTextExW (g_RegEnumPool, KeyName, 0, NULL); } else { MYASSERT (ParentNode); newKeyName = JoinPathsInPoolExW (( g_RegEnumPool, (*ParentNode)->KeyName, (*ParentNode)->SubKeyName, NULL )); // // check if this starting path may match the pattern before continuing // FirstSegment = RegEnum->RegEnumInfo.RegPattern->NodePattern->Pattern->Segment; if (FirstSegment->Type == SEGMENTTYPE_EXACTMATCH && !StringIMatchByteCountW ( FirstSegment->Exact.LowerCasePhrase, newKeyName, FirstSegment->Exact.PhraseBytes )) { //lint !e64 DEBUGMSGW (( DBG_REGENUM, "Skipping tree %s\\* because it cannot match the pattern", newKeyName )); FreeTextExW (g_RegEnumPool, newKeyName); if (Ignore) { *Ignore = TRUE; } return NULL; } } if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { // // look if this key and the whole subtree are excluded; if so, soft block creation of node // if (ElIsTreeExcluded2W (ELT_REGISTRY, newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { //lint !e64 DEBUGMSGW (( DBG_REGENUM, "Skipping tree %s\\%s because it's excluded", newKeyName, RegEnum->RegEnumInfo.RegPattern->Leaf )); FreeTextExW (g_RegEnumPool, newKeyName); if (Ignore) { *Ignore = TRUE; } return NULL; } } if (ParentNode) { // // remember current offset // offset = (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf); } // // allocate space for the new node in the growbuffer // newNode = (PREGNODEW) GbGrow (&RegEnum->RegNodes, DWSIZEOF (REGNODEW)); if (!newNode) { FreeTextExW (g_RegEnumPool, newKeyName); goto fail; } if (ParentNode) { // // check if the buffer moved // if (offset != (LONG)((PBYTE)*ParentNode - RegEnum->RegNodes.Buf)) { // // adjust the parent position // *ParentNode = (PREGNODEW)(RegEnum->RegNodes.Buf + offset); } } // // initialize the newly created node // ZeroMemory (newNode, DWSIZEOF (REGNODEW)); newNode->KeyName = newKeyName; prevMode = SetRegOpenAccessMode (KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS); if (ParentNode) { newNode->KeyHandle = OpenRegKeyW ((*ParentNode)->KeyHandle, (*ParentNode)->SubKeyName); newNode->Flags |= RNF_RETURN_KEYS; } else { newNode->KeyHandle = OpenRegKeyStrW (newNode->KeyName); if ((RegEnum->RegEnumInfo.RegPattern->Leaf == NULL) && (RegEnum->RegEnumInfo.RegPattern->ExactRoot) && (!WildCharsPatternW (RegEnum->RegEnumInfo.RegPattern->NodePattern)) ) { newNode->Flags |= DNF_RETURN_DIRNAME; } } SetRegOpenAccessMode (prevMode); if (!newNode->KeyHandle) { DEBUGMSGW (( DBG_REGENUM, "pCreateRegNodeW: Cannot open registry key: %s; rc=%lu", newNode->KeyName, GetLastError() )); goto fail; } if (!pGetRegNodeInfoW (newNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { DEBUGMSGW (( DBG_REGENUM, "pCreateRegNodeW: Cannot get info for key: %s; rc=%lu", newNode->KeyName, GetLastError() )); goto fail; } newNode->EnumState = RNS_ENUM_INIT; if ((RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTNODE | OBSPF_NODEISROOTPLUSSTAR)) || TestParsedPatternW (RegEnum->RegEnumInfo.RegPattern->NodePattern, newKeyName) ) { newNode->Flags |= RNF_KEYNAME_MATCHES; } if (ParentNode) { newNode->SubLevel = (*ParentNode)->SubLevel + 1; } else { newNode->SubLevel = 0; } return newNode; fail: if (Ignore) { if (RegEnum->RegEnumInfo.CallbackOnError) { *Ignore = (*RegEnum->RegEnumInfo.CallbackOnError)(newNode); } else { *Ignore = FALSE; } } if (newNode) { pDeleteRegNodeW (RegEnum, TRUE); } return NULL; } /*++ Routine Description: pEnumFirstRegRoot enumerates the first root that matches caller's conditions Arguments: RegEnum - Specifies the context; receives updated info Return Value: TRUE if a root node was created; FALSE if not --*/ BOOL pEnumFirstRegRootA ( IN OUT PREGTREE_ENUMA RegEnum ) { PCSTR root; BOOL ignore; root = RegEnum->RegEnumInfo.RegPattern->ExactRoot; if (root) { if (pCreateRegNodeA (RegEnum, root, NULL, NULL)) { RegEnum->RootState = RES_ROOT_DONE; return TRUE; } } else { RegEnum->RootEnum = pAllocateMemory (DWSIZEOF (REGROOT_ENUMA)); if (!EnumFirstRegRootA (RegEnum->RootEnum)) { return FALSE; } do { if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { if (ElIsTreeExcluded2A (ELT_REGISTRY, RegEnum->RootEnum->RegRootName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { DEBUGMSGA ((DBG_REGENUM, "pEnumFirstRegRootA: Root is excluded: %s", RegEnum->RootEnum->RegRootName)); continue; } } if (!pCreateRegNodeA (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) { if (ignore) { continue; } break; } RegEnum->RootState = RES_ROOT_NEXT; return TRUE; } while (EnumNextRegRootA (RegEnum->RootEnum)); pFreeMemory (RegEnum->RootEnum); RegEnum->RootEnum = NULL; } return FALSE; } BOOL pEnumFirstRegRootW ( IN OUT PREGTREE_ENUMW RegEnum ) { PCWSTR root; BOOL ignore; root = RegEnum->RegEnumInfo.RegPattern->ExactRoot; //lint !e64 if (root) { if (pCreateRegNodeW (RegEnum, root, NULL, NULL)) { RegEnum->RootState = RES_ROOT_DONE; return TRUE; } } else { RegEnum->RootEnum = pAllocateMemory (DWSIZEOF (REGROOT_ENUMW)); if (!EnumFirstRegRootW (RegEnum->RootEnum)) { return FALSE; } do { if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { if (ElIsTreeExcluded2W (ELT_REGISTRY, RegEnum->RootEnum->RegRootName, RegEnum->RegEnumInfo.RegPattern->Leaf)) { //lint !e64 DEBUGMSGW ((DBG_REGENUM, "pEnumFirstRegRootW: Root is excluded: %s", RegEnum->RootEnum->RegRootName)); continue; } } if (!pCreateRegNodeW (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) { if (ignore) { continue; } break; } RegEnum->RootState = RES_ROOT_NEXT; return TRUE; } while (EnumNextRegRootW (RegEnum->RootEnum)); pFreeMemory (RegEnum->RootEnum); RegEnum->RootEnum = NULL; } return FALSE; } /*++ Routine Description: pEnumNextRegRoot enumerates the next root that matches caller's conditions Arguments: RegEnum - Specifies the context; receives updated info Return Value: TRUE if a root node was created; FALSE if not --*/ BOOL pEnumNextRegRootA ( IN OUT PREGTREE_ENUMA RegEnum ) { BOOL ignore; while (EnumNextRegRootA (RegEnum->RootEnum)) { if (pCreateRegNodeA (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) { return TRUE; } if (!ignore) { break; } } RegEnum->RootState = RES_ROOT_DONE; return FALSE; } BOOL pEnumNextRegRootW ( IN OUT PREGTREE_ENUMW RegEnum ) { BOOL ignore; while (EnumNextRegRootW (RegEnum->RootEnum)) { if (pCreateRegNodeW (RegEnum, RegEnum->RootEnum->RegRootName, NULL, &ignore)) { return TRUE; } if (!ignore) { break; } } RegEnum->RootState = RES_ROOT_DONE; return FALSE; } /*++ Routine Description: pEnumNextValue enumerates the next value that matches caller's conditions Arguments: RegNode - Specifies the node and the current context; receives updated info ReadData - Specifies if the data associated with this value should be read Return Value: TRUE if a new value was found; FALSE if not --*/ BOOL pEnumNextValueA ( IN OUT PREGNODEA RegNode, IN BOOL ReadData ) { LONG rc; DWORD valueNameLength; if (RegNode->ValueIndex == 0) { SetLastError (ERROR_SUCCESS); return FALSE; } RegNode->ValueIndex--; valueNameLength = RegNode->ValueLengthMax; if (ReadData) { RegNode->ValueDataSize = RegNode->ValueDataSizeMax; } rc = RegEnumValueA ( RegNode->KeyHandle, RegNode->ValueIndex, RegNode->ValueName, &valueNameLength, NULL, &RegNode->ValueType, ReadData ? RegNode->ValueData : NULL, ReadData ? &RegNode->ValueDataSize : NULL ); if (rc != ERROR_SUCCESS) { SetLastError (rc == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : (DWORD)rc); return FALSE; } RegNode->Flags &= ~RNF_VALUENAME_INVALID; if (ReadData) { RegNode->Flags &= ~RNF_VALUEDATA_INVALID; } return TRUE; } BOOL pEnumNextValueW ( IN OUT PREGNODEW RegNode, IN BOOL ReadData ) { LONG rc; DWORD valueNameLength; if (RegNode->ValueIndex == 0) { SetLastError (ERROR_SUCCESS); return FALSE; } RegNode->ValueIndex--; valueNameLength = RegNode->ValueLengthMax; if (ReadData) { RegNode->ValueDataSize = RegNode->ValueDataSizeMax; } rc = RegEnumValueW ( RegNode->KeyHandle, RegNode->ValueIndex, RegNode->ValueName, &valueNameLength, NULL, &RegNode->ValueType, ReadData ? RegNode->ValueData : NULL, ReadData ? &RegNode->ValueDataSize : NULL ); if (rc != ERROR_SUCCESS) { SetLastError (rc == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : (DWORD)rc); return FALSE; } RegNode->Flags &= ~RNF_VALUENAME_INVALID; if (ReadData) { RegNode->Flags &= ~RNF_VALUEDATA_INVALID; } return TRUE; } /*++ Routine Description: pEnumFirstValue enumerates the first value that matches caller's conditions Arguments: RegNode - Specifies the node and the current context; receives updated info ReadData - Specifies if the data associated with this value should be read Return Value: TRUE if a first value was found; FALSE if not --*/ BOOL pEnumFirstValueA ( IN OUT PREGNODEA RegNode, IN BOOL ReadData ) { RegNode->ValueIndex = RegNode->ValueCount; return pEnumNextValueA (RegNode, ReadData); } BOOL pEnumFirstValueW ( OUT PREGNODEW RegNode, IN BOOL ReadData ) { RegNode->ValueIndex = RegNode->ValueCount; return pEnumNextValueW (RegNode, ReadData); } /*++ Routine Description: pEnumNextSubKey enumerates the next subkey that matches caller's conditions Arguments: RegNode - Specifies the node and the current context; receives updated info Return Value: TRUE if a new subkey was found; FALSE if not --*/ BOOL pEnumNextSubKeyA ( IN OUT PREGNODEA RegNode ) { LONG rc; RegNode->SubKeyIndex++; do { rc = RegEnumKeyA ( RegNode->KeyHandle, RegNode->SubKeyIndex - 1, RegNode->SubKeyName, RegNode->SubKeyLengthMax ); if (rc == ERROR_NO_MORE_ITEMS) { SetLastError (ERROR_SUCCESS); return FALSE; } if (rc == ERROR_MORE_DATA) { // // double the current buffer size // MYASSERT (RegNode->SubKeyName); pFreeMemory (RegNode->SubKeyName); RegNode->SubKeyLengthMax *= 2; RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (MBCHAR)); } } while (rc == ERROR_MORE_DATA); return rc == ERROR_SUCCESS; } BOOL pEnumNextSubKeyW ( IN OUT PREGNODEW RegNode ) { LONG rc; RegNode->SubKeyIndex++; do { rc = RegEnumKeyW ( RegNode->KeyHandle, RegNode->SubKeyIndex - 1, RegNode->SubKeyName, RegNode->SubKeyLengthMax ); if (rc == ERROR_NO_MORE_ITEMS) { SetLastError (ERROR_SUCCESS); return FALSE; } if (rc == ERROR_MORE_DATA) { // // double the current buffer size // MYASSERT (RegNode->SubKeyName); pFreeMemory (RegNode->SubKeyName); RegNode->SubKeyLengthMax *= 2; RegNode->SubKeyName = pAllocateMemory (RegNode->SubKeyLengthMax * DWSIZEOF (WCHAR)); } } while (rc == ERROR_MORE_DATA); return rc == ERROR_SUCCESS; } /*++ Routine Description: pEnumFirstSubKey enumerates the first subkey that matches caller's conditions Arguments: RegNode - Specifies the node and the current context; receives updated info Return Value: TRUE if a first subkey was found; FALSE if not --*/ BOOL pEnumFirstSubKeyA ( IN OUT PREGNODEA RegNode ) { RegNode->SubKeyIndex = 0; return pEnumNextSubKeyA (RegNode); } BOOL pEnumFirstSubKeyW ( OUT PREGNODEW RegNode ) { RegNode->SubKeyIndex = 0; return pEnumNextSubKeyW (RegNode); } /*++ Routine Description: pEnumNextRegObjectInTree is a private function that enumerates the next node matching the specified criteria; it's implemented as a state machine that travels the keys/values as specified the the caller; it doesn't check if they actually match the patterns Arguments: RegEnum - Specifies the current enum context; receives updated info CurrentKeyNode - Receives the key node that is currently processed, if success is returned Return Value: TRUE if a next match was found; FALSE if no more keys/values match --*/ BOOL pEnumNextRegObjectInTreeA ( IN OUT PREGTREE_ENUMA RegEnum, OUT PREGNODEA* CurrentKeyNode ) { PREGNODEA currentNode; PREGNODEA newNode; PCSTR valueName; BOOL ignore; LONG rc; while ((currentNode = pGetCurrentRegNodeA (RegEnum, FALSE)) != NULL) { *CurrentKeyNode = currentNode; switch (currentNode->EnumState) { case RNS_VALUE_FIRST: if (RegEnum->ControlFlags & RECF_SKIPVALUES) { RegEnum->ControlFlags &= ~RECF_SKIPVALUES; currentNode->EnumState = RNS_VALUE_DONE; break; } if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTLEAF) { BOOL readData = RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA; valueName = RegEnum->RegEnumInfo.RegPattern->Leaf; MYASSERT (valueName); currentNode->EnumState = RNS_VALUE_DONE; currentNode->ValueDataSize = currentNode->ValueDataSizeMax; rc = RegQueryValueExA ( currentNode->KeyHandle, valueName, NULL, ¤tNode->ValueType, readData ? currentNode->ValueData : NULL, readData ? ¤tNode->ValueDataSize : NULL ); if (rc == ERROR_SUCCESS) { if (SizeOfStringA (valueName) <= currentNode->ValueLengthMax * DWSIZEOF (MBCHAR) ) { StringCopyA (currentNode->ValueName, valueName); currentNode->Flags &= ~RNF_VALUENAME_INVALID; if (readData) { currentNode->Flags &= ~RNF_VALUEDATA_INVALID; } return TRUE; } } } else { if (pEnumFirstValueA (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { currentNode->EnumState = RNS_VALUE_NEXT; return TRUE; } currentNode->EnumState = RNS_VALUE_DONE; } break; case RNS_VALUE_NEXT: if (RegEnum->ControlFlags & RECF_SKIPVALUES) { RegEnum->ControlFlags &= ~RECF_SKIPVALUES; currentNode->EnumState = RNS_VALUE_DONE; break; } if (pEnumNextValueA (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { return TRUE; } // // no more values for this one, go to the next // currentNode->EnumState = RNS_VALUE_DONE; // // fall through // case RNS_VALUE_DONE: if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) || !currentNode->SubKeyCount) { // // done with this node // currentNode->EnumState = RNS_ENUM_DONE; break; } // // now enum subkeys // currentNode->EnumState = RNS_SUBKEY_FIRST; // // fall through // case RNS_SUBKEY_FIRST: if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) { RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS; currentNode->EnumState = RNS_SUBKEY_DONE; break; } // // check new node's level; if too large, quit // if (currentNode->SubLevel >= RegEnum->RegEnumInfo.MaxSubLevel) { currentNode->EnumState = RNS_SUBKEY_DONE; break; } if (!pEnumFirstSubKeyA (currentNode)) { currentNode->EnumState = RNS_SUBKEY_DONE; break; } currentNode->EnumState = RNS_SUBKEY_NEXT; newNode = pCreateRegNodeA (RegEnum, NULL, ¤tNode, &ignore); if (newNode) { // // now look at the new node // if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { newNode->Flags &= ~RNF_RETURN_KEYS; *CurrentKeyNode = newNode; return TRUE; } } break; } if (!ignore) { // // abort enum // DEBUGMSGA (( DBG_ERROR, "Error encountered enumerating registry; aborting enumeration" )); RegEnum->RootState = RES_ROOT_DONE; return FALSE; } // // fall through // case RNS_SUBKEY_NEXT: if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) { RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS; currentNode->EnumState = RNS_SUBKEY_DONE; break; } if (pEnumNextSubKeyA (currentNode)) { newNode = pCreateRegNodeA (RegEnum, NULL, ¤tNode, &ignore); if (newNode) { // // look at the new node first // if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { newNode->Flags &= ~RNF_RETURN_KEYS; *CurrentKeyNode = newNode; return TRUE; } } break; } if (!ignore) { // // abort enum // DEBUGMSGA (( DBG_ERROR, "Error encountered enumerating registry; aborting enumeration" )); RegEnum->RootState = RES_ROOT_DONE; return FALSE; } // // continue with next subkey // break; } // // this node is done // currentNode->EnumState = RNS_SUBKEY_DONE; // // fall through // case RNS_SUBKEY_DONE: if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // now enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } // // done with this node // currentNode->EnumState = RNS_ENUM_DONE; // // fall through // case RNS_ENUM_DONE: if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (!(RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST)) { if (currentNode->Flags & RNF_RETURN_KEYS) { currentNode->Flags &= ~RNF_RETURN_KEYS; // // set additional data before returning // if (currentNode->ValueName) { pFreeMemory (currentNode->ValueName); currentNode->ValueName = NULL; currentNode->Flags |= RNF_VALUENAME_INVALID; } return TRUE; } } } pDeleteRegNodeA (RegEnum, FALSE); break; case RNS_ENUM_INIT: if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { if (currentNode->Flags & RNF_RETURN_KEYS) { currentNode->Flags &= ~RNF_RETURN_KEYS; return TRUE; } } } if (RegEnum->ControlFlags & RECF_SKIPKEY) { RegEnum->ControlFlags &= ~RECF_SKIPKEY; currentNode->EnumState = RNS_ENUM_DONE; break; } if ((RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } if (currentNode->SubKeyCount) { // // enum keys // if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTNODE) { currentNode->EnumState = RNS_SUBKEY_DONE; } else { currentNode->EnumState = RNS_SUBKEY_FIRST; } break; } if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } currentNode->EnumState = RNS_ENUM_DONE; break; default: MYASSERT (FALSE); //lint !e506 } } return FALSE; } BOOL pEnumNextRegObjectInTreeW ( IN OUT PREGTREE_ENUMW RegEnum, OUT PREGNODEW* CurrentKeyNode ) { PREGNODEW currentNode; PREGNODEW newNode; PCWSTR valueName; BOOL ignore; LONG rc; while ((currentNode = pGetCurrentRegNodeW (RegEnum, FALSE)) != NULL) { *CurrentKeyNode = currentNode; switch (currentNode->EnumState) { case RNS_VALUE_FIRST: if (RegEnum->ControlFlags & RECF_SKIPVALUES) { RegEnum->ControlFlags &= ~RECF_SKIPVALUES; currentNode->EnumState = RNS_VALUE_DONE; break; } if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTLEAF) { BOOL readData = RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA; valueName = RegEnum->RegEnumInfo.RegPattern->Leaf; MYASSERT (valueName); currentNode->EnumState = RNS_VALUE_DONE; currentNode->ValueDataSize = currentNode->ValueDataSizeMax; rc = RegQueryValueExW ( currentNode->KeyHandle, valueName, NULL, ¤tNode->ValueType, readData ? currentNode->ValueData : NULL, readData ? ¤tNode->ValueDataSize : NULL ); if (rc == ERROR_SUCCESS) { if (SizeOfStringW (valueName) <= currentNode->ValueLengthMax * DWSIZEOF (WCHAR) ) { StringCopyW (currentNode->ValueName, valueName); currentNode->Flags &= ~RNF_VALUENAME_INVALID; if (readData) { currentNode->Flags &= ~RNF_VALUEDATA_INVALID; } return TRUE; } } } else { if (pEnumFirstValueW (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { currentNode->EnumState = RNS_VALUE_NEXT; return TRUE; } currentNode->EnumState = RNS_VALUE_DONE; } break; case RNS_VALUE_NEXT: if (RegEnum->ControlFlags & RECF_SKIPVALUES) { RegEnum->ControlFlags &= ~RECF_SKIPVALUES; currentNode->EnumState = RNS_VALUE_DONE; break; } if (pEnumNextValueW (currentNode, RegEnum->RegEnumInfo.Flags & REIF_READ_VALUE_DATA)) { return TRUE; } // // no more values for this one, go to the next // currentNode->EnumState = RNS_VALUE_DONE; // // fall through // case RNS_VALUE_DONE: if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) || !currentNode->SubKeyCount) { // // done with this node // currentNode->EnumState = RNS_ENUM_DONE; break; } // // now enum subkeys // currentNode->EnumState = RNS_SUBKEY_FIRST; // // fall through // case RNS_SUBKEY_FIRST: if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) { RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS; currentNode->EnumState = RNS_SUBKEY_DONE; break; } // // check new node's level; if too large, quit // if (currentNode->SubLevel >= RegEnum->RegEnumInfo.MaxSubLevel) { currentNode->EnumState = RNS_SUBKEY_DONE; break; } if (!pEnumFirstSubKeyW (currentNode)) { currentNode->EnumState = RNS_SUBKEY_DONE; break; } currentNode->EnumState = RNS_SUBKEY_NEXT; newNode = pCreateRegNodeW (RegEnum, NULL, ¤tNode, &ignore); if (newNode) { // // now look at the new node // if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { newNode->Flags &= ~RNF_RETURN_KEYS; *CurrentKeyNode = newNode; return TRUE; } } break; } if (!ignore) { // // abort enum // DEBUGMSGW (( DBG_ERROR, "Error encountered enumerating registry; aborting enumeration" )); RegEnum->RootState = RES_ROOT_DONE; return FALSE; } // // fall through // case RNS_SUBKEY_NEXT: if (RegEnum->ControlFlags & RECF_SKIPSUBKEYS) { RegEnum->ControlFlags &= ~RECF_SKIPSUBKEYS; currentNode->EnumState = RNS_SUBKEY_DONE; break; } if (pEnumNextSubKeyW (currentNode)) { newNode = pCreateRegNodeW (RegEnum, NULL, ¤tNode, &ignore); if (newNode) { // // look at the new node first // if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { newNode->Flags &= ~RNF_RETURN_KEYS; *CurrentKeyNode = newNode; return TRUE; } } break; } if (!ignore) { // // abort enum // DEBUGMSGW (( DBG_ERROR, "Error encountered enumerating registry; aborting enumeration" )); RegEnum->RootState = RES_ROOT_DONE; return FALSE; } // // continue with next subkey // break; } // // this node is done // currentNode->EnumState = RNS_SUBKEY_DONE; // // fall through // case RNS_SUBKEY_DONE: if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // now enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } // // done with this node // currentNode->EnumState = RNS_ENUM_DONE; // // fall through // case RNS_ENUM_DONE: if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (!(RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST)) { if (currentNode->Flags & RNF_RETURN_KEYS) { currentNode->Flags &= ~RNF_RETURN_KEYS; // // set additional data before returning // if (currentNode->ValueName) { pFreeMemory (currentNode->ValueName); currentNode->ValueName = NULL; currentNode->Flags |= RNF_VALUENAME_INVALID; } return TRUE; } } } pDeleteRegNodeW (RegEnum, FALSE); break; case RNS_ENUM_INIT: if (RegEnum->RegEnumInfo.Flags & REIF_RETURN_KEYS) { if (RegEnum->RegEnumInfo.Flags & REIF_CONTAINERS_FIRST) { if (currentNode->Flags & RNF_RETURN_KEYS) { currentNode->Flags &= ~RNF_RETURN_KEYS; return TRUE; } } } if (RegEnum->ControlFlags & RECF_SKIPKEY) { RegEnum->ControlFlags &= ~RECF_SKIPKEY; currentNode->EnumState = RNS_ENUM_DONE; break; } if ((RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } if (currentNode->SubKeyCount) { // // enum keys // if (RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_EXACTNODE) { currentNode->EnumState = RNS_SUBKEY_DONE; } else { currentNode->EnumState = RNS_SUBKEY_FIRST; } break; } if (!(RegEnum->RegEnumInfo.Flags & REIF_VALUES_FIRST) && currentNode->ValueCount) { // // enum values // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & OBSPF_NOLEAF)) { currentNode->EnumState = RNS_VALUE_FIRST; break; } } currentNode->EnumState = RNS_ENUM_DONE; break; default: MYASSERT (FALSE); //lint !e506 } } return FALSE; } /*++ Routine Description: EnumFirstRegObjectInTreeEx enumerates registry keys, and optionally values, that match the specified criteria Arguments: RegEnum - Receives the enum context info; this will be used in subsequent calls to EnumNextRegObjectInTree EncodedRegPattern - Specifies the encoded key pattern (encoded as defined by the ParsedPattern functions) EncodedValuePattern - Specifies the encoded value pattern (encoded as defined by the ParsedPattern functions); optional; NULL means no values should be returned (only look for keys) EnumKeyNames - Specifies TRUE if key names should be returned during the enumeration (if they match the pattern); a key name is returned before any of its subkeys or values ContainersFirst - Specifies TRUE if keys should be returned before any of its values or subkeys; used only if EnumKeyNames is TRUE ValuesFirst - Specifies TRUE if a key's values should be returned before key's subkeys; this parameter decides the enum order between values and subkeys for each key DepthFirst - Specifies TRUE if the current subkey of any key should be fully enumerated before going to the next subkey; this parameter decides if the tree traversal is depth-first (TRUE) or width-first (FALSE) MaxSubLevel - Specifies the maximum sub-level of a key that is to be enumerated, relative to the root; if 0, only the root is enumerated; if -1, all sub-levels are enumerated UseExclusions - Specifies TRUE if exclusion APIs should be used to determine if certain keys/values are excluded from enumeration; this slows down the speed ReadValueData - Specifies TRUE if data associated with values should also be returned CallbackOnError - Specifies a pointer to a callback function that will be called during enumeration if an error occurs; if the callback is defined and it returns FALSE, the enumeration is aborted, otherwise it will continue ignoring the error Return Value: TRUE if a first match is found. FALSE otherwise. --*/ BOOL EnumFirstRegObjectInTreeExA ( OUT PREGTREE_ENUMA RegEnum, IN PCSTR EncodedRegPattern, IN BOOL EnumKeyNames, IN BOOL ContainersFirst, IN BOOL ValuesFirst, IN BOOL DepthFirst, IN DWORD MaxSubLevel, IN BOOL UseExclusions, IN BOOL ReadValueData, IN RPE_ERROR_CALLBACKA CallbackOnError OPTIONAL ) { MYASSERT (RegEnum && EncodedRegPattern && *EncodedRegPattern); ZeroMemory (RegEnum, DWSIZEOF (REGTREE_ENUMA)); //lint !e613 !e668 // // first try to get reg enum info in internal format // if (!pGetRegEnumInfoA ( &RegEnum->RegEnumInfo, EncodedRegPattern, EnumKeyNames, ContainersFirst, ValuesFirst, DepthFirst, MaxSubLevel, UseExclusions, ReadValueData )) { //lint !e613 AbortRegObjectInTreeEnumA (RegEnum); return FALSE; } if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { //lint !e613 // // next check if the starting key is in an excluded tree // if (ElIsObsPatternExcludedA (ELT_REGISTRY, RegEnum->RegEnumInfo.RegPattern)) { //lint !e613 DEBUGMSGA (( DBG_REGENUM, "EnumFirstRegObjectInTreeExA: Root is excluded: %s", EncodedRegPattern )); AbortRegObjectInTreeEnumA (RegEnum); return FALSE; } } if (!pEnumFirstRegRootA (RegEnum)) { AbortRegObjectInTreeEnumA (RegEnum); return FALSE; } /*lint -e(613)*/RegEnum->RegEnumInfo.CallbackOnError = CallbackOnError; return EnumNextRegObjectInTreeA (RegEnum); } BOOL EnumFirstRegObjectInTreeExW ( OUT PREGTREE_ENUMW RegEnum, IN PCWSTR EncodedRegPattern, IN BOOL EnumKeyNames, IN BOOL ContainersFirst, IN BOOL ValuesFirst, IN BOOL DepthFirst, IN DWORD MaxSubLevel, IN BOOL UseExclusions, IN BOOL ReadValueData, IN RPE_ERROR_CALLBACKW CallbackOnError OPTIONAL ) { MYASSERT (RegEnum && EncodedRegPattern && *EncodedRegPattern); ZeroMemory (RegEnum, DWSIZEOF (REGTREE_ENUMW)); //lint !e613 !e668 // // first try to get reg enum info in internal format // if (!pGetRegEnumInfoW ( &RegEnum->RegEnumInfo, EncodedRegPattern, EnumKeyNames, ContainersFirst, ValuesFirst, DepthFirst, MaxSubLevel, UseExclusions, ReadValueData )) { //lint !e613 AbortRegObjectInTreeEnumW (RegEnum); return FALSE; } if (/*lint -e(613)*/RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { // // next check if the starting key is in an excluded tree // if (ElIsObsPatternExcludedW (ELT_REGISTRY, /*lint -e(613)*/RegEnum->RegEnumInfo.RegPattern)) { DEBUGMSGW (( DBG_REGENUM, "EnumFirstRegObjectInTreeExW: Root is excluded: %s", EncodedRegPattern )); AbortRegObjectInTreeEnumW (RegEnum); return FALSE; } } if (!pEnumFirstRegRootW (RegEnum)) { AbortRegObjectInTreeEnumW (RegEnum); return FALSE; } /*lint -e(613)*/RegEnum->RegEnumInfo.CallbackOnError = CallbackOnError; return EnumNextRegObjectInTreeW (RegEnum); } /*++ Routine Description: EnumNextRegObjectInTree enumerates the next node matching the criteria specified in RegEnum; this is filled on the call to EnumFirstRegObjectInTreeEx; Arguments: RegEnum - Specifies the current enum context; receives updated info Return Value: TRUE if a next match was found; FALSE if no more keys/values match --*/ BOOL EnumNextRegObjectInTreeA ( IN OUT PREGTREE_ENUMA RegEnum ) { PREGNODEA currentNode; BOOL success; MYASSERT (RegEnum); do { if (RegEnum->EncodedFullName) { ObsFreeA (RegEnum->EncodedFullName); RegEnum->EncodedFullName = NULL; } while (TRUE) { if (RegEnum->LastWackPtr) { *RegEnum->LastWackPtr = '\\'; RegEnum->LastWackPtr = NULL; } if (!pEnumNextRegObjectInTreeA (RegEnum, ¤tNode)) { break; } MYASSERT (currentNode && currentNode->KeyName); // // check if this object matches the pattern // if (!(currentNode->Flags & RNF_KEYNAME_MATCHES)) { //lint !e613 continue; } RegEnum->CurrentKeyHandle = /*lint -e(613)*/currentNode->KeyHandle; RegEnum->CurrentLevel = RegEnum->RegEnumInfo.RootLevel + /*lint -e(613)*/currentNode->SubLevel; if ((!currentNode->ValueName) || (currentNode->Flags & RNF_VALUENAME_INVALID)) { RegEnum->Location = /*lint -e(613)*/currentNode->KeyName; RegEnum->LastWackPtr = _mbsrchr (RegEnum->Location, '\\'); if (!RegEnum->LastWackPtr) { RegEnum->Name = RegEnum->Location; } else { RegEnum->Name = _mbsinc (RegEnum->LastWackPtr); if (!RegEnum->Name) { RegEnum->Name = RegEnum->Location; } } RegEnum->CurrentValueData = NULL; RegEnum->CurrentValueDataSize = 0; RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType; RegEnum->Attributes = REG_ATTRIBUTE_KEY; // // prepare full path buffer // StringCopyA (RegEnum->NativeFullName, RegEnum->Location); RegEnum->LastNode = currentNode; RegEnum->RegNameAppendPos = NULL; if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { if (ElIsExcluded2A (ELT_REGISTRY, RegEnum->Location, NULL)) { DEBUGMSGA (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s was found, but it's excluded", RegEnum->Location )); continue; } } RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExA ( RegEnum->Location, NULL, TRUE ); } else { RegEnum->Location = /*lint -e(613)*/currentNode->KeyName; RegEnum->Name = /*lint -e(613)*/currentNode->ValueName; RegEnum->CurrentValueData = /*lint -e(613)*/currentNode->ValueData; RegEnum->CurrentValueDataSize = currentNode->ValueDataSize; RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType; if (RegEnum->LastNode != currentNode) { RegEnum->LastNode = currentNode; // // prepare full path buffer // RegEnum->NativeFullName[0] = 0; RegEnum->RegNameAppendPos = StringCatA (RegEnum->NativeFullName, RegEnum->Location); RegEnum->RegNameAppendPos = StringCatA (RegEnum->RegNameAppendPos, "\\["); } else if (!RegEnum->RegNameAppendPos) { RegEnum->RegNameAppendPos = GetEndOfStringA (RegEnum->NativeFullName); RegEnum->RegNameAppendPos = StringCatA (RegEnum->RegNameAppendPos, "\\["); } MYASSERT (RegEnum->Name); if ((RegEnum->RegNameAppendPos + SizeOfStringA (RegEnum->Name) / DWSIZEOF(CHAR))> (RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(CHAR))) { DEBUGMSGA (( DBG_ERROR, "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's path is too long", RegEnum->Location, RegEnum->Name )); continue; } StringCopyA (RegEnum->RegNameAppendPos, RegEnum->Name); StringCatA (RegEnum->RegNameAppendPos, "]"); RegEnum->Attributes = REG_ATTRIBUTE_VALUE; // // now test if the value matches // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTLEAF | OBSPF_OPTIONALLEAF)) && !TestParsedPatternA ( RegEnum->RegEnumInfo.RegPattern->LeafPattern, RegEnum->Name ) ) { continue; } if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { // // check if this object is excluded // if (RegEnum->Name && ElIsExcluded2A (ELT_REGISTRY, NULL, RegEnum->Name)) { DEBUGMSGA (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded by value name", RegEnum->Location, RegEnum->Name )); continue; } if (ElIsExcluded2A (ELT_REGISTRY, RegEnum->Location, RegEnum->Name)) { DEBUGMSGA (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded", RegEnum->Location, RegEnum->Name )); continue; } } RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExA ( RegEnum->Location, RegEnum->Name, TRUE ); } if (RegEnum->LastWackPtr) { *RegEnum->LastWackPtr = 0; } return TRUE; } // // try the next root // if (RegEnum->RootState == RES_ROOT_DONE) { break; } MYASSERT (RegEnum->RootState == RES_ROOT_NEXT); MYASSERT (RegEnum->RootEnum); success = pEnumNextRegRootA (RegEnum); } while (success); AbortRegObjectInTreeEnumA (RegEnum); return FALSE; } BOOL EnumNextRegObjectInTreeW ( IN OUT PREGTREE_ENUMW RegEnum ) { PREGNODEW currentNode; BOOL success; MYASSERT (RegEnum); do { if (RegEnum->EncodedFullName) { ObsFreeW (RegEnum->EncodedFullName); RegEnum->EncodedFullName = NULL; } while (TRUE) { if (RegEnum->LastWackPtr) { *RegEnum->LastWackPtr = L'\\'; RegEnum->LastWackPtr = NULL; } if (!pEnumNextRegObjectInTreeW (RegEnum, ¤tNode)) { break; } MYASSERT (currentNode && currentNode->KeyName); // // check if this object matches the pattern // if (!(currentNode->Flags & RNF_KEYNAME_MATCHES)) { //lint !e613 continue; } RegEnum->CurrentKeyHandle = /*lint -e(613)*/currentNode->KeyHandle; RegEnum->CurrentLevel = RegEnum->RegEnumInfo.RootLevel + /*lint -e(613)*/currentNode->SubLevel; if ((!currentNode->ValueName) || (currentNode->Flags & RNF_VALUENAME_INVALID)) { RegEnum->Location = /*lint -e(613)*/currentNode->KeyName; RegEnum->LastWackPtr = wcsrchr (RegEnum->Location, L'\\'); if (!RegEnum->LastWackPtr) { RegEnum->Name = RegEnum->Location; } else { RegEnum->Name = RegEnum->LastWackPtr + 1; if (!RegEnum->Name) { RegEnum->Name = RegEnum->Location; } } RegEnum->CurrentValueData = NULL; RegEnum->CurrentValueDataSize = 0; RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType; RegEnum->Attributes = REG_ATTRIBUTE_KEY; // // prepare full path buffer // StringCopyW (RegEnum->NativeFullName, RegEnum->Location); RegEnum->LastNode = currentNode; RegEnum->RegNameAppendPos = NULL; if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { if (ElIsExcluded2W (ELT_REGISTRY, RegEnum->Location, NULL)) { DEBUGMSGW (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s was found, but it's excluded", RegEnum->Location )); continue; } } RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExW ( RegEnum->Location, NULL, TRUE ); } else { RegEnum->Location = /*lint -e(613)*/currentNode->KeyName; RegEnum->Name = /*lint -e(613)*/currentNode->ValueName; RegEnum->CurrentValueData = /*lint -e(613)*/currentNode->ValueData; RegEnum->CurrentValueDataSize = currentNode->ValueDataSize; RegEnum->CurrentValueType = /*lint -e(613)*/currentNode->ValueType; if (RegEnum->LastNode != currentNode) { RegEnum->LastNode = currentNode; // // prepare full path buffer // RegEnum->NativeFullName[0] = 0; RegEnum->RegNameAppendPos = StringCatW (RegEnum->NativeFullName, RegEnum->Location); RegEnum->RegNameAppendPos = StringCatW (RegEnum->RegNameAppendPos, L"\\["); } else if (!RegEnum->RegNameAppendPos) { RegEnum->RegNameAppendPos = GetEndOfStringW (RegEnum->NativeFullName); RegEnum->RegNameAppendPos = StringCatW (RegEnum->RegNameAppendPos, L"\\["); } MYASSERT (RegEnum->Name); { UINT size1 = 0; UINT size2 = 0; INT size3 = 0; size1 = (UINT)(RegEnum->RegNameAppendPos + SizeOfStringW (RegEnum->Name) / DWSIZEOF(WCHAR)); size2 = (UINT)(RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(WCHAR)); size3 = size2 - size1; } if ((RegEnum->RegNameAppendPos + SizeOfStringW (RegEnum->Name) / DWSIZEOF(WCHAR))> (RegEnum->NativeFullName + DWSIZEOF (RegEnum->NativeFullName) / DWSIZEOF(WCHAR))) { DEBUGMSGW (( DBG_ERROR, "EnumNextRegObjectInTreeW: RegKey %s [%s] was found, but it's path is too long", RegEnum->Location, RegEnum->Name )); continue; } StringCopyW (RegEnum->RegNameAppendPos, RegEnum->Name); StringCatW (RegEnum->RegNameAppendPos, L"]"); RegEnum->Attributes = REG_ATTRIBUTE_VALUE; // // now test if the value matches // if (!(RegEnum->RegEnumInfo.RegPattern->Flags & (OBSPF_EXACTLEAF | OBSPF_OPTIONALLEAF)) && !TestParsedPatternW ( RegEnum->RegEnumInfo.RegPattern->LeafPattern, RegEnum->Name ) ) { continue; } if (RegEnum->RegEnumInfo.Flags & REIF_USE_EXCLUSIONS) { // // check if this object is excluded // if (RegEnum->Name && ElIsExcluded2W (ELT_REGISTRY, NULL, RegEnum->Name)) { DEBUGMSGW (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded by value name", RegEnum->Location, RegEnum->Name )); continue; } if (ElIsExcluded2W (ELT_REGISTRY, RegEnum->Location, RegEnum->Name)) { DEBUGMSGW (( DBG_REGENUM, "EnumNextRegObjectInTreeA: RegKey %s [%s] was found, but it's excluded", RegEnum->Location, RegEnum->Name )); continue; } } RegEnum->EncodedFullName = ObsBuildEncodedObjectStringExW ( RegEnum->Location, RegEnum->Name, TRUE ); } if (RegEnum->LastWackPtr) { *RegEnum->LastWackPtr = 0; } return TRUE; } // // try the next root // if (RegEnum->RootState == RES_ROOT_DONE) { break; } MYASSERT (RegEnum->RootState == RES_ROOT_NEXT); MYASSERT (RegEnum->RootEnum); success = pEnumNextRegRootW (RegEnum); } while (success); AbortRegObjectInTreeEnumW (RegEnum); return FALSE; } /*++ Routine Description: AbortRegObjectInTreeEnum aborts the enumeration, freeing all resources allocated Arguments: RegEnum - Specifies the current enum context; receives a "clean" context Return Value: none --*/ VOID AbortRegObjectInTreeEnumA ( IN OUT PREGTREE_ENUMA RegEnum ) { while (pDeleteRegNodeA (RegEnum, TRUE)) { } GbFree (&RegEnum->RegNodes); if (RegEnum->EncodedFullName) { ObsFreeA (RegEnum->EncodedFullName); RegEnum->EncodedFullName = NULL; } if (RegEnum->RegEnumInfo.RegPattern) { ObsDestroyParsedPatternA (RegEnum->RegEnumInfo.RegPattern); RegEnum->RegEnumInfo.RegPattern = NULL; } if (RegEnum->RootEnum) { pFreeMemory (RegEnum->RootEnum); RegEnum->RootEnum = NULL; } } VOID AbortRegObjectInTreeEnumW ( IN OUT PREGTREE_ENUMW RegEnum ) { while (pDeleteRegNodeW (RegEnum, TRUE)) { } GbFree (&RegEnum->RegNodes); if (RegEnum->EncodedFullName) { ObsFreeW (RegEnum->EncodedFullName); RegEnum->EncodedFullName = NULL; } if (RegEnum->RegEnumInfo.RegPattern) { ObsDestroyParsedPatternW (RegEnum->RegEnumInfo.RegPattern); RegEnum->RegEnumInfo.RegPattern = NULL; } if (RegEnum->RootEnum) { pFreeMemory (RegEnum->RootEnum); RegEnum->RootEnum = NULL; } }