989 lines
27 KiB
C
989 lines
27 KiB
C
//+----------------------------------------------------------------------------
|
||
//
|
||
// 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);
|
||
}
|
||
}
|
||
|
||
|