windows-nt/Source/XPSP1/NT/windows/appcompat/windowsupdate/installer/registry.cpp
2020-09-26 16:20:57 +08:00

1398 lines
28 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
Registry.cpp
Abstract:
Implementation of the registry
wrapper class.
Notes:
Unicode only.
History:
01/29/2001 rparsons Created
03/02/2001 rparsons Major overhaul
--*/
#include "registry.h"
/*++
Routine Description:
Allocates memory from the heap
Arguments:
dwBytes - Number of bytes to allocate
This value will be multiplied
by the size of a WCHAR
Return Value:
A pointer to a block of memory
--*/
LPVOID
CRegistry::Malloc(
IN SIZE_T dwBytes
)
{
LPVOID lpReturn = NULL;
lpReturn = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwBytes*sizeof(WCHAR));
return (lpReturn);
}
/*++
Routine Description:
Frees memory from the heap
Arguments:
lpMem - Pointer to a block of memory to free
Return Value:
None
--*/
void
CRegistry::Free(
IN LPVOID lpMem
)
{
if (NULL != lpMem) {
HeapFree(GetProcessHeap(), 0, lpMem);
}
return;
}
/*++
Routine Description:
Creates the specified key or opens it if it
already exists
Arguments:
hKey - Handle to a predefined key
lpwSubKey - Path to the sub key to open
samDesired - The desired access rights
Return Value:
A handle to the key on success, NULL otherwise
--*/
HKEY
CRegistry::CreateKey(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN REGSAM samDesired
)
{
HKEY hReturnKey = NULL;
if (!hKey || !lpwSubKey || !samDesired) {
return NULL;
}
RegCreateKeyEx(hKey,
lpwSubKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
samDesired,
NULL,
&hReturnKey,
0);
return (hReturnKey);
}
/*++
Routine Description:
Opens the specified key
Arguments:
hKey - Handle to a predefined key
lpwSubKey - Path to the sub key to open
samDesired - The desired access rights
Return Value:
A handle to the key on success, NULL otherwise
--*/
HKEY
CRegistry::OpenKey(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN REGSAM samDesired
)
{
HKEY hReturnKey = NULL;
if (!hKey || !lpwSubKey || !samDesired) {
return NULL;
}
RegOpenKeyEx(hKey,
lpwSubKey,
0,
samDesired,
&hReturnKey);
return (hReturnKey);
}
/*++
Routine Description:
Closes the specified key handle
Arguments:
hKey - Handle of the key to close
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::CloseKey(
IN HKEY hKey
)
{
LONG lResult = 0;
lResult = RegCloseKey(hKey);
return (lResult == ERROR_SUCCESS ? TRUE : FALSE);
}
/*++
Routine Description:
Gets a size for a specified value name
Arguments:
hKey - Open key handle (not predefined)
lpwValueName - Name of data value
lpType - Receives the type of data
Return Value:
Number of bytes the value occupies
--*/
DWORD
CRegistry::GetStringSize(
IN HKEY hKey,
IN LPCWSTR lpwValueName,
OUT LPDWORD lpType OPTIONAL
)
{
DWORD cbSize = 0;
if (!hKey || !lpwValueName) {
return 0;
}
RegQueryValueEx(hKey,
lpwValueName,
0,
lpType,
NULL,
&cbSize);
return (cbSize);
}
/*++
Routine Description:
Retrieves a string value from the registry
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of data value
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
The requested value data on success, NULL otherwise
--*/
LPWSTR
CRegistry::GetString(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN BOOL fPredefined
)
{
DWORD cbSize = 0;
BOOL fResult = FALSE;
LONG lResult = 0;
LPWSTR lpwReturn = NULL;
HKEY hLocalKey = NULL;
if (!hKey || !lpwValueName) {
return NULL;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwSubKey, KEY_QUERY_VALUE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Get the required string size and allocate
// memory for the actual call
//
cbSize = this->GetStringSize(hLocalKey, lpwValueName, NULL);
if (0 == cbSize) {
__leave;
}
lpwReturn = (LPWSTR) this->Malloc(cbSize*sizeof(WCHAR));
if (NULL == lpwReturn) {
__leave;
}
//
// Make the actual call to get the data
//
lResult = RegQueryValueEx(hLocalKey,
lpwValueName,
0,
NULL,
(LPBYTE) lpwReturn,
&cbSize);
if (ERROR_SUCCESS != lResult) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
}
return (fResult ? lpwReturn : NULL);
}
/*++
Routine Description:
Retrieves a DWORD value from the registry
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of data value
lpdwData - Pointer to store the value
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise.
--*/
BOOL
CRegistry::GetDword(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN LPDWORD lpdwData,
IN BOOL fPredefined
)
{
DWORD cbSize = MAX_PATH;
BOOL fResult = FALSE;
LONG lResult = 0;
HKEY hLocalKey = NULL;
if (!hKey || !lpwValueName || !lpdwData) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwSubKey, KEY_QUERY_VALUE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Make the call to get the data
//
lResult = RegQueryValueEx(hLocalKey,
lpwValueName,
0,
NULL,
(LPBYTE) lpdwData,
&cbSize);
if (ERROR_SUCCESS != lResult) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} //finally
return (fResult);
}
/*++
Routine Description:
Sets a DWORD value in the registry
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of data value
dwData - Value to store
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::SetDword(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN DWORD dwData,
IN BOOL fPredefined
)
{
LONG lResult = 0;
BOOL fResult = FALSE;
HKEY hLocalKey = NULL;
if (!hKey || !lpwValueName) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwSubKey, KEY_SET_VALUE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Make the call to set the data
//
lResult = RegSetValueEx(hLocalKey,
lpwValueName,
0,
REG_DWORD,
(LPBYTE) &dwData,
sizeof(DWORD));
if (ERROR_SUCCESS != lResult) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Sets a string value in the registry
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of data value
lpwData - Value to store
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise.
--*/
BOOL
CRegistry::SetString(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN LPWSTR lpwData,
IN BOOL fPredefined
)
{
HKEY hLocalKey = NULL;
BOOL fResult = FALSE;
LONG lResult = 0;
if (!hKey || !lpwValueName) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwSubKey, KEY_SET_VALUE);
if (NULL == hLocalKey) {
__leave;
}
}
lResult = RegSetValueEx(hLocalKey,
lpwValueName,
0,
REG_SZ,
(LPBYTE) lpwData,
(wcslen(lpwData)+1)*sizeof(WCHAR));
if (ERROR_SUCCESS != lResult) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Deletes the specified value from the registry
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of the value to delete
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise.
--*/
BOOL
CRegistry::DeleteRegistryString(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN BOOL fPredefined
)
{
HKEY hLocalKey = NULL;
BOOL fResult = FALSE;
LONG lResult = 0;
if (!hKey || !lpwValueName) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwSubKey, KEY_WRITE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Delete the value
//
lResult = RegDeleteValue(hLocalKey,
lpwValueName);
if (ERROR_SUCCESS != lResult) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Deletes the specified key from the registry
(At this time, subkeys are not allowed)
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwSubKeyName - Name of the subkey
fPredefined - Flag to indicate if a predefined
key handle was passed
fFlush - Flag to indicate if we should flush the key
Return Value:
TRUE on success, FALSE otherwise.
--*/
BOOL
CRegistry::DeleteRegistryKey(
IN HKEY hKey,
IN LPCWSTR lpwKey,
IN LPCWSTR lpwSubKeyName,
IN BOOL fPredefined,
IN BOOL fFlush
)
{
HKEY hLocalKey = NULL;
BOOL fResult = FALSE;
LONG lResult = 0;
if (!hKey) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey, lpwKey, KEY_WRITE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Delete the value
//
lResult = RegDeleteKey(hLocalKey,
lpwSubKeyName);
if (ERROR_SUCCESS != lResult) {
__leave;
}
if (fFlush) {
RegFlushKey(hLocalKey);
}
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Adds a string to a REG_MULTI_SZ key
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of the value
lpwEntry - Name of entry to add
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::AddStringToMultiSz(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN LPCWSTR lpwEntry,
IN BOOL fPredefined
)
{
int nLen = 0;
HKEY hLocalKey = NULL;
DWORD cbSize = 0, dwType = 0;
LPWSTR lpwNew = NULL, lpwData = NULL;
BOOL fResult = FALSE;
LONG lResult = 0;
if (!hKey || !lpwEntry) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey,
lpwSubKey,
KEY_QUERY_VALUE | KEY_WRITE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Get the required string size and allocate
// memory for the actual call
//
cbSize = this->GetStringSize(hLocalKey, lpwValueName, &dwType);
if ((0 == cbSize) || (dwType != REG_MULTI_SZ)) {
__leave;
}
lpwData = (LPWSTR) this->Malloc(cbSize * sizeof(WCHAR));
if (NULL == lpwData) {
__leave;
}
//
// Get the actual data
//
lResult = RegQueryValueEx(hLocalKey,
lpwValueName,
0,
0,
(LPBYTE) lpwData,
&cbSize);
if (ERROR_SUCCESS != lResult) {
__leave;
}
lpwNew = lpwData;
while (*lpwNew) {
nLen = wcslen(lpwNew);
//
// Move to the next string
//
lpwNew += nLen + 1;
//
// At end of list of strings, append here
//
if (!*lpwNew) {
wcscpy(lpwNew, lpwEntry);
lpwNew += wcslen(lpwEntry) + 1;
*lpwNew = 0;
nLen = this->ListStoreLen(lpwData);
lResult = RegSetValueEx(hLocalKey,
lpwValueName,
0,
REG_MULTI_SZ,
(const BYTE*) lpwData,
nLen);
if (lResult != ERROR_SUCCESS) {
__leave;
} else {
fResult = TRUE;
}
break;
}
}
} // try
__finally {
if (lpwData) {
this->Free(lpwData);
}
if (hLocalKey) {
RegCloseKey(hKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Removes a string from a REG_MULTI_SZ key
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwValueName - Name of the value
lpwEntry - Name of entry to remove
fPredefined - Flag to indicate if a predefined
key handle was passed
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::RemoveStringFromMultiSz(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwValueName,
IN LPCWSTR lpwEntry,
IN BOOL fPredefined
)
{
LPBYTE lpBuf = NULL;
HKEY hLocalKey = NULL;
WCHAR *pFirst = NULL;
WCHAR *pSecond = NULL;
DWORD dwType = 0, cbSize = 0;
DWORD dwNameLen = 0, dwNameOffset = 0, dwSize = 0;
BOOL fResult = FALSE;
LONG lResult = 0;
if (!hKey || !lpwEntry) {
return FALSE;
}
__try {
hLocalKey = hKey;
if (fPredefined) {
//
// We'll need to open the key for them
//
hLocalKey = this->OpenKey(hKey,
lpwSubKey,
KEY_QUERY_VALUE | KEY_WRITE);
if (NULL == hLocalKey) {
__leave;
}
}
//
// Get the required string size and allocate
// memory for the actual call
//
cbSize = this->GetStringSize(hLocalKey, lpwValueName, &dwType);
if ((0 == cbSize) || (dwType != REG_MULTI_SZ)) {
__leave;
}
lpBuf = (LPBYTE) this->Malloc(cbSize * sizeof(WCHAR));
if (NULL == lpBuf) {
__leave;
}
//
// Get the actual data
//
lResult = RegQueryValueEx(hLocalKey,
lpwValueName,
0,
0,
(LPBYTE) lpBuf,
&cbSize);
if (ERROR_SUCCESS != lResult) {
__leave;
}
//
// Attempt to find the string we're looking for
//
for (pFirst = (WCHAR*) lpBuf; *pFirst; pFirst += dwNameLen) {
dwNameLen = wcslen(pFirst) + 1; // Length of name plus NULL
dwNameOffset += dwNameLen;
//
// Check for a match
//
if (_wcsicmp(pFirst, lpwEntry) == 0) {
dwSize = wcslen(pFirst) + 1; // Length of name
pSecond = (WCHAR*) pFirst + dwSize;
while(*pSecond)
while(*pSecond)
*pFirst++ = *pSecond++;
*pFirst++ = *pSecond++;
*pFirst = '\0';
//
// Found a match - update the key
//
lResult = RegSetValueEx(hLocalKey,
lpwValueName,
0,
REG_MULTI_SZ,
(const BYTE*) lpBuf,
cbSize -
(dwSize*sizeof(WCHAR)));
if (lResult != ERROR_SUCCESS) {
__leave;
} else {
fResult = TRUE;
}
break;
}
}
} // try
__finally {
if (lpBuf) {
this->Free(lpBuf);
}
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Determines if the specified subkey is present
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
Return Value:
TRUE if it's present, FALSE otherwise.
--*/
BOOL
CRegistry::IsRegistryKeyPresent(
IN HKEY hKey,
IN LPCWSTR lpwSubKey
)
{
BOOL fResult = FALSE;
HKEY hLocalKey = NULL;
if (!hKey || !lpwSubKey) {
return FALSE;
}
__try {
hLocalKey = hKey;
//
// Check for the presence of the key
//
hLocalKey = this->OpenKey(hKey,
lpwSubKey,
KEY_QUERY_VALUE);
if (NULL == hLocalKey) {
__leave;
} else {
fResult = TRUE;
}
} // try
__finally {
if (hLocalKey)
RegCloseKey(hLocalKey);
} // finally
return (fResult);
}
/*++
Routine Description:
Restores the specified registry key
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwFileName - Path & name of the file to restore
fGrantPrivs - Flag to indicate if we should grant
privileges to the user
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::RestoreKey(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwFileName,
IN BOOL fGrantPrivs
)
{
BOOL fResult = FALSE;
HKEY hLocalKey = NULL;
LONG lResult = 0;
if (!hKey || !lpwSubKey || !lpwFileName) {
return FALSE;
}
__try {
//
// If necessary, grant privileges for the restore
//
if (fGrantPrivs) {
this->ModifyTokenPrivilege(L"SeRestorePrivilege", TRUE);
}
lResult = RegCreateKeyEx(hKey,
lpwSubKey,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hLocalKey,
0);
if (ERROR_SUCCESS != lResult) {
__leave;
}
//
// Restore the key from the specified file
//
lResult = RegRestoreKey(hLocalKey,
lpwFileName,
REG_FORCE_RESTORE);
if (ERROR_SUCCESS != lResult) {
__leave;
}
RegFlushKey(hLocalKey);
fResult = TRUE;
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
if (fGrantPrivs) {
this->ModifyTokenPrivilege(L"SeRestorePrivilege", FALSE);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Makes a backup of the specified registry key
Arguments:
hKey - Predefined or open key handle
lpwSubKey - Path to the subkey
lpwFileName - Path & name of the file to restore
fGrantPrivs - Flag to indicate if we should grant
privileges to the user
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::BackupRegistryKey(
IN HKEY hKey,
IN LPCWSTR lpwSubKey,
IN LPCWSTR lpwFileName,
IN BOOL fGrantPrivs
)
{
BOOL fResult = FALSE;
HKEY hLocalKey = NULL;
DWORD dwDisposition = 0;
DWORD dwLastError = 0;
LONG lResult = 0;
if (!hKey || !lpwSubKey || !lpwFileName) {
return FALSE;
}
__try {
if (fGrantPrivs) {
ModifyTokenPrivilege(L"SeBackupPrivilege", TRUE);
}
lResult = RegCreateKeyEx(hKey,
lpwSubKey,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
KEY_QUERY_VALUE, // this argument is ignored
NULL,
&hLocalKey,
&dwDisposition);
if (ERROR_SUCCESS != lResult) {
__leave;
}
//
// Verify that we didn't create a new key
//
if (REG_CREATED_NEW_KEY == dwDisposition) {
__leave;
}
//
// Save the key to the file
//
lResult = RegSaveKey(hLocalKey,
lpwFileName,
NULL);
if (ERROR_SUCCESS != lResult) {
__leave;
} else {
fResult = TRUE;
}
} // try
__finally {
if (hLocalKey) {
RegCloseKey(hLocalKey);
}
if (fGrantPrivs) {
this->ModifyTokenPrivilege(L"SeBackupPrivilege", FALSE);
}
} // finally
return (fResult);
}
/*++
Routine Description:
Helper function that calculates the size of MULTI_SZ string.
Arguments:
lpwList - MULTI_SZ string.
Return Value:
Size of the string.
--*/
int
CRegistry::ListStoreLen(
IN LPWSTR lpwList
)
{
int nStoreLen = 2, nLen = 0;
if (NULL == lpwList) {
return 0;
}
while (*lpwList) {
nLen = wcslen(lpwList) + 1;
nStoreLen += nLen * 2;
lpwList += nLen;
}
return (nStoreLen);
}
/*++
Routine Description:
Enables or disables a specified privilege
Arguments:
lpwPrivilege - The name of the privilege
fEnable - A flag to indicate if the
privilege should be enabled
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
CRegistry::ModifyTokenPrivilege(
IN LPCWSTR lpwPrivilege,
IN BOOL fEnable
)
{
HANDLE hToken = NULL;
LUID luid;
BOOL fResult = FALSE;
TOKEN_PRIVILEGES tp;
if (NULL == lpwPrivilege) {
return FALSE;
}
__try {
//
// Get a handle to the access token associated with the current process
//
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken);
if (NULL == hToken) {
__leave;
}
//
// Obtain a LUID for the specified privilege
//
if (!LookupPrivilegeValue(NULL, lpwPrivilege, &luid)) {
__leave;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
//
// Modify the access token
//
if (!AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
NULL,
NULL)) {
__leave;
}
fResult = TRUE;
} // try
__finally {
if (hToken) {
CloseHandle(hToken);
}
} // finally
return (fResult);
}