You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1555 lines
33 KiB
1555 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regutils.c
|
|
|
|
Abstract:
|
|
|
|
Implements wrappers similar to migutil's reg.c, but for Win95 registry.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 30-Jan-1998
|
|
|
|
Revisions:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "win95regp.h"
|
|
|
|
#ifdef DEBUG
|
|
#undef Win95RegCloseKey
|
|
#endif
|
|
|
|
#define DBG_REGUTILS "RegUtils"
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
BOOL
|
|
pPopRegKeyInfo95A (
|
|
IN PREGTREE_ENUMA EnumPtr
|
|
);
|
|
|
|
BOOL
|
|
pPopRegKeyInfo95W (
|
|
IN PREGTREE_ENUMW EnumPtr
|
|
);
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstRegKey95A and EnumFirstRegKey95W begin an enumeration of registry
|
|
subkeys. They initialize the registy enumeration structure and
|
|
call the registry APIs to enumerate subkeys of the specified key handle.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Receives the updated state of enumeration. The structure
|
|
can be accessed directly.
|
|
|
|
Key - Specifies the handle of the registry key to enumerate.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, or FALSE if an error or if no more subkeys are available.
|
|
Call GetLastError for the failure code.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumFirstRegKey95A (
|
|
OUT PREGKEY_ENUMA EnumPtr,
|
|
IN HKEY hKey
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMA));
|
|
EnumPtr->KeyHandle = hKey;
|
|
|
|
return EnumNextRegKey95A (EnumPtr);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumFirstRegKey95W (
|
|
OUT PREGKEY_ENUMW EnumPtr,
|
|
IN HKEY hKey
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMW));
|
|
EnumPtr->KeyHandle = hKey;
|
|
|
|
return EnumNextRegKey95W (EnumPtr);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
OpenRegKeyStr95A and OpenRegKeyStr95W parse a text string that specifies a
|
|
registry key into the hive and subkey, and then they open the subkey
|
|
and return the handle.
|
|
|
|
Arguments:
|
|
|
|
RegKey - Specifies the complete path to the registry subkey, including
|
|
the hive.
|
|
|
|
Return Value:
|
|
|
|
A non-NULL registry handle if successful, or NULL if either the subkey
|
|
could not be opened or the string is malformed.
|
|
|
|
--*/
|
|
|
|
HKEY
|
|
RealOpenRegKeyStr95A (
|
|
IN PCSTR RegKey
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
DWORD End;
|
|
HKEY RootKey;
|
|
HKEY Key;
|
|
|
|
RootKey = ConvertRootStringToKeyA (RegKey, &End);
|
|
if (!RootKey) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!RegKey[End]) {
|
|
OurRegOpenRootKey95A (RootKey, RegKey /* , */ DEBUG_TRACKING_ARGS);
|
|
return RootKey;
|
|
}
|
|
|
|
Key = RealOpenRegKey95A (RootKey, &RegKey[End] /* , */ DEBUG_TRACKING_ARGS);
|
|
return Key;
|
|
}
|
|
|
|
|
|
HKEY
|
|
RealOpenRegKeyStr95W (
|
|
IN PCWSTR RegKey
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
PCSTR AnsiRegKey;
|
|
HKEY Key;
|
|
|
|
AnsiRegKey = ConvertWtoA (RegKey);
|
|
if (!AnsiRegKey) {
|
|
return NULL;
|
|
}
|
|
|
|
Key = RealOpenRegKeyStr95A (AnsiRegKey /* , */ DEBUG_TRACKING_ARGS);
|
|
|
|
FreeConvertedStr (AnsiRegKey);
|
|
|
|
return Key;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstRegKeyStr95A and EnumFirstRegKeyStr95W start an enumeration of
|
|
subkeys within the given key. In these functions, the key is specified
|
|
via a string instead of an HKEY value.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Receives the updated state of enumeration. The structure
|
|
can be accessed directly.
|
|
|
|
RegKey - Specifies the full path of the registry key to enumerate.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, or FALSE if an error or if no more subkeys are available.
|
|
Call GetLastError for the failure code.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
RealEnumFirstRegKeyStr95A (
|
|
OUT PREGKEY_ENUMA EnumPtr,
|
|
IN PCSTR RegKey
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
HKEY Key;
|
|
BOOL b;
|
|
|
|
Key = RealOpenRegKeyStr95A (RegKey /* , */ DEBUG_TRACKING_ARGS);
|
|
|
|
if (!Key) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = EnumFirstRegKey95A (EnumPtr, Key);
|
|
if (!b) {
|
|
CloseRegKey95 (Key);
|
|
} else {
|
|
EnumPtr->OpenedByEnum = TRUE;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealEnumFirstRegKeyStr95W (
|
|
IN PREGKEY_ENUMW EnumPtr,
|
|
IN PCWSTR RegKey
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
HKEY Key;
|
|
BOOL b;
|
|
|
|
Key = RealOpenRegKeyStr95W (RegKey /* , */ DEBUG_TRACKING_ARGS);
|
|
if (!Key) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = EnumFirstRegKey95W (EnumPtr, Key);
|
|
if (!b) {
|
|
CloseRegKey95 (Key);
|
|
} else {
|
|
EnumPtr->OpenedByEnum = TRUE;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
AbortRegKeyEnum95A and AbortRegKeyEnum95W release all resources associated
|
|
with a registry subkey enumeration. Call this function to stop the
|
|
enumeration before it completes by itself.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Specifies the enumeration to stop. Receives the updated
|
|
state of enumeration.
|
|
|
|
Return Value:
|
|
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
AbortRegKeyEnum95A (
|
|
IN OUT PREGKEY_ENUMA EnumPtr
|
|
)
|
|
{
|
|
if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
|
|
CloseRegKey95 (EnumPtr->KeyHandle);
|
|
EnumPtr->KeyHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
AbortRegKeyEnum95W (
|
|
IN OUT PREGKEY_ENUMW EnumPtr
|
|
)
|
|
{
|
|
if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
|
|
CloseRegKey95 (EnumPtr->KeyHandle);
|
|
EnumPtr->KeyHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumNextRegKey95A and EnumNextRegKey95W continue an enumeration started by
|
|
one of the subkey enumeration routines above. If all items have been
|
|
enumerated, this function cleans up all resources and returns FALSE.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Specifies the enumeration to continue. Receives the updated
|
|
state of enumeration. The structure can be accessed directly.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, or FALSE if an error or if no more subkeys are available.
|
|
Call GetLastError for the failure code.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumNextRegKey95A (
|
|
IN OUT PREGKEY_ENUMA EnumPtr
|
|
)
|
|
{
|
|
LONG rc;
|
|
|
|
rc = Win95RegEnumKeyA (
|
|
EnumPtr->KeyHandle,
|
|
EnumPtr->Index,
|
|
EnumPtr->SubKeyName,
|
|
MAX_REGISTRY_KEYA
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
if (EnumPtr->OpenedByEnum) {
|
|
CloseRegKey95 (EnumPtr->KeyHandle);
|
|
EnumPtr->KeyHandle = NULL;
|
|
}
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
} else {
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->Index += 1;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumNextRegKey95W (
|
|
IN OUT PREGKEY_ENUMW EnumPtr
|
|
)
|
|
{
|
|
LONG rc;
|
|
|
|
rc = Win95RegEnumKeyW (
|
|
EnumPtr->KeyHandle,
|
|
EnumPtr->Index,
|
|
EnumPtr->SubKeyName,
|
|
MAX_REGISTRY_KEYW
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
if (EnumPtr->OpenedByEnum) {
|
|
CloseRegKey95 (EnumPtr->KeyHandle);
|
|
EnumPtr->KeyHandle = NULL;
|
|
}
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
} else {
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->Index += 1;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pPushRegKeyInfo95A (
|
|
IN PREGTREE_ENUMA EnumPtr,
|
|
IN PCSTR KeyName
|
|
)
|
|
{
|
|
PREGKEYINFOA RetVal;
|
|
PSTR p;
|
|
|
|
RetVal = (PREGKEYINFOA) PoolMemGetAlignedMemory (
|
|
EnumPtr->EnumPool,
|
|
sizeof (REGKEYINFOA)
|
|
);
|
|
|
|
if (!RetVal) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize struct to zero
|
|
//
|
|
|
|
ZeroMemory (RetVal, sizeof (REGKEYINFOA));
|
|
|
|
//
|
|
// Link parent and child pointers
|
|
//
|
|
|
|
RetVal->Parent = EnumPtr->CurrentKey;
|
|
if (EnumPtr->CurrentKey) {
|
|
EnumPtr->CurrentKey->Child = RetVal;
|
|
}
|
|
EnumPtr->CurrentKey = RetVal;
|
|
|
|
//
|
|
// Prepare full key path by appending the key name to the existing
|
|
// base
|
|
//
|
|
|
|
RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
|
|
|
|
p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
|
|
|
|
if (EnumPtr->FullKeyNameBytes) {
|
|
StringCopyA (p, "\\");
|
|
EnumPtr->FullKeyNameBytes += ByteCountA (p);
|
|
p = _mbsinc (p);
|
|
}
|
|
|
|
_mbssafecpy (p, KeyName, MAX_REGISTRY_KEYA - EnumPtr->FullKeyNameBytes);
|
|
EnumPtr->FullKeyNameBytes += ByteCountA (KeyName);
|
|
|
|
//
|
|
// Save the key name independent of the full registry path.
|
|
// Also open the key.
|
|
//
|
|
|
|
_mbssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYA);
|
|
RetVal->KeyHandle = OpenRegKeyStr95A (EnumPtr->FullKeyName);
|
|
|
|
if (!RetVal->KeyHandle) {
|
|
pPopRegKeyInfo95A (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pPushRegKeyInfo95W (
|
|
IN PREGTREE_ENUMW EnumPtr,
|
|
IN PCWSTR KeyName
|
|
)
|
|
{
|
|
PREGKEYINFOW RetVal;
|
|
PWSTR p;
|
|
|
|
RetVal = (PREGKEYINFOW) PoolMemGetAlignedMemory (
|
|
EnumPtr->EnumPool,
|
|
sizeof (REGKEYINFOW)
|
|
);
|
|
|
|
if (!RetVal) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize struct to zero
|
|
//
|
|
|
|
ZeroMemory (RetVal, sizeof (REGKEYINFOW));
|
|
|
|
//
|
|
// Link parent and child pointers
|
|
//
|
|
|
|
RetVal->Parent = EnumPtr->CurrentKey;
|
|
if (EnumPtr->CurrentKey) {
|
|
EnumPtr->CurrentKey->Child = RetVal;
|
|
}
|
|
EnumPtr->CurrentKey = RetVal;
|
|
|
|
//
|
|
// Prepare full key path by appending the key name to the existing
|
|
// base
|
|
//
|
|
|
|
RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
|
|
|
|
p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
|
|
|
|
if (EnumPtr->FullKeyNameBytes) {
|
|
StringCopyW (p, L"\\");
|
|
EnumPtr->FullKeyNameBytes += ByteCountW (p);
|
|
p++;
|
|
}
|
|
|
|
_wcssafecpy (p, KeyName, MAX_REGISTRY_KEYW - (EnumPtr->FullKeyNameBytes / sizeof (WCHAR)));
|
|
EnumPtr->FullKeyNameBytes += ByteCountW (KeyName);
|
|
|
|
//
|
|
// Save the key name independent of the full registry path.
|
|
// Also open the key.
|
|
//
|
|
|
|
_wcssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYW);
|
|
RetVal->KeyHandle = OpenRegKeyStr95W (EnumPtr->FullKeyName);
|
|
|
|
if (!RetVal->KeyHandle) {
|
|
pPopRegKeyInfo95W (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pPopRegKeyInfo95A (
|
|
IN PREGTREE_ENUMA EnumPtr
|
|
)
|
|
{
|
|
PREGKEYINFOA FreeMe;
|
|
PSTR p;
|
|
|
|
FreeMe = EnumPtr->CurrentKey;
|
|
|
|
//
|
|
// Skip if nothing was ever pushed
|
|
//
|
|
|
|
if (!FreeMe) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Trim the full key string
|
|
//
|
|
|
|
EnumPtr->CurrentKey = FreeMe->Parent;
|
|
EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
|
|
p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
|
|
*p = 0;
|
|
|
|
//
|
|
// Adjust the linkage
|
|
//
|
|
|
|
if (EnumPtr->CurrentKey) {
|
|
EnumPtr->CurrentKey->Child = NULL;
|
|
}
|
|
|
|
//
|
|
// Clean up resources
|
|
//
|
|
|
|
if (FreeMe->KeyHandle) {
|
|
CloseRegKey95 (FreeMe->KeyHandle);
|
|
}
|
|
|
|
AbortRegKeyEnum95A (&FreeMe->KeyEnum);
|
|
PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
|
|
|
|
//
|
|
// Return FALSE if last item was poped
|
|
//
|
|
|
|
return EnumPtr->CurrentKey != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pPopRegKeyInfo95W (
|
|
IN PREGTREE_ENUMW EnumPtr
|
|
)
|
|
{
|
|
PREGKEYINFOW FreeMe;
|
|
PWSTR p;
|
|
|
|
FreeMe = EnumPtr->CurrentKey;
|
|
|
|
//
|
|
// Skip if nothing was ever pushed
|
|
//
|
|
|
|
if (!FreeMe) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Trim the full key string
|
|
//
|
|
|
|
EnumPtr->CurrentKey = FreeMe->Parent;
|
|
EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
|
|
p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
|
|
*p = 0;
|
|
|
|
//
|
|
// Adjust the linkage
|
|
//
|
|
|
|
if (EnumPtr->CurrentKey) {
|
|
EnumPtr->CurrentKey->Child = NULL;
|
|
}
|
|
|
|
//
|
|
// Clean up resources
|
|
//
|
|
|
|
if (FreeMe->KeyHandle) {
|
|
CloseRegKey95 (FreeMe->KeyHandle);
|
|
}
|
|
|
|
AbortRegKeyEnum95W (&FreeMe->KeyEnum);
|
|
PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
|
|
|
|
//
|
|
// Return FALSE if last item was poped
|
|
//
|
|
|
|
return EnumPtr->CurrentKey != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealEnumFirstRegKeyInTree95A (
|
|
OUT PREGTREE_ENUMA EnumPtr,
|
|
IN PCSTR BaseKeyStr
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMA));
|
|
|
|
//
|
|
// Allocate pool for enum structs
|
|
//
|
|
|
|
EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTree95A");
|
|
if (!EnumPtr->EnumPool) {
|
|
return FALSE;
|
|
}
|
|
|
|
PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
|
|
PoolMemDisableTracking (EnumPtr->EnumPool);
|
|
|
|
//
|
|
// Push base key on the enum stack
|
|
//
|
|
|
|
if (!pPushRegKeyInfo95A (EnumPtr, BaseKeyStr)) {
|
|
DEBUGMSG ((DBG_REGUTILS, "EnumFirstRegKeyInTree95A failed to push base key"));
|
|
AbortRegKeyTreeEnum95A (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->EnumBaseBytes = ByteCountA (BaseKeyStr);
|
|
|
|
//
|
|
// Set state so EnumNextRegKeyInTree95 knows what to do
|
|
//
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealEnumFirstRegKeyInTree95W (
|
|
OUT PREGTREE_ENUMW EnumPtr,
|
|
IN PCWSTR BaseKeyStr
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMW));
|
|
|
|
//
|
|
// Allocate pool for enum structs
|
|
//
|
|
|
|
EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTree95W");
|
|
if (!EnumPtr->EnumPool) {
|
|
return FALSE;
|
|
}
|
|
|
|
PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
|
|
PoolMemDisableTracking (EnumPtr->EnumPool);
|
|
|
|
//
|
|
// Push base key on the enum stack
|
|
//
|
|
|
|
if (!pPushRegKeyInfo95W (EnumPtr, BaseKeyStr)) {
|
|
DEBUGMSG ((DBG_REGUTILS, "EnumFirstRegKeyInTree95W failed to push base key"));
|
|
AbortRegKeyTreeEnum95W (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->EnumBaseBytes = ByteCountW (BaseKeyStr);
|
|
|
|
//
|
|
// Set state so EnumNextRegKeyInTree95 knows what to do
|
|
//
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealEnumNextRegKeyInTree95A (
|
|
IN OUT PREGTREE_ENUMA EnumPtr
|
|
)
|
|
{
|
|
if (EnumPtr->State == NO_MORE_ITEMS) {
|
|
return FALSE;
|
|
}
|
|
|
|
while (TRUE) {
|
|
switch (EnumPtr->State) {
|
|
|
|
case ENUMERATE_SUBKEY_BEGIN:
|
|
//
|
|
// Start enumeration
|
|
//
|
|
|
|
if (EnumFirstRegKey95A (
|
|
&EnumPtr->CurrentKey->KeyEnum,
|
|
EnumPtr->CurrentKey->KeyHandle
|
|
)) {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_NEXT:
|
|
//
|
|
// Continue enumerations
|
|
//
|
|
|
|
if (EnumNextRegKey95A (&EnumPtr->CurrentKey->KeyEnum)) {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_DONE:
|
|
//
|
|
// Enumeration of this key is done; pop and continue.
|
|
//
|
|
|
|
if (!pPopRegKeyInfo95A (EnumPtr)) {
|
|
EnumPtr->State = NO_MORE_ITEMS;
|
|
AbortRegKeyTreeEnum95A (EnumPtr);
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_RETURN:
|
|
//
|
|
// Return enumerated item to caller
|
|
//
|
|
|
|
if (!pPushRegKeyInfo95A (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
|
|
DEBUGMSGA ((
|
|
DBG_REGUTILS,
|
|
"EnumFirstRegKeyInTree95A failed to push sub key %s",
|
|
EnumPtr->CurrentKey->KeyEnum.SubKeyName
|
|
));
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
|
|
break;
|
|
}
|
|
|
|
if (!EnumPtr->FirstEnumerated) {
|
|
EnumPtr->FirstEnumerated = TRUE;
|
|
EnumPtr->EnumBaseBytes += sizeof (CHAR);
|
|
}
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
|
|
return TRUE;
|
|
|
|
default:
|
|
MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealEnumNextRegKeyInTree95W (
|
|
IN OUT PREGTREE_ENUMW EnumPtr
|
|
)
|
|
{
|
|
if (EnumPtr->State == NO_MORE_ITEMS) {
|
|
return FALSE;
|
|
}
|
|
|
|
while (TRUE) {
|
|
switch (EnumPtr->State) {
|
|
|
|
case ENUMERATE_SUBKEY_BEGIN:
|
|
//
|
|
// Start enumeration
|
|
//
|
|
|
|
if (EnumFirstRegKey95W (
|
|
&EnumPtr->CurrentKey->KeyEnum,
|
|
EnumPtr->CurrentKey->KeyHandle
|
|
)) {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_NEXT:
|
|
//
|
|
// Continue enumerations
|
|
//
|
|
|
|
if (EnumNextRegKey95W (&EnumPtr->CurrentKey->KeyEnum)) {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_DONE:
|
|
//
|
|
// Enumeration of this key is done; pop and continue.
|
|
//
|
|
|
|
if (!pPopRegKeyInfo95W (EnumPtr)) {
|
|
EnumPtr->State = NO_MORE_ITEMS;
|
|
AbortRegKeyTreeEnum95W (EnumPtr);
|
|
} else {
|
|
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
|
|
}
|
|
|
|
break;
|
|
|
|
case ENUMERATE_SUBKEY_RETURN:
|
|
//
|
|
// Return enumerated item to caller
|
|
//
|
|
|
|
if (!pPushRegKeyInfo95W (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
|
|
DEBUGMSGW ((
|
|
DBG_REGUTILS,
|
|
"EnumFirstRegKeyInTree95A failed to push sub key %s",
|
|
EnumPtr->CurrentKey->KeyEnum.SubKeyName
|
|
));
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
|
|
break;
|
|
}
|
|
|
|
if (!EnumPtr->FirstEnumerated) {
|
|
EnumPtr->FirstEnumerated = TRUE;
|
|
EnumPtr->EnumBaseBytes += sizeof (WCHAR);
|
|
}
|
|
|
|
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
|
|
return TRUE;
|
|
|
|
default:
|
|
MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
AbortRegKeyTreeEnum95A (
|
|
IN OUT PREGTREE_ENUMA EnumPtr
|
|
)
|
|
{
|
|
//
|
|
// Free all resources
|
|
//
|
|
|
|
while (pPopRegKeyInfo95A (EnumPtr)) {
|
|
}
|
|
|
|
PoolMemDestroyPool (EnumPtr->EnumPool);
|
|
}
|
|
|
|
|
|
VOID
|
|
AbortRegKeyTreeEnum95W (
|
|
IN OUT PREGTREE_ENUMW EnumPtr
|
|
)
|
|
{
|
|
//
|
|
// Free all resources
|
|
//
|
|
|
|
while (pPopRegKeyInfo95W (EnumPtr)) {
|
|
}
|
|
|
|
PoolMemDestroyPool (EnumPtr->EnumPool);
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstRegValue95A and EnumerateFirstRegvalueW enumerate the first registry
|
|
value name in the specified subkey.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Receives the updated state of enumeration. The structure
|
|
can be accessed directly.
|
|
|
|
hKey - Specifies handle of registry subkey to enumerate.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, or FALSE if an error or if no more values are available.
|
|
Call GetLastError for the failure code.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumFirstRegValue95A (
|
|
IN PREGVALUE_ENUMA EnumPtr,
|
|
IN HKEY hKey
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMA));
|
|
EnumPtr->KeyHandle = hKey;
|
|
|
|
return EnumNextRegValue95A (EnumPtr);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumFirstRegValue95W (
|
|
IN PREGVALUE_ENUMW EnumPtr,
|
|
IN HKEY hKey
|
|
)
|
|
{
|
|
ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMW));
|
|
EnumPtr->KeyHandle = hKey;
|
|
|
|
return EnumNextRegValue95W (EnumPtr);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumNextRegValue95A and EnumNextRegValue95W continue the enumeration started
|
|
by EnumFirstRegValue95A/W. The enumeration structure is updated to
|
|
reflect the next value name in the subkey being enumerated.
|
|
|
|
Arguments:
|
|
|
|
EnumPtr - Specifies the registry subkey and enumeration position.
|
|
Receives the updated state of enumeration. The structure
|
|
can be accessed directly.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, or FALSE if an error or if no more values are available.
|
|
Call GetLastError for the failure code.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumNextRegValue95A (
|
|
IN OUT PREGVALUE_ENUMA EnumPtr
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD ValueNameSize;
|
|
|
|
ValueNameSize = MAX_REGISTRY_VALUE_NAMEA;
|
|
|
|
rc = Win95RegEnumValueA (
|
|
EnumPtr->KeyHandle,
|
|
EnumPtr->Index,
|
|
EnumPtr->ValueName,
|
|
&ValueNameSize,
|
|
NULL,
|
|
&EnumPtr->Type,
|
|
NULL,
|
|
&EnumPtr->DataSize
|
|
);
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
return FALSE;
|
|
} else if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->Index += 1;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumNextRegValue95W (
|
|
IN OUT PREGVALUE_ENUMW EnumPtr
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD ValueNameSize;
|
|
|
|
ValueNameSize = MAX_REGISTRY_VALUE_NAMEW;
|
|
|
|
rc = Win95RegEnumValueW (
|
|
EnumPtr->KeyHandle,
|
|
EnumPtr->Index,
|
|
EnumPtr->ValueName,
|
|
&ValueNameSize,
|
|
NULL,
|
|
&EnumPtr->Type,
|
|
NULL,
|
|
&EnumPtr->DataSize
|
|
);
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
return FALSE;
|
|
} else if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->Index += 1;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
pMemAllocWrapper95 (
|
|
IN DWORD Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pMemAllocWrapper95 implements a default allocation routine. The APIs
|
|
that have a "2" at the end allow the caller to supply an alternative
|
|
allocator or deallocator. The routines without the "2" use this
|
|
default allocator.
|
|
|
|
Arguments:
|
|
|
|
Size - Specifies the amount of memory (in bytes) to allocate
|
|
|
|
Return Value:
|
|
|
|
A pointer to a block of memory that can hold Size bytes, or NULL
|
|
if allocation fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
return MemAlloc (g_hHeap, 0, Size);
|
|
}
|
|
|
|
|
|
VOID
|
|
pMemFreeWrapper95 (
|
|
IN PVOID Mem
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pMemFreeWrapper95 implements a default deallocation routine.
|
|
See pMemAllocWrapper95 above.
|
|
|
|
Arguments:
|
|
|
|
Mem - Specifies the block of memory to free, and was allocated by the
|
|
pMemAllocWrapper95 function.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
MemFree (g_hHeap, 0, Mem);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetRegValueDataEx95A and GetRegValueDataEx95W query a registry value and
|
|
return the data as a pointer. They use the specified Alloc and Free
|
|
routines to allocate and free the memory as needed.
|
|
|
|
A GetRegValueData macro is defined, and it uses the default allocators,
|
|
simplifying the function parameters and allowing the caller to free
|
|
the return value via MemFree.
|
|
|
|
Arguments:
|
|
|
|
hKey - Specifies the registry key that holds the specified value.
|
|
|
|
Value - Specifies the value name to query.
|
|
|
|
Alloc - Specifies the allocation routine, called to allocate a block of
|
|
memory for the return data.
|
|
|
|
Free - Specifies the deallocation routine, called if an error is encountered
|
|
during processing.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the data retrieved, or NULL if the value does not exist or an
|
|
error occurred. Call GetLastError to obtian the failure code.
|
|
|
|
--*/
|
|
|
|
PBYTE
|
|
GetRegValueDataEx95A (
|
|
IN HKEY hKey,
|
|
IN PCSTR Value,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD BufSize;
|
|
PBYTE DataBuf;
|
|
|
|
rc = Win95RegQueryValueExA (hKey, Value, NULL, NULL, NULL, &BufSize);
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
DataBuf = (PBYTE) Alloc (BufSize + sizeof (CHAR));
|
|
rc = Win95RegQueryValueExA (hKey, Value, NULL, NULL, DataBuf, &BufSize);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
*((PSTR) DataBuf + BufSize) = 0;
|
|
return DataBuf;
|
|
}
|
|
|
|
Free (DataBuf);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PBYTE
|
|
GetRegValueDataEx95W (
|
|
IN HKEY hKey,
|
|
IN PCWSTR Value,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD BufSize;
|
|
PBYTE DataBuf;
|
|
|
|
rc = Win95RegQueryValueExW (hKey, Value, NULL, NULL, NULL, &BufSize);
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
DataBuf = (PBYTE) Alloc (BufSize + sizeof(WCHAR));
|
|
rc = Win95RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
*((PWSTR) (DataBuf + BufSize)) = 0;
|
|
return DataBuf;
|
|
}
|
|
|
|
Free (DataBuf);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetRegValueDataOfTypeEx95A and GetRegValueDataOfTypeEx95W are extensions of
|
|
GetRegValueData. They only return a data pointer when the data stored
|
|
in the registry value is the correct type.
|
|
|
|
Arguments:
|
|
|
|
hKey - Specifies the registry key to query
|
|
|
|
Value - Specifies the value name to query
|
|
|
|
MustBeType - Specifies the type of data (a REG_* constant). If the specified
|
|
value has data but is a different type, NULL will be returned.
|
|
|
|
Alloc - Specifies the allocation routine, called to allocate the return data.
|
|
|
|
Free - Specifies the deallocation routine, called when an error is encountered.
|
|
|
|
Return Value:
|
|
|
|
If successful, returns a pointer to data that matches the specified type.
|
|
If the data is a different type, the value name does not exist, or an
|
|
error occurs during the query, NULL is returned, and the failure code
|
|
can be obtained from GetLastError.
|
|
|
|
--*/
|
|
|
|
|
|
PBYTE
|
|
GetRegValueDataOfTypeEx95A (
|
|
IN HKEY hKey,
|
|
IN PCSTR Value,
|
|
IN DWORD MustBeType,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD BufSize;
|
|
PBYTE DataBuf;
|
|
DWORD Type;
|
|
|
|
rc = Win95RegQueryValueExA (hKey, Value, NULL, &Type, NULL, &BufSize);
|
|
if (rc != ERROR_SUCCESS || Type != MustBeType) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
DataBuf = (PBYTE) Alloc (BufSize + sizeof (CHAR));
|
|
rc = Win95RegQueryValueExA (hKey, Value, NULL, NULL, DataBuf, &BufSize);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
*((PSTR) DataBuf + BufSize) = 0;
|
|
return DataBuf;
|
|
}
|
|
|
|
Free (DataBuf);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PBYTE
|
|
GetRegValueDataOfTypeEx95W (
|
|
IN HKEY hKey,
|
|
IN PCWSTR Value,
|
|
IN DWORD MustBeType,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
LONG rc;
|
|
DWORD BufSize;
|
|
PBYTE DataBuf;
|
|
DWORD Type;
|
|
|
|
rc = Win95RegQueryValueExW (hKey, Value, NULL, &Type, NULL, &BufSize);
|
|
if (rc != ERROR_SUCCESS || Type != MustBeType) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
DataBuf = (PBYTE) Alloc (BufSize + sizeof(WCHAR));
|
|
rc = Win95RegQueryValueExW (hKey, Value, NULL, NULL, DataBuf, &BufSize);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
*((PWSTR) (DataBuf + BufSize)) = 0;
|
|
return DataBuf;
|
|
}
|
|
|
|
Free (DataBuf);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetRegKeyDataEx95A and GetRegKeyDataEx95W return default data associated
|
|
with a registry key. They open the specified subkey, query the value,
|
|
close the subkey and return the data.
|
|
|
|
Arguments:
|
|
|
|
Parent - Specifies the key that contains SubKey.
|
|
|
|
SubKey - Specifies the name of the subkey to obtain the default value for.
|
|
|
|
Alloc - Specifies the allocation routine, called to allocate a block of
|
|
memory for the registry data.
|
|
|
|
Free - Specifies the deallocation routine, called to free the block of
|
|
data if an error occurs.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the block of data obtained from the subkey's default value,
|
|
or NULL if the subkey does not exist or an error was encountered. Call
|
|
GetLastError for a failure code.
|
|
|
|
--*/
|
|
|
|
PBYTE
|
|
GetRegKeyDataEx95A (
|
|
IN HKEY Parent,
|
|
IN PCSTR SubKey,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
HKEY SubKeyHandle;
|
|
PBYTE Data;
|
|
|
|
SubKeyHandle = OpenRegKey95A (Parent, SubKey);
|
|
if (!SubKeyHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
Data = GetRegValueDataEx95A (SubKeyHandle, "", Alloc, Free);
|
|
|
|
CloseRegKey95 (SubKeyHandle);
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
PBYTE
|
|
GetRegKeyDataEx95W (
|
|
IN HKEY Parent,
|
|
IN PCWSTR SubKey,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
HKEY SubKeyHandle;
|
|
PBYTE Data;
|
|
|
|
SubKeyHandle = OpenRegKey95W (Parent, SubKey);
|
|
if (!SubKeyHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
Data = GetRegValueDataEx95W (SubKeyHandle, L"", Alloc, Free);
|
|
|
|
CloseRegKey95 (SubKeyHandle);
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetRegDataEx95A and GetRegDataEx95W open a registry key, query a value,
|
|
close the registry key and return the value.
|
|
|
|
Arguments:
|
|
|
|
KeyString - Specifies the registry key to open
|
|
|
|
ValueName - Specifies the value to query
|
|
|
|
Alloc - Specifies the allocation routine, used to allocate a block of
|
|
memory to hold the value data
|
|
|
|
Free - Specifies the deallocation routine, used to free the block of
|
|
memory when an error is encountered.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the registry data retrieved, or NULL if the key or value
|
|
does not exist, or if an error occurs. Call GetLastError for a failure code.
|
|
|
|
--*/
|
|
|
|
PBYTE
|
|
GetRegDataEx95A (
|
|
IN PCSTR KeyString,
|
|
IN PCSTR ValueName,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
HKEY Key;
|
|
PBYTE Data;
|
|
|
|
Key = OpenRegKeyStr95A (KeyString);
|
|
if (!Key) {
|
|
return NULL;
|
|
}
|
|
|
|
Data = GetRegValueDataEx95A (Key, ValueName, Alloc, Free);
|
|
|
|
CloseRegKey95 (Key);
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
PBYTE
|
|
GetRegDataEx95W (
|
|
IN PCWSTR KeyString,
|
|
IN PCWSTR ValueName,
|
|
IN ALLOCATOR Alloc,
|
|
IN DEALLOCATOR Free
|
|
)
|
|
{
|
|
HKEY Key;
|
|
PBYTE Data;
|
|
|
|
Key = OpenRegKeyStr95W (KeyString);
|
|
if (!Key) {
|
|
return NULL;
|
|
}
|
|
|
|
Data = GetRegValueDataEx95W (Key, ValueName, Alloc, Free);
|
|
|
|
CloseRegKey95 (Key);
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
OpenRegKey95A and OpenRegKey95W open a subkey.
|
|
|
|
Arguments:
|
|
|
|
ParentKey - Specifies a handle to the parent registry key to contain
|
|
the subkey.
|
|
|
|
KeyToOpen - Specifies the name of the subkey to open.
|
|
|
|
Return Value:
|
|
|
|
The handle to an open registry key upon success, or NULL if an
|
|
error occurred. Call GetLastError for a failure code.
|
|
|
|
--*/
|
|
|
|
HKEY
|
|
RealOpenRegKey95A (
|
|
IN HKEY ParentKey,
|
|
IN PCSTR KeyToOpen OPTIONAL
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
HKEY SubKey;
|
|
LONG rc;
|
|
|
|
rc = OurRegOpenKeyEx95A (
|
|
ParentKey,
|
|
KeyToOpen,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&SubKey
|
|
DEBUG_TRACKING_ARGS
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
return SubKey;
|
|
}
|
|
|
|
|
|
HKEY
|
|
RealOpenRegKey95W (
|
|
IN HKEY ParentKey,
|
|
IN PCWSTR KeyToOpen
|
|
DEBUG_TRACKING_PARAMS
|
|
)
|
|
{
|
|
LONG rc;
|
|
HKEY SubKey;
|
|
|
|
rc = OurRegOpenKeyEx95W (
|
|
ParentKey,
|
|
KeyToOpen,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&SubKey
|
|
DEBUG_TRACKING_ARGS
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
return SubKey;
|
|
}
|
|
|
|
|
|
LONG
|
|
RealCloseRegKey95 (
|
|
IN HKEY Key
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RealCloseRegKey95 closes the reg handle supplied, unless the handle is
|
|
a pre-defined Win32 handle. The CloseRegKey95 macro resolves directly
|
|
to this function in the free build, and to OurCloseRegKey95 in the
|
|
checked build.
|
|
|
|
Arguments:
|
|
|
|
Key - Specifies the reg handle to close
|
|
|
|
Return Value:
|
|
|
|
A standard Win32 error code indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (GetOffsetOfRootKey (Key)) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
return Win95RegCloseKey (Key);
|
|
}
|
|
|
|
|