/*++ 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); }