2797 lines
78 KiB
C
2797 lines
78 KiB
C
/*++
|
|
|
|
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:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#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;
|
|
}
|
|
}
|