mirror of https://github.com/tongzx/nt5src
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.
988 lines
27 KiB
988 lines
27 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1992, Microsoft Corporation
|
|
//
|
|
// File: registry.c
|
|
//
|
|
// Contents: Module to read in registry parameters.
|
|
//
|
|
// This module is intended as a simple, reusable, interface to the
|
|
// registry. Among its features are:
|
|
//
|
|
// o Kernel Callable.
|
|
//
|
|
// o Intuitive (it is to me!) - To read the value for /a/b/c/d,
|
|
// you say KRegGetValue("/a/b/c/d"), instead of calling at
|
|
// least 3 different Nt APIs. Any and all strings returned are
|
|
// guaranteed to be NULL terminated.
|
|
//
|
|
// o Allocates memory on behalf of caller - so we don't waste any
|
|
// by allocating max amounts.
|
|
//
|
|
// o Completely non-reentrant - 'cause it maintains state across
|
|
// calls. (It would be simple to make it multi-threaded tho)
|
|
//
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions: KRegSetRoot
|
|
// KRegCloseRoot
|
|
// KRegGetValue
|
|
// KRegGetNumValuesAndSubKeys
|
|
// KRegEnumValueSet
|
|
// KRegEnumSubKeySet
|
|
//
|
|
//
|
|
// History: 18 Sep 92 Milans created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "registry.h"
|
|
#include "regsups.h"
|
|
|
|
|
|
//
|
|
// If we ever needed to go multithreaded, we should return HKEY_ROOT to caller
|
|
// instead of keeping it here.
|
|
//
|
|
|
|
static HKEY HKEY_ROOT = NULL; // Handle to root key
|
|
|
|
#define KREG_SIZE_THRESHOLD 5 // For allocation optimization
|
|
|
|
//
|
|
// Some commonly used error format strings.
|
|
//
|
|
|
|
#if DBG == 1
|
|
|
|
static char *szErrorOpen = "Error opening %ws section.\n";
|
|
static char *szErrorRead = "Error reading %ws section.\n";
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, KRegInit )
|
|
#pragma alloc_text( PAGE, KRegCloseRoot )
|
|
#pragma alloc_text( PAGE, KRegSetRoot )
|
|
#pragma alloc_text( PAGE, KRegCreateKey )
|
|
#pragma alloc_text( PAGE, KRegGetValue )
|
|
#pragma alloc_text( PAGE, KRegSetValue )
|
|
#pragma alloc_text( PAGE, KRegDeleteValue )
|
|
#pragma alloc_text( PAGE, KRegGetNumValuesAndSubKeys )
|
|
#pragma alloc_text( PAGE, KRegEnumValueSet )
|
|
#pragma alloc_text( PAGE, KRegEnumSubKeySet )
|
|
#pragma alloc_text( PAGE, KRegFreeArray )
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KREG_CHECK_HARD_STATUS, macro
|
|
//
|
|
// Synopsis: If Status is not STATUS_SUCCESS, print out debug msg and return.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define KREG_CHECK_HARD_STATUS(Status, M1, M2) \
|
|
if (!NT_SUCCESS(Status)) { \
|
|
kreg_debug_out(M1, M2); \
|
|
return(Status); \
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegInit
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: STATUS_SUCCESS
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegInit(void)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------void
|
|
//
|
|
// Function: KRegCloseRoot
|
|
//
|
|
// Synopsis: Close the Root opened by KRegSetRoot.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void
|
|
KRegCloseRoot()
|
|
{
|
|
if (HKEY_ROOT) {
|
|
NtClose(HKEY_ROOT);
|
|
HKEY_ROOT = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegSetRoot
|
|
//
|
|
// Synopsis: Sets a particular key as the "root" key for subsequent calls
|
|
// to registry routines.
|
|
//
|
|
// Arguments: wszRootName - Name of root key
|
|
//
|
|
// Returns: Result of opening the key.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegSetRoot(
|
|
IN PWSTR wszRootName
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (HKEY_ROOT != NULL) {
|
|
NtClose(HKEY_ROOT);
|
|
}
|
|
|
|
Status = NtOpenKey(
|
|
&HKEY_ROOT, // Handle to DFS root key
|
|
KEY_READ | KEY_WRITE, // Only need to read
|
|
KRegpAttributes( // Name of Key
|
|
NULL,
|
|
wszRootName
|
|
)
|
|
);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegDeleteKey
|
|
//
|
|
// Synopsis: Deletes a key from the registry.
|
|
//
|
|
// Arguments: [wszKey] -- name of key relative to the current root.
|
|
//
|
|
// Returns: Status from deleting the key.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegDeleteKey(
|
|
IN PWSTR wszKey)
|
|
{
|
|
NTSTATUS Status;
|
|
APWSTR awszSubKeys;
|
|
ULONG cSubKeys, i;
|
|
HKEY hkey;
|
|
|
|
//
|
|
// NtDeleteKey won't delete key's which have subkeys. So, we first
|
|
// enumerate all the subkeys and delete them, before deleting the key.
|
|
//
|
|
|
|
Status = KRegEnumSubKeySet(wszKey, &cSubKeys, &awszSubKeys);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return( Status );
|
|
}
|
|
|
|
for (i = 0; i < cSubKeys && NT_SUCCESS(Status); i++) {
|
|
|
|
Status = NtOpenKey(
|
|
&hkey,
|
|
KEY_ALL_ACCESS,
|
|
KRegpAttributes(HKEY_ROOT, awszSubKeys[i])
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtDeleteKey( hkey );
|
|
NtClose(hkey);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// If we were able to delete all the subkeys, we can delete the
|
|
// key itself.
|
|
//
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtOpenKey(
|
|
&hkey,
|
|
KEY_ALL_ACCESS,
|
|
KRegpAttributes(HKEY_ROOT, wszKey)
|
|
);
|
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
Status = STATUS_SUCCESS;
|
|
} else if (NT_SUCCESS(Status)) {
|
|
Status = NtDeleteKey( hkey );
|
|
NtClose(hkey);
|
|
}
|
|
}
|
|
|
|
KRegFreeArray( cSubKeys, (APBYTE) awszSubKeys );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegCreateKey
|
|
//
|
|
// Synopsis: Creates a new key in the registry under the subkey given
|
|
// in wszSubKey. wszSubKey may be NULL, in which case the
|
|
// new key is created directly under the current root.
|
|
//
|
|
// Arguments: [wszSubKey] -- Name of subkey relative to root key under
|
|
// which new key will be created.
|
|
// [wszNewKey] -- Name of new key to be created.
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegCreateKey(
|
|
IN PWSTR wszSubKey,
|
|
IN PWSTR wszNewKey)
|
|
{
|
|
HKEY hkeySubKey, hkeyNewKey;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ustrValueName;
|
|
|
|
|
|
if (wszSubKey != NULL) {
|
|
Status = NtOpenKey(
|
|
&hkeySubKey,
|
|
KEY_WRITE,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
} else {
|
|
hkeySubKey = HKEY_ROOT;
|
|
}
|
|
|
|
Status = NtCreateKey(
|
|
&hkeyNewKey,
|
|
KEY_WRITE,
|
|
KRegpAttributes(hkeySubKey, wszNewKey),
|
|
0L, // TitleIndex
|
|
NULL, // Class
|
|
REG_OPTION_NON_VOLATILE, // Create option
|
|
NULL); // Create disposition
|
|
|
|
if (wszSubKey != NULL) {
|
|
NtClose(hkeySubKey);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
kreg_debug_out(szErrorOpen, wszNewKey);
|
|
NtClose(hkeyNewKey);
|
|
return(Status);
|
|
}
|
|
|
|
NtClose(hkeyNewKey);
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegGetValue
|
|
//
|
|
// Synopsis: Given a Value Name and a handle, will allocate memory for the
|
|
// handle and fill it with the Value Data for the value name.
|
|
//
|
|
// Arguments: [wszSubKey] - Name of subkey relative to root key
|
|
// [wszValueName] - name of value data
|
|
// [ppValueData] - pointer to pointer to byte data.
|
|
//
|
|
// Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, Status from NtReg api.
|
|
//
|
|
// Notes: It will allocate memory for the data, and return a pointer to
|
|
// it in ppValueData. Caller must free it.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegGetValue(
|
|
IN PWSTR wszSubKey,
|
|
IN PWSTR wszValueName,
|
|
OUT PBYTE *ppValueData
|
|
)
|
|
{
|
|
HKEY hkeySubKey;
|
|
ULONG dwUnused, cbMaxDataSize;
|
|
ULONG cbActualSize;
|
|
PBYTE pbData = NULL;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtOpenKey(
|
|
&hkeySubKey,
|
|
KEY_READ,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
|
|
Status = KRegpGetKeyInfo(
|
|
hkeySubKey,
|
|
&dwUnused, // Number of Subkeys
|
|
&dwUnused, // Max size of subkey length
|
|
&dwUnused, // # of Values
|
|
&dwUnused, // Max size of value Name
|
|
&cbMaxDataSize // Max size of value Data
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
kreg_debug_out(szErrorRead, wszSubKey);
|
|
NtClose(hkeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Just in case the value is of type REG_SZ, provide for inserting a
|
|
// UNICODE_NULL at the end.
|
|
//
|
|
|
|
cbMaxDataSize += sizeof(UNICODE_NULL);
|
|
|
|
pbData = kreg_alloc(cbMaxDataSize);
|
|
if (pbData == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
cbActualSize = cbMaxDataSize;
|
|
|
|
Status = KRegpGetValueByName(
|
|
hkeySubKey,
|
|
wszValueName,
|
|
pbData,
|
|
&cbActualSize);
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if ((cbMaxDataSize - cbActualSize) < KREG_SIZE_THRESHOLD) {
|
|
|
|
//
|
|
// Optimization - no need to double allocate if actual size and max
|
|
// size are pretty close.
|
|
//
|
|
|
|
*ppValueData = pbData;
|
|
pbData = NULL; // "deallocate" pbData
|
|
|
|
} else {
|
|
|
|
//
|
|
// Big enough difference between actual and max size, warrants
|
|
// allocating a smaller buffer.
|
|
//
|
|
|
|
*ppValueData = (PBYTE) kreg_alloc(cbActualSize);
|
|
if (*ppValueData == NULL) {
|
|
|
|
//
|
|
// Well, we couldn't "reallocate" a smaller chunk, we'll just
|
|
// live on the edge and return the original buffer.
|
|
//
|
|
*ppValueData = pbData;
|
|
pbData = NULL;
|
|
} else {
|
|
RtlMoveMemory(*ppValueData, pbData, cbActualSize);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
NtClose(hkeySubKey);
|
|
if (pbData != NULL) {
|
|
kreg_free(pbData);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegSetValue
|
|
//
|
|
// Synopsis: Given a Key Name, Value Name, and type, size and data, this
|
|
// routine will update the registry's value to the type and data.
|
|
// The valuename will be created if it doesn't exist. The key
|
|
// must already exist.
|
|
//
|
|
// Arguments: [wszSubKey] - Name of subkey relative to root key
|
|
// [wszValueName] - name of value data
|
|
// [ulType] - as in REG_DWORD, REG_SZ, REG_MULTI_SZ, etc.
|
|
// [cbSize] - size in bytes of data. If type == REG_SZ, data need
|
|
// !not! include the terminating NULL. One will be
|
|
// appended as needed.
|
|
// [pValueData] - pointer to pointer to byte data.
|
|
//
|
|
// Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, Status from NtReg api.
|
|
//
|
|
// Notes: It will allocate memory for the data, and return a pointer to
|
|
// it in ppValueData. Caller must free it.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegSetValue(
|
|
IN PWSTR wszSubKey,
|
|
IN PWSTR wszValueName,
|
|
IN ULONG ulType,
|
|
IN ULONG cbSize,
|
|
IN PBYTE pValueData
|
|
)
|
|
{
|
|
HKEY hkeySubKey;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ustrValueName;
|
|
PWSTR pwszValueData;
|
|
|
|
|
|
|
|
Status = NtOpenKey(
|
|
&hkeySubKey,
|
|
KEY_WRITE,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
|
|
RtlInitUnicodeString(&ustrValueName, wszValueName);
|
|
|
|
if (ulType == REG_SZ) {
|
|
|
|
pwszValueData = (PWSTR) kreg_alloc(cbSize+sizeof(UNICODE_NULL));
|
|
|
|
if (pwszValueData == NULL) {
|
|
NtClose(hkeySubKey);
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID) pwszValueData, (PVOID) pValueData, cbSize);
|
|
pwszValueData[cbSize/sizeof(WCHAR)] = UNICODE_NULL;
|
|
cbSize += sizeof(UNICODE_NULL);
|
|
} else {
|
|
pwszValueData = (PWSTR) pValueData;
|
|
}
|
|
|
|
Status = NtSetValueKey(
|
|
hkeySubKey,
|
|
&ustrValueName,
|
|
0L, // TitleIndex
|
|
ulType,
|
|
pwszValueData,
|
|
cbSize);
|
|
|
|
if (ulType == REG_SZ) {
|
|
kreg_free(pwszValueData);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
NtFlushKey(hkeySubKey);
|
|
}
|
|
|
|
NtClose(hkeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegDeleteValue
|
|
//
|
|
// Synopsis: Deletes a value name
|
|
//
|
|
// Arguments: [wszSubKey] -- Name of subkey under which wszValueName exists.
|
|
// [wszValueName] -- Name of Value to delete.
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS KRegDeleteValue(
|
|
IN PWSTR wszSubKey,
|
|
IN PWSTR wszValueName)
|
|
{
|
|
HKEY hkeySubKey;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ustrValueName;
|
|
|
|
Status = NtOpenKey(
|
|
&hkeySubKey,
|
|
KEY_WRITE,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
RtlInitUnicodeString(&ustrValueName, wszValueName);
|
|
|
|
Status = NtDeleteValueKey(
|
|
hkeySubKey,
|
|
&ustrValueName);
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
NtFlushKey(hkeySubKey);
|
|
}
|
|
|
|
NtClose(hkeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegGetNumValuesAndSubKeys
|
|
//
|
|
// Synopsis: Given a Subkey, return how many subkeys and values it has.
|
|
//
|
|
// Arguments: [wszSubKey] - for which info is required.
|
|
// [plNumValues] - receives number of values this subkey has.
|
|
// [plNumSubKeys] - receives number of subkeys under this subkey.
|
|
//
|
|
// Returns: STATUS_SUCCESS, or Status from NtRegAPI.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegGetNumValuesAndSubKeys(
|
|
IN PWSTR wszSubKey,
|
|
OUT PULONG pcNumValues,
|
|
OUT PULONG pcNumSubKeys
|
|
)
|
|
{
|
|
HKEY hKeySubKey;
|
|
ULONG dwUnused;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtOpenKey(
|
|
&hKeySubKey,
|
|
KEY_READ,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
|
|
Status = KRegpGetKeyInfo(
|
|
hKeySubKey,
|
|
pcNumSubKeys, // Number of Subkeys
|
|
&dwUnused, // Max size of subkey length
|
|
pcNumValues, // # of Values
|
|
&dwUnused, // Max size of value Name
|
|
&dwUnused // Max size of value Data
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
kreg_debug_out(szErrorRead, wszSubKey);
|
|
NtClose(hKeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
NtClose(hKeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegEnumValueSet
|
|
//
|
|
// Synopsis: Given a subkey, return the names and data for all its values.
|
|
//
|
|
// Arguments: [wszSubKey] - Name of subkey to read.
|
|
// [pcMaxElements] - On return, contains number of names and
|
|
// data actually read.
|
|
// [pawszValueNames] - Pointer to array of PWSTRS. This routine
|
|
// will allocate memory for the array and the
|
|
// strings.
|
|
// [papbValueData] - pointer to array of PBYTES. This routine
|
|
// will allocate the array and the memory for the
|
|
// data, stuffing the pointers to data into this
|
|
// array.
|
|
// [paValueStatus] - Status of reading the corresponding Value. The
|
|
// array will be allocated here.
|
|
//
|
|
// Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, or Status from NtRegAPI.
|
|
//
|
|
// Notes: Returned Value Names are always NULL terminated.
|
|
// If the Value Data is of type REG_SZ, it, too, is NULL terminated
|
|
// Caller frees the last three OUT params (and the contents of
|
|
// awszValueNames and apbValueData!) only on SUCCESSFUL return.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegEnumValueSet(
|
|
IN PWSTR wszSubKey,
|
|
OUT PULONG pcMaxElements,
|
|
OUT APWSTR *pawszValueNames,
|
|
OUT APBYTE *papbValueData,
|
|
OUT ANTSTATUS *paValueStatus
|
|
)
|
|
{
|
|
ULONG i = 0;
|
|
HKEY hKeySubKey;
|
|
ULONG dwUnused, cbMaxNameSize, cbMaxDataSize;
|
|
PWSTR wszName = NULL;
|
|
PBYTE pbData = NULL;
|
|
NTSTATUS Status;
|
|
|
|
APWSTR awszValueNames;
|
|
APBYTE apbValueData;
|
|
ANTSTATUS aValueStatus;
|
|
ULONG cMaxElements;
|
|
|
|
awszValueNames = *pawszValueNames = NULL;
|
|
apbValueData = *papbValueData = NULL;
|
|
aValueStatus = *paValueStatus = NULL;
|
|
|
|
Status = NtOpenKey(
|
|
&hKeySubKey,
|
|
KEY_READ,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
|
|
Status = KRegpGetKeyInfo(
|
|
hKeySubKey,
|
|
&dwUnused, // Number of Subkeys
|
|
&dwUnused, // Max size of subkey length
|
|
&cMaxElements, // # of Values
|
|
&cbMaxNameSize, // Max size of value Name
|
|
&cbMaxDataSize // Max size of value Data
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
kreg_debug_out(szErrorRead, wszSubKey);
|
|
NtClose(hKeySubKey);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the arrays.
|
|
//
|
|
|
|
awszValueNames = *pawszValueNames = kreg_alloc(cMaxElements * sizeof(PWSTR));
|
|
apbValueData = *papbValueData = kreg_alloc(cMaxElements * sizeof(PBYTE));
|
|
aValueStatus = *paValueStatus = kreg_alloc(cMaxElements * sizeof(NTSTATUS));
|
|
|
|
if (awszValueNames == NULL || apbValueData == NULL || aValueStatus == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the arrays
|
|
//
|
|
|
|
RtlZeroMemory(awszValueNames, cMaxElements * sizeof(PWSTR));
|
|
RtlZeroMemory(apbValueData, cMaxElements * sizeof(PBYTE));
|
|
RtlZeroMemory(aValueStatus, cMaxElements * sizeof(NTSTATUS));
|
|
|
|
//
|
|
// For name, we need an extra spot for the terminating NULL
|
|
//
|
|
|
|
wszName = kreg_alloc(cbMaxNameSize + sizeof(WCHAR));
|
|
pbData = kreg_alloc(cbMaxDataSize);
|
|
|
|
if (pbData == NULL || wszName == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
for (i = 0; i < cMaxElements; i++) {
|
|
ULONG cbActualNameSize, cbActualDataSize;
|
|
|
|
cbActualNameSize = cbMaxNameSize;
|
|
cbActualDataSize = cbMaxDataSize;
|
|
|
|
Status = KRegpEnumKeyValues(
|
|
hKeySubKey,
|
|
i,
|
|
wszName,
|
|
&cbActualNameSize,
|
|
pbData,
|
|
&cbActualDataSize
|
|
);
|
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
} else if (!NT_SUCCESS(Status)) {
|
|
aValueStatus[i] = Status;
|
|
continue;
|
|
} else {
|
|
aValueStatus[i] = Status;
|
|
}
|
|
|
|
cbActualNameSize += sizeof(WCHAR); // For terminating NULL
|
|
awszValueNames[i] = (PWSTR) kreg_alloc(cbActualNameSize);
|
|
apbValueData[i] = (PBYTE) kreg_alloc(cbActualDataSize);
|
|
|
|
if (apbValueData[i] == NULL || awszValueNames[i] == NULL) {
|
|
Status = aValueStatus[i] = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
RtlMoveMemory(awszValueNames[i], wszName, cbActualNameSize);
|
|
RtlMoveMemory(apbValueData[i], pbData, cbActualDataSize);
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
NtClose(hKeySubKey);
|
|
if (wszName != NULL) {
|
|
kreg_free(wszName);
|
|
}
|
|
if (pbData != NULL) {
|
|
kreg_free(pbData);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
*pcMaxElements = 0;
|
|
|
|
KRegFreeArray(i+1, (APBYTE) awszValueNames);
|
|
KRegFreeArray(i+1, apbValueData);
|
|
|
|
if (aValueStatus != NULL) {
|
|
kreg_free(aValueStatus);
|
|
}
|
|
|
|
} else { // Status success
|
|
|
|
*pcMaxElements = i;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegEnumSubKeySet
|
|
//
|
|
// Synopsis: This one's slightly trick. Given a Subkey, it returns an array
|
|
// of its subkey-names. The following is true - say the root is
|
|
// /a/b/c. Say wszSubKey is d. Say d has subkeys s1, s2, and s3.
|
|
// Then the array of subkey-names returned will contain the names
|
|
// d/s1, d/s2, d/s3.
|
|
//
|
|
// Arguments: [wszSubKey] - the Subkey relative to the root.
|
|
// [pcMaxElements] - On return, # subkeys actually being returned.
|
|
// [awszValueNames] - Unitialized array of PWSTR (room for at least
|
|
// *plMaxElements). This routine will allocate
|
|
// memory for the subkey names, and fill in this
|
|
// array with pointers to them.
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: Caller must free at most *plMaxElements members of
|
|
// awszSubKeyNames. See synopsis above for form of subkey names.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegEnumSubKeySet(
|
|
IN PWSTR wszSubKey,
|
|
IN OUT PULONG pcMaxElements,
|
|
OUT APWSTR *pawszSubKeyNames
|
|
)
|
|
{
|
|
ULONG i, j = 0;
|
|
APWSTR awszSubKeyNames = NULL;
|
|
PWSTR wszBuffer = NULL;
|
|
HKEY hKeySubKey;
|
|
ULONG dwUnused, cbMaxNameSize, cwszSubKey;
|
|
NTSTATUS Status;
|
|
|
|
cwszSubKey = wcslen(wszSubKey);
|
|
|
|
*pawszSubKeyNames = NULL;
|
|
|
|
Status = NtOpenKey(
|
|
&hKeySubKey,
|
|
KEY_READ,
|
|
KRegpAttributes(HKEY_ROOT, wszSubKey)
|
|
);
|
|
|
|
KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
|
|
|
|
Status = KRegpGetKeyInfo(
|
|
hKeySubKey,
|
|
pcMaxElements, // Number of Subkeys
|
|
&cbMaxNameSize, // Max size of subkey name
|
|
&dwUnused, // # of Values
|
|
&dwUnused, // Max size of value Name
|
|
&dwUnused // Max size of value Data
|
|
);
|
|
|
|
if (pcMaxElements == 0) {
|
|
NtClose(hKeySubKey);
|
|
*pawszSubKeyNames = NULL;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
kreg_debug_out(szErrorRead, wszSubKey);
|
|
goto Cleanup;
|
|
}
|
|
|
|
*pawszSubKeyNames = kreg_alloc(
|
|
(*pcMaxElements + 1) * sizeof(PWSTR)
|
|
);
|
|
awszSubKeyNames = *pawszSubKeyNames;
|
|
wszBuffer = kreg_alloc(cbMaxNameSize + sizeof(WCHAR));
|
|
|
|
if (wszBuffer == NULL || awszSubKeyNames == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
} else {
|
|
RtlZeroMemory(awszSubKeyNames, (*pcMaxElements + 1) * sizeof(PWSTR));
|
|
}
|
|
|
|
for (i = j = 0; j < *pcMaxElements; i++) {
|
|
ULONG cbActualNameSize, cNameIndex;
|
|
|
|
cbActualNameSize = cbMaxNameSize;
|
|
|
|
Status = KRegpEnumSubKeys(
|
|
hKeySubKey,
|
|
i,
|
|
wszBuffer,
|
|
&cbActualNameSize
|
|
);
|
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
} else if (!NT_SUCCESS(Status)) {
|
|
continue;
|
|
}
|
|
|
|
cbActualNameSize += sizeof(WCHAR); // for terminating NULL
|
|
awszSubKeyNames[j] = (PWSTR) kreg_alloc(
|
|
cwszSubKey * sizeof(WCHAR) +
|
|
sizeof(WCHAR) + // for backslash
|
|
cbActualNameSize
|
|
);
|
|
if (awszSubKeyNames[j] == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
} else {
|
|
RtlZeroMemory(
|
|
awszSubKeyNames[j],
|
|
cwszSubKey * sizeof(WCHAR) +
|
|
sizeof(WCHAR) + // for backslash
|
|
cbActualNameSize);
|
|
if (wszSubKey[0] != UNICODE_NULL) {
|
|
wcscpy(awszSubKeyNames[j], wszSubKey);
|
|
wcscat(awszSubKeyNames[j], UNICODE_PATH_SEP_STR);
|
|
cNameIndex = cwszSubKey + 1;
|
|
} else {
|
|
cNameIndex = 0;
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
&awszSubKeyNames[j][cNameIndex],
|
|
wszBuffer,
|
|
cbActualNameSize);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
NtClose(hKeySubKey);
|
|
if (wszBuffer != NULL) {
|
|
kreg_free(wszBuffer);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
*pcMaxElements = 0;
|
|
|
|
KRegFreeArray(j, (APBYTE) awszSubKeyNames);
|
|
|
|
} else { // status success
|
|
*pcMaxElements = j;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegFreeArray
|
|
//
|
|
// Synopsis: Given an array of pointers, frees the pointers and the array.
|
|
//
|
|
// Arguments: [cElements] - Number of elements to free. Some elements can be
|
|
// NULL.
|
|
// [pa] - pointer to the array.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
KRegFreeArray(
|
|
IN ULONG cElements,
|
|
IN APBYTE pa)
|
|
{
|
|
ULONG i;
|
|
|
|
if (pa != NULL) {
|
|
for (i = 0; i < cElements; i++) {
|
|
if (pa[i] != NULL) {
|
|
kreg_free(pa[i]);
|
|
}
|
|
}
|
|
|
|
kreg_free(pa);
|
|
}
|
|
}
|
|
|
|
|