Leaked source code of windows server 2003
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.
 
 
 
 
 
 

787 lines
19 KiB

// Copyright (c) 1995, Microsoft Corporation, all rights reserved
//
// reg.c
// Registry utility routines
// Listed alphabetically
//
// 11/31/95 Steve Cobb
#include <windows.h> // Win32 root
#include <debug.h> // Trace/Assert library
#include <nouiutil.h> // Prototypes and heap macros
//-----------------------------------------------------------------------------
// Local prototypes (alphabetically)
//-----------------------------------------------------------------------------
BOOL
RegDeleteTreeWorker(
IN HKEY ParentKeyHandle,
IN TCHAR* KeyName,
OUT DWORD* ErrorCode );
//-----------------------------------------------------------------------------
// Routines (alphabetically)
//-----------------------------------------------------------------------------
VOID
GetRegBinary(
IN HKEY hkey,
IN TCHAR* pszName,
OUT BYTE** ppbResult,
OUT DWORD* pcbResult )
// Set '*ppbResult' to the BINARY registry value 'pszName' under key
// 'hkey'. If the value does not exist *ppbResult' is set to NULL.
// '*PcbResult' is the number of bytes in the returned '*ppbResult'. It
// is caller's responsibility to Free the returned block.
//
{
DWORD dwErr;
DWORD dwType;
BYTE* pb;
DWORD cb = 0;
*ppbResult = NULL;
*pcbResult = 0;
// Get result buffer size required.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, NULL, &cb );
if (dwErr != 0)
{
return;
}
// Allocate result buffer.
//
pb = Malloc( cb );
if (!pb)
{
return;
}
// Get the result block.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, (LPBYTE )pb, &cb );
if (dwErr == 0)
{
*ppbResult = pb;
*pcbResult = cb;
}
}
VOID
GetRegDword(
IN HKEY hkey,
IN TCHAR* pszName,
OUT DWORD* pdwResult )
// Set '*pdwResult' to the DWORD registry value 'pszName' under key
// 'hkey'. If the value does not exist '*pdwResult' is unchanged.
//
{
DWORD dwErr;
DWORD dwType;
DWORD dwResult;
DWORD cb;
cb = sizeof(DWORD);
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, (LPBYTE )&dwResult, &cb );
if (dwErr == 0 && dwType == REG_DWORD && cb == sizeof(DWORD))
{
*pdwResult = dwResult;
}
}
DWORD
GetRegExpandSz(
IN HKEY hkey,
IN TCHAR* pszName,
OUT TCHAR** ppszResult )
// Set '*ppszResult' to the fully expanded EXPAND_SZ registry value
// 'pszName' under key 'hkey'. If the value does not exist *ppszResult'
// is set to empty string.
//
// Returns 0 if successful or an error code. It is caller's
// responsibility to Free the returned string.
//
{
DWORD dwErr;
DWORD cb;
TCHAR* pszResult;
// Get the unexpanded result string.
//
dwErr = GetRegSz( hkey, pszName, ppszResult );
if (dwErr != 0)
{
return dwErr;
}
// Find out how big the expanded string will be.
//
cb = ExpandEnvironmentStrings( *ppszResult, NULL, 0 );
if (cb == 0)
{
dwErr = GetLastError();
ASSERT( dwErr != 0 );
Free( *ppszResult );
return dwErr;
}
// Allocate a buffer for the expanded string.
//
pszResult = Malloc( (cb + 1) * sizeof(TCHAR) );
if (!pszResult)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
// Expand the environmant variables in the string, storing the result in
// the allocated buffer.
//
cb = ExpandEnvironmentStrings( *ppszResult, pszResult, cb + 1 );
if (cb == 0)
{
dwErr = GetLastError();
ASSERT( dwErr != 0 );
Free( *ppszResult );
Free( pszResult );
return dwErr;
}
Free( *ppszResult );
*ppszResult = pszResult;
return 0;
}
DWORD
GetRegMultiSz(
IN HKEY hkey,
IN TCHAR* pszName,
IN OUT DTLLIST** ppListResult,
IN DWORD dwNodeType )
// Replaces '*ppListResult' with a list containing a node for each string
// in the MULTI_SZ registry value 'pszName' under key 'hkey'. If the
// value does not exist *ppListResult' is replaced with an empty list.
// 'DwNodeType' determines the type of node.
//
// Returns 0 if successful or an error code. It is caller's
// responsibility to destroy the returned list.
//
{
DWORD dwErr;
DWORD dwType;
DWORD cb;
TCHAR* pszzResult;
DTLLIST* pList;
pList = DtlCreateList( 0 );
if (!pList)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
pszzResult = NULL;
// Get result buffer size required.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, NULL, &cb );
if (dwErr != 0)
{
// If can't find the value, just return an empty list. This not
// considered an error.
//
dwErr = 0;
}
else
{
// Allocate result buffer.
//
pszzResult = Malloc( cb );
if (!pszzResult)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
// Get the result string. It's not an error if we can't get it.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, (LPBYTE )pszzResult, &cb );
if (dwErr != 0)
{
// Not an error if can't read the string, though this should
// have been caught by the query retrieving the buffer size.
//
dwErr = 0;
}
else if (dwType == REG_MULTI_SZ)
{
TCHAR* psz;
TCHAR* pszKey;
// Convert the result to a list of strings.
//
pszKey = NULL;
for (psz = pszzResult;
*psz != TEXT('\0');
psz += lstrlen( psz ) + 1)
{
DTLNODE* pNode;
if (dwNodeType == NT_Psz)
{
pNode = CreatePszNode( psz );
}
else
{
if (pszKey)
{
ASSERT(*psz==TEXT('='));
pNode = CreateKvNode( pszKey, psz + 1 );
pszKey = NULL;
}
else
{
pszKey = psz;
continue;
}
}
if (!pNode)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
DtlAddNodeLast( pList, pNode );
}
}
}
}
{
PDESTROYNODE pfunc;
if (dwNodeType == NT_Psz)
{
pfunc = DestroyPszNode;
}
else
{
pfunc = DestroyKvNode;
}
if (dwErr == 0)
{
DtlDestroyList( *ppListResult, pfunc );
*ppListResult = pList;
}
else
{
DtlDestroyList( pList, pfunc );
}
}
Free0( pszzResult );
return 0;
}
DWORD
GetRegSz(
IN HKEY hkey,
IN TCHAR* pszName,
OUT TCHAR** ppszResult )
// Set '*ppszResult' to the SZ registry value 'pszName' under key 'hkey'.
// If the value does not exist *ppszResult' is set to empty string.
//
// Returns 0 if successful or an error code. It is caller's
// responsibility to Free the returned string.
//
{
DWORD dwErr;
DWORD dwType;
DWORD cb = 0;
TCHAR* pszResult;
// Get result buffer size required.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, NULL, &cb );
if (dwErr != 0)
{
cb = sizeof(TCHAR);
}
// Allocate result buffer.
//
pszResult = Malloc( cb );
if (!pszResult)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
*pszResult = TEXT('\0');
*ppszResult = pszResult;
// Get the result string. It's not an error if we can't get it.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, (LPBYTE )pszResult, &cb );
return 0;
}
DWORD
GetRegSzz(
IN HKEY hkey,
IN TCHAR* pszName,
OUT TCHAR** ppszResult )
// Set '*ppszResult to the MULTI_SZ registry value 'pszName' under key
// 'hkey', returned as a null-terminated list of null-terminated strings.
// If the value does not exist, *ppszResult is set to an empty string
// (single null character).
//
// Returns 0 if successful or an error code. It is caller's
// responsibility to Free the returned string.
//
{
DWORD dwErr;
DWORD dwType;
DWORD cb = 0;
TCHAR* pszResult;
// Get result buffer size required.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, NULL, &cb );
if (dwErr != 0)
{
cb = sizeof(TCHAR);
}
// Allocate result buffer.
//
pszResult = Malloc( cb );
if (!pszResult)
return ERROR_NOT_ENOUGH_MEMORY;
*pszResult = TEXT('\0');
*ppszResult = pszResult;
// Get the result string list. It's not an error if we can't get it.
//
dwErr = RegQueryValueEx(
hkey, pszName, NULL, &dwType, (LPBYTE )pszResult, &cb );
return 0;
}
DWORD
RegDeleteTree(
IN HKEY RootKey,
IN TCHAR* SubKeyName )
// Delete registry tree 'SubKeyName' under key 'RootKey'.
//
// (taken from Ted Miller's setup API)
//
{
DWORD d,err;
d = RegDeleteTreeWorker(RootKey,SubKeyName,&err) ? NO_ERROR : err;
if((d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
d = NO_ERROR;
}
if(d == NO_ERROR) {
//
// Delete top-level key
//
d = RegDeleteKey(RootKey,SubKeyName);
if((d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
d = NO_ERROR;
}
}
return(d);
}
BOOL
RegDeleteTreeWorker(
IN HKEY ParentKeyHandle,
IN TCHAR* KeyName,
OUT DWORD* ErrorCode )
// Delete all subkeys of a key whose name and parent's handle was passed
// as parameter. The algorithm used in this function guarantees that the
// maximum number of descendent keys will be deleted.
//
// 'ParentKeyHandle' is a handle to the parent of the key that is
// currently being examined.
//
// 'KeyName' is the name of the key that is currently being examined.
// This name can be an empty string (but not a NULL pointer), and in this
// case ParentKeyHandle refers to the key that is being examined.
//
// 'ErrorCode' is the address to receive a Win32 error code if the
// function fails.
//
// Returns true if successful, false otherwise.
//
// (taken from Ted Miller's setup API)
//
{
HKEY CurrentKeyTraverseAccess;
DWORD iSubKey;
TCHAR SubKeyName[MAX_PATH+1];
DWORD SubKeyNameLength;
FILETIME ftLastWriteTime;
LONG Status;
LONG StatusEnum;
LONG SavedStatus;
//
// Do not accept NULL pointer for ErrorCode
//
if(ErrorCode == NULL) {
return(FALSE);
}
//
// Do not accept NULL pointer for KeyName.
//
if(KeyName == NULL) {
*ErrorCode = ERROR_INVALID_PARAMETER;
return(FALSE);
}
//
// Open a handle to the key whose subkeys are to be deleted.
// Since we need to delete its subkeys, the handle must have
// KEY_ENUMERATE_SUB_KEYS access.
//
Status = RegOpenKeyEx(
ParentKeyHandle,
KeyName,
0,
KEY_ENUMERATE_SUB_KEYS | DELETE,
&CurrentKeyTraverseAccess
);
if(Status != ERROR_SUCCESS) {
//
// If unable to enumerate the subkeys, return error.
//
*ErrorCode = Status;
return(FALSE);
}
//
// Traverse the key
//
iSubKey = 0;
SavedStatus = ERROR_SUCCESS;
do {
//
// Get the name of a subkey
//
SubKeyNameLength = sizeof(SubKeyName) / sizeof(TCHAR);
StatusEnum = RegEnumKeyEx(
CurrentKeyTraverseAccess,
iSubKey,
SubKeyName,
&SubKeyNameLength,
NULL,
NULL,
NULL,
&ftLastWriteTime
);
if(StatusEnum == ERROR_SUCCESS) {
//
// Delete all children of the subkey.
// Just assume that the children will be deleted, and don't check
// for failure.
//
RegDeleteTreeWorker(CurrentKeyTraverseAccess,SubKeyName,&Status);
//
// Now delete the subkey, and check for failure.
//
Status = RegDeleteKey(CurrentKeyTraverseAccess,SubKeyName);
//
// If unable to delete the subkey, then save the error code.
// Note that the subkey index is incremented only if the subkey
// was not deleted.
//
if(Status != ERROR_SUCCESS) {
iSubKey++;
SavedStatus = Status;
}
} else {
//
// If unable to get a subkey name due to ERROR_NO_MORE_ITEMS,
// then the key doesn't have subkeys, or all subkeys were already
// enumerated. Otherwise, an error has occurred, so just save
// the error code.
//
if(StatusEnum != ERROR_NO_MORE_ITEMS) {
SavedStatus = StatusEnum;
}
}
//if((StatusEnum != ERROR_SUCCESS ) && (StatusEnum != ERROR_NO_MORE_ITEMS)) {
// printf( "RegEnumKeyEx() failed, Key Name = %ls, Status = %d, iSubKey = %d \n",KeyName,StatusEnum,iSubKey);
//}
} while(StatusEnum == ERROR_SUCCESS);
//
// Close the handle to the key whose subkeys were deleted, and return
// the result of the operation.
//
RegCloseKey(CurrentKeyTraverseAccess);
if(SavedStatus != ERROR_SUCCESS) {
*ErrorCode = SavedStatus;
return(FALSE);
}
return(TRUE);
}
BOOL
RegValueExists(
IN HKEY hkey,
IN TCHAR* pszValue )
// Returns true if 'pszValue' is an existing value under 'hkey', false if
// not.
//
{
DWORD dwErr;
DWORD dwType;
DWORD cb = 0;
dwErr = RegQueryValueEx( hkey, pszValue, NULL, &dwType, NULL, &cb );
return !!(dwErr == 0);
}
DWORD
SetRegDword(
IN HKEY hkey,
IN TCHAR* pszName,
IN DWORD dwValue )
// Set registry value 'pszName' under key 'hkey' to REG_DWORD value
// 'dwValue'.
//
// Returns 0 is successful or an error code.
//
{
return RegSetValueEx(
hkey, pszName, 0, REG_DWORD, (LPBYTE )&dwValue, sizeof(dwValue) );
}
DWORD
SetRegMultiSz(
IN HKEY hkey,
IN TCHAR* pszName,
IN DTLLIST* pListValues,
IN DWORD dwNodeType )
// Set registry value 'pszName' under key 'hkey' to a REG_MULTI_SZ value
// containing the strings in the Psz list 'pListValues'. 'DwNodeType'
// determines the type of node.
//
// Returns 0 is successful or an error code.
//
{
DWORD dwErr;
DWORD cb;
DTLNODE* pNode;
TCHAR* pszzValues;
TCHAR* pszValue;
// Count up size of MULTI_SZ buffer needed.
//
cb = sizeof(TCHAR);
for (pNode = DtlGetFirstNode( pListValues );
pNode;
pNode = DtlGetNextNode( pNode ))
{
if (dwNodeType == NT_Psz)
{
TCHAR* psz;
psz = (TCHAR* )DtlGetData( pNode );
ASSERT(psz);
cb += (lstrlen( psz ) + 1) * sizeof(TCHAR);
}
else
{
KEYVALUE* pkv;
ASSERT(dwNodeType==NT_Kv);
pkv = (KEYVALUE* )DtlGetData( pNode );
ASSERT(pkv);
ASSERT(pkv->pszKey);
ASSERT(pkv->pszValue);
cb += (lstrlen( pkv->pszKey ) + 1
+ 1 + lstrlen( pkv->pszValue ) + 1) * sizeof(TCHAR);
}
}
if (cb == sizeof(TCHAR))
{
cb += sizeof(TCHAR);
}
// Allocate MULTI_SZ buffer.
//
pszzValues = Malloc( cb );
if (!pszzValues)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
// Fill MULTI_SZ buffer from list.
//
if (cb == 2 * sizeof(TCHAR))
{
pszzValues[ 0 ] = pszzValues[ 1 ] = TEXT('\0');
}
else
{
pszValue = pszzValues;
for (pNode = DtlGetFirstNode( pListValues );
pNode;
pNode = DtlGetNextNode( pNode ))
{
if (dwNodeType == NT_Psz)
{
TCHAR* psz;
psz = (TCHAR* )DtlGetData( pNode );
ASSERT(psz);
lstrcpy( pszValue, psz );
pszValue += lstrlen( pszValue ) + 1;
}
else
{
KEYVALUE* pkv;
pkv = (KEYVALUE* )DtlGetData( pNode );
ASSERT(pkv);
ASSERT(pkv->pszKey);
ASSERT(pkv->pszValue);
lstrcpy( pszValue, pkv->pszKey );
pszValue += lstrlen( pszValue ) + 1;
*pszValue = TEXT('=');
++pszValue;
lstrcpy( pszValue, pkv->pszValue );
pszValue += lstrlen( pszValue ) + 1;
}
}
*pszValue = TEXT('\0');
}
/* Set registry value from MULTI_SZ buffer.
*/
dwErr = RegSetValueEx(
hkey, pszName, 0, REG_MULTI_SZ, (LPBYTE )pszzValues, cb );
Free( pszzValues );
return dwErr;
}
DWORD
SetRegSz(
IN HKEY hkey,
IN TCHAR* pszName,
IN TCHAR* pszValue )
// Set registry value 'pszName' under key 'hkey' to a REG_SZ value
// 'pszValue'.
//
// Returns 0 is successful or an error code.
//
{
TCHAR* psz;
if (pszValue)
{
psz = pszValue;
}
else
{
psz = TEXT("");
}
return
RegSetValueEx(
hkey, pszName, 0, REG_SZ,
(LPBYTE )psz, (lstrlen( psz ) + 1) * sizeof(TCHAR) );
}
DWORD
SetRegSzz(
IN HKEY hkey,
IN TCHAR* pszName,
IN TCHAR* pszValue )
// Set registry value 'pszName' under key 'hkey' to a REG_MULTI_SZ value
// 'pszValue'.
//
// Returns 0 is successful or an error code.
//
{
DWORD cb;
TCHAR* psz;
cb = sizeof(TCHAR);
if (!pszValue)
{
psz = TEXT("");
}
else
{
INT nLen;
for (psz = pszValue; *psz; psz += nLen)
{
nLen = lstrlen( psz ) + 1;
cb += nLen * sizeof(TCHAR);
}
psz = pszValue;
}
return RegSetValueEx( hkey, pszName, 0, REG_MULTI_SZ, (LPBYTE )psz, cb );
}