//Copyright (c) 1998 - 1999 Microsoft Corporation /*-------------------------------------------------------------------------------------------------------- * * Module Name: * * Registry.cpp * * Abstract: * * Registry.cpp: implementation of the CRegistry class. * This class helps with registry by allocating memory by itself * As a result caller must copy the pointer returned by Get functions * immediately. * * * * Author: * * Makarand Patwardhan - April 9, 1997 * * -------------------------------------------------------------------------------------------------------*/ #include "stdafx.h" #include "Registry.h" /*-------------------------------------------------------------------------------------------------------- * Constructor * -------------------------------------------------------------------------------------------------------*/ CRegistry::CRegistry() { m_pMemBlock = NULL; m_hKey = NULL; m_iEnumIndex = -1; m_iEnumValueIndex = -1; #ifdef DBG m_dwSizeDebugOnly = 0; #endif } CRegistry::CRegistry(HKEY hKey) { m_pMemBlock = NULL; m_hKey = hKey; m_iEnumIndex = -1; m_iEnumValueIndex = -1; } /*-------------------------------------------------------------------------------------------------------- * Destructor * -------------------------------------------------------------------------------------------------------*/ CRegistry::~CRegistry() { if (m_hKey != NULL) { RegCloseKey(m_hKey); m_hKey = NULL; } Release(); } /*-------------------------------------------------------------------------------------------------------- * void Allocate (DWORD dwSize) * This private function is used for allocating the memory for * reading registry * returns the pointer to memory allocated. * -------------------------------------------------------------------------------------------------------*/ void *CRegistry::Allocate (DWORD dwSize) { if (m_pMemBlock) Release(); m_pMemBlock = new BYTE[dwSize]; #ifdef DBG // remember the size of the block to be allocated. m_dwSizeDebugOnly = dwSize; #endif return m_pMemBlock; } /*-------------------------------------------------------------------------------------------------------- * void Release () * This private function is used for releasing internal memory block * -------------------------------------------------------------------------------------------------------*/ void CRegistry::Release () { if (m_pMemBlock) { #ifdef DBG // fistly fill up the block we allocated previously with garbage. // so that if anybody is using this block, it is more lilely to // catch the bug. FillMemory(m_pMemBlock, m_dwSizeDebugOnly, 'c'); m_dwSizeDebugOnly = 0; #endif delete [] m_pMemBlock; } m_pMemBlock = 0; } ///*-------------------------------------------------------------------------------------------------------- //* DWORD CRegistry::CreateKey(HKEY hKey, LPCTSTR lpSubKey, REGSAM access /*= KEY_ALL_ACCESS*/, DWORD *pDisposition /*= NULL*/, LPSECURITY_ATTRIBUTES lpSecAttr /* = NULL */) //* opens/creates the key specified. before attempting any operation on any key/value. this function //* must be called. //* hKey - hive //* lpSubKey - Path of the key in the format _T("SYSTEM\\CurrentControlSet\\Control\\Terminal Server") //* access - access desired. like REG_READ, REG_WRITE.. //* RETURNS error code. //* -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::CreateKey(HKEY hKey, LPCTSTR lpSubKey, REGSAM access /*= KEY_ALL_ACCESS*/, DWORD *pDisposition /*= NULL*/, LPSECURITY_ATTRIBUTES lpSecAttr /* = NULL */) { ASSERT(lpSubKey); ASSERT(*lpSubKey != '\\'); // security descriptor should be null or it should be a valid one. ASSERT(!lpSecAttr || IsValidSecurityDescriptor(lpSecAttr->lpSecurityDescriptor)); ASSERT(lpSubKey); ASSERT(*lpSubKey != '\\'); if (m_hKey != NULL) { RegCloseKey(m_hKey); m_hKey = NULL; } DWORD dwDisposition; LONG lResult = RegCreateKeyEx( hKey, // handle of an open key lpSubKey, // address of subkey name 0, // reserved NULL, // address of class string REG_OPTION_NON_VOLATILE , // special options flag access, // desired security access lpSecAttr, // address of key security structure &m_hKey, // address of buffer for opened handle &dwDisposition // address of disposition value buffer ); if (lResult != ERROR_SUCCESS) { m_hKey = NULL; } if (pDisposition) *pDisposition = dwDisposition; return lResult; } /*-------------------------------------------------------------------------------------------------------- * DWORD OpenKey(HKEY hKey, LPCTSTR lpSubKey, REGSAM access) () * opens the key specified. before attempting any operation on any key/value. this function * must be called. * hKey - hive * lpSubKey - Path of the key in the format _T("SYSTEM\\CurrentControlSet\\Control\\Terminal Server") * access - access desired. like REG_READ, REG_WRITE.. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::OpenKey(HKEY hKey, LPCTSTR lpSubKey, REGSAM access /*= KEY_ALL_ACCESS*/, LPCTSTR lpMachineName /* = NULL */) { LONG lResult; ASSERT(lpSubKey); ASSERT(*lpSubKey != '\\'); LPTSTR szCompName = NULL; if (lpMachineName) { // if remote name is specified, hkey must be one of following. ASSERT(hKey == HKEY_LOCAL_MACHINE || hKey == HKEY_USERS || hKey == HKEY_PERFORMANCE_DATA); szCompName = new TCHAR[_tcslen(lpMachineName) + 3]; if (!szCompName) return ERROR_OUTOFMEMORY; _tcscpy(szCompName, _T("")); if (*lpMachineName != '\\') { ASSERT(*(lpMachineName + 1) != '\\'); _tcscpy(szCompName, _T("\\\\")); } _tcscat(szCompName, lpMachineName); // now connect to the remote computer. lResult = RegConnectRegistry (szCompName, hKey, &hKey); if (ERROR_SUCCESS != lResult) { delete [] szCompName; return lResult; } } if (m_hKey != NULL) { RegCloseKey(m_hKey); m_hKey = NULL; } lResult = RegOpenKeyEx( hKey, // handle of open key lpSubKey, // address of name of subkey to open 0 , // reserved access, // security access mask &m_hKey // address of handle of open key ); if (lResult != ERROR_SUCCESS) { m_hKey = NULL; } // if we opened remote registry.. lets close the top level key if (szCompName) { RegCloseKey(hKey); delete [] szCompName; } return lResult; } DWORD CRegistry::DeleteValue (LPCTSTR lpValue) { ASSERT(lpValue); ASSERT(m_hKey); return RegDeleteValue(m_hKey, lpValue); } DWORD CRegistry::RecurseDeleteKey (LPCTSTR lpSubKey) { ASSERT(lpSubKey); ASSERT(m_hKey); CRegistry reg; DWORD dwError = reg.OpenKey(m_hKey, lpSubKey); if (dwError != ERROR_SUCCESS) return dwError; LPTSTR lpChildKey; DWORD dwSize; // we needn't/shouldn't use GetNextSubKey in this here // as we are deleting the key during the loop. while (ERROR_SUCCESS == reg.GetFirstSubKey(&lpChildKey, &dwSize)) { VERIFY(reg.RecurseDeleteKey(lpChildKey) == ERROR_SUCCESS); } return RegDeleteKey(m_hKey, lpSubKey); } /*-------------------------------------------------------------------------------------------------------- * DWORD ReadReg(LPCTSTR lpValue, LPBYTE *lppbyte, DWORD *pdw, DWORD dwDatatype) * Reads the registry used internally. * LPCTSTR lpValue - value to be read. * LPBYTE *lppbyte - address of the lpbyte at which to place the output buffer. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * dword datatype - datatype you are expecting. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::ReadReg(LPCTSTR lpValue, LPBYTE *lppbyte, DWORD *pdw, DWORD dwDatatype) { ASSERT(lpValue); ASSERT(lppbyte); ASSERT(pdw); ASSERT(m_hKey != NULL); *pdw = 0; DWORD dwType; DWORD lResult = RegQueryValueEx( m_hKey, // handle of key to query lpValue, // address of name of value to query 0, // reserved &dwType, // address of buffer for value type 0, // address of data buffer pdw // address of data buffer size ); if (lResult == ERROR_SUCCESS) { ASSERT(dwType == dwDatatype || dwType == REG_EXPAND_SZ); if (0 == Allocate(*pdw)) return ERROR_OUTOFMEMORY; lResult = RegQueryValueEx( m_hKey, // handle of key to query lpValue, // address of name of value to query 0, // reserved &dwType, // address of buffer for value type m_pMemBlock, // address of data buffer pdw // address of data buffer size ); ASSERT (ERROR_MORE_DATA != lResult); if (lResult == ERROR_SUCCESS) *lppbyte = m_pMemBlock; } return lResult; } /*-------------------------------------------------------------------------------------------------------- * DWORD ReadRegString(LPCTSTR lpValue, LPTSTR *lppStr, DWORD *pdw) * Reads A string (REG_SZ) from the registry * LPCTSTR lpValue value to be read. * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::ReadRegString(LPCTSTR lpValue, LPTSTR *lppStr, DWORD *pdw) { return ReadReg(lpValue, (LPBYTE *)lppStr, pdw, REG_SZ); } /*-------------------------------------------------------------------------------------------------------- * DWORD ReadRegDWord(LPCTSTR lpValue, DWORD *pdw) * Reads A string (REG_SZ) from the registry * LPCTSTR lpValue value to be read. * DWORD *pdw - address of dword in which the read dword returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::ReadRegDWord(LPCTSTR lpValue, DWORD *pdw) { ASSERT(pdw); DWORD dwSize; LPBYTE pByte; DWORD dwReturn = ReadReg(lpValue, &pByte, &dwSize, REG_DWORD); ASSERT(dwReturn != ERROR_SUCCESS || dwSize == sizeof(DWORD)); if (dwReturn == ERROR_SUCCESS) *pdw = * LPDWORD(pByte); return dwReturn; } /*-------------------------------------------------------------------------------------------------------- * DWORD ReadRegMultiString(LPCTSTR lpValue, LPTSTR *lppStr, DWORD *pdw) * Reads A string (REG_MULTI_SZ) from the registry * LPCTSTR lpValue value to be read. * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::ReadRegMultiString(LPCTSTR lpValue, LPTSTR *lppStr, DWORD *pdw) { return ReadReg(lpValue, (LPBYTE *)lppStr, pdw, REG_MULTI_SZ); } /*-------------------------------------------------------------------------------------------------------- * DWORD ReadRegBinary(LPCTSTR lpValue, LPBYTE *lppByte, DWORD *pdw) * Reads A string (REG_MULTI_SZ) from the registry * LPCTSTR lpValue value to be read. * LPBYTE *lppByte - address of LPBYTE in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::ReadRegBinary(LPCTSTR lpValue, LPBYTE *lppByte, DWORD *pdw) { return ReadReg(lpValue, lppByte, pdw, REG_BINARY); } /*-------------------------------------------------------------------------------------------------------- * DWORD GetFirstSubKey(LPTSTR *lppStr, DWORD *pdw) * Reads a first subkey for the key * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * used to enumerate the registry. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::GetFirstSubKey(LPTSTR *lppStr, DWORD *pdw) { ASSERT(lppStr); ASSERT(pdw); m_iEnumIndex = 0; return GetNextSubKey(lppStr, pdw); } /*-------------------------------------------------------------------------------------------------------- * DWORD GetNextSubKey(LPTSTR *lppStr, DWORD *pdw * Reads the next subkey for the key * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * used to enumerate the registry. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::GetNextSubKey(LPTSTR *lppStr, DWORD *pdw) { ASSERT(lppStr); ASSERT(pdw); ASSERT(m_hKey != NULL); ASSERT(m_iEnumIndex >= 0); // must call GetFirstSubKey first. *pdw = 1024; if (0 == Allocate(*pdw * sizeof(TCHAR))) return ERROR_NOT_ENOUGH_MEMORY; LONG lResult = RegEnumKeyEx( m_hKey, // handle of key to enumerate m_iEnumIndex, // index of subkey to enumerate (LPTSTR)m_pMemBlock, // address of buffer for subkey name pdw, // address for size of subkey buffer 0, // reserved NULL, // address of buffer for class string NULL, // address for size of class buffer NULL // address for time key last written to ); (*pdw)++; // since null is not included in the size. if (ERROR_NO_MORE_ITEMS == lResult) return lResult; m_iEnumIndex++; if (lResult == ERROR_SUCCESS) *lppStr = (LPTSTR)m_pMemBlock; return lResult; } /*-------------------------------------------------------------------------------------------------------- * DWORD GetFirstValue(LPTSTR *lppStr, DWORD *pdw, DWORD *pDataType) * Reads a first value for the key * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * used to enumerate the registry. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * DWORD *pDataType - datatype of the value is returned in this one. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::GetFirstValue(LPTSTR *lppStr, DWORD *pdw, DWORD *pDataType) { ASSERT(lppStr); ASSERT(pdw); ASSERT(pDataType); m_iEnumValueIndex = 0; return GetNextValue(lppStr, pdw, pDataType); } /*-------------------------------------------------------------------------------------------------------- * DWORD GetNextValue(LPTSTR *lppStr, DWORD *pdw, DWORD *pDataType) * Reads a next value for the key * LPTSTR *lppStr - address of LPTSTR in which resultant buffer is returned. caller must copy * the buffer to immediately. caller must not use this buffer except for copying it. * caller must not write to this buffer. * used to enumerate the registry. * DWORD *pdw - address of dword in which size of the buffer (in bytes) is returned. * DWORD *pDataType - datatype of the value is returned in this one. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::GetNextValue(LPTSTR *lppStr, DWORD *pdw, DWORD *pDataType) { ASSERT(lppStr); ASSERT(pdw); ASSERT(pDataType); ASSERT(m_hKey != NULL); ASSERT(m_iEnumValueIndex >= 0); // must call GetFirstSubKey first. *pdw = 1024; if (0 == Allocate(*pdw * sizeof(TCHAR))) return ERROR_NOT_ENOUGH_MEMORY; LONG lResult = RegEnumValue( m_hKey, // handle of key to query m_iEnumValueIndex, // index of value to query (LPTSTR)m_pMemBlock, // address of buffer for value string pdw, // address for size of value buffer 0, // reserved pDataType, // address of buffer for type code NULL, // address of buffer for value data maks_todo : use this NULL // address for size of data buffer ); (*pdw)++; // since null is not included in the size. if (ERROR_NO_MORE_ITEMS == lResult) return lResult; m_iEnumValueIndex++; if (lResult == ERROR_SUCCESS) *lppStr = (LPTSTR)m_pMemBlock; return lResult; } /*-------------------------------------------------------------------------------------------------------- * DWORD WriteRegString(LPCTSTR lpValueName, LPCTSTR lpStr) * writes REG_SZ value into the registry * LPCTSTR lpValueName - value name to be written to * LPCTSTR lpStr - data to be written * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::WriteRegString(LPCTSTR lpValueName, LPCTSTR lpStr) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpStr); DWORD dwSize = (_tcslen(lpStr) + 1) * sizeof(TCHAR) / sizeof(BYTE); return RegSetValueEx( m_hKey, // handle of key to set value for lpValueName, // address of value to set 0, // Reserved REG_SZ, // flag for value type (LPBYTE)lpStr, // address of value data dwSize // size of value data ); } /*-------------------------------------------------------------------------------------------------------- * DWORD WriteRegMultiString(LPCTSTR lpValueName, LPCTSTR lpStr, DWORD dwSize) * writes REG_MULTI_SZ value into the registry * LPCTSTR lpValueName - value name to be written to * LPCTSTR lpStr - data to be written * DWORD dwSize - size of data. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::WriteRegMultiString(LPCTSTR lpValueName, LPCTSTR lpStr, DWORD dwSize) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpStr); #ifdef DBG // lets make sure that the given size is right. LPCTSTR lpTemp = lpStr; DWORD rightsize = 0; while (_tcslen(lpTemp) > 0) { rightsize += _tcslen(lpTemp) + 1; lpTemp += _tcslen(lpTemp) + 1; } ASSERT(*lpTemp == 0); // final NULL. rightsize++; // account for final terminating null rightsize *= sizeof(TCHAR) / sizeof(BYTE); // size must be in bytes. ASSERT(dwSize == rightsize); #endif return RegSetValueEx( m_hKey, // handle of key to set value for lpValueName, // address of value to set 0, // Reserved REG_MULTI_SZ, // flag for value type (LPBYTE)lpStr, // address of value data dwSize // size of value data ); } /*-------------------------------------------------------------------------------------------------------- * DWORD WriteRegBinary (LPCTSTR lpValueName, LPBYTE lpData, DWORD dwSize) * writes REG_BINARY value into the registry * LPCTSTR lpValueName - value name to be written to * LPBYTE lpData - data to be written * DWORD dwSize - size of data. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::WriteRegBinary (LPCTSTR lpValueName, LPBYTE lpData, DWORD dwSize) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpData); ASSERT(dwSize > 0); return RegSetValueEx( m_hKey, // handle of key to set value for lpValueName, // address of value to set 0, // Reserved REG_BINARY, // flag for value type lpData, // address of value data dwSize // size of value data ); } /*-------------------------------------------------------------------------------------------------------- * DWORD WriteRegDWord(LPCTSTR lpValueName, DWORD dwValue) * writes REG_DWORD value into the registry * LPCTSTR lpValueName - value name to be written to * LPCTSTR dwValue - data to be written * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::WriteRegDWord(LPCTSTR lpValueName, DWORD dwValue) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); return RegSetValueEx( m_hKey, // handle of key to set value for lpValueName, // address of value to set 0, // Reserved REG_DWORD, // flag for value type (LPBYTE)&dwValue, // address of value data sizeof(dwValue) // size of value data ); } /*-------------------------------------------------------------------------------------------------------- * DWORD ExistInMultiString (LPCTSTR lpValueName, LPCTSTR lpStr, BOOL *pbExists) * checks if given null terminated string exists in a multi_sz value * LPCTSTR lpValueName - value name to be checked * LPCTSTR lpCheckForStr - the value to be checked for * BOOL *pbExists - return. TRUE if exits. * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ /* DWORD CRegistry::ExistInMultiString (LPCTSTR lpValueName, LPCTSTR lpCheckForStr, BOOL *pbExists) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpCheckForStr); ASSERT(*lpCheckForStr); ASSERT(pbExists); DWORD dwError = ERROR_SUCCESS; *pbExists = FALSE; LPTSTR szValue; DWORD dwSize; dwError = ReadRegMultiString(lpValueName, &szValue, dwSize); if (ERROR_SUCCESS == dwError) { LPCTSTR pTemp = szValue; while(_tcslen(pTemp) > 0 ) { if (_tcscmp(pTemp, lpCheckForStr) == 0) { *pbExists = TRUE; break; } pTemp += _tcslen(pTemp) + 1; // point to the next string within the multistring. if ( DWORD(pTemp - szSuiteValue) > (dwSize / sizeof(TCHAR))) break; // temporary pointer passes the size of the szSuiteValue something is wrong with szSuiteValue. } } return dwError; ASSERT(FALSE); return ERROR_CALL_NOT_IMPLEMENTED; } */ /*-------------------------------------------------------------------------------------------------------- * DWORD AppendToMultiString (LPCTSTR lpValueName, LPCTSTR lpStr) * appends given string to a multistring value * LPCTSTR lpValueName - value name to be appended to * LPCTSTR lpStr - the value to be appended * RETURNS error code. * -------------------------------------------------------------------------------------------------------*/ DWORD CRegistry::AppendToMultiString (LPCTSTR lpValueName, LPCTSTR lpStr) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpStr); ASSERT(*lpStr); return ERROR_CALL_NOT_IMPLEMENTED; } // copy the buffer immediately DWORD CRegistry::GetSecurity(PSECURITY_DESCRIPTOR *ppSec, SECURITY_INFORMATION SecurityInformation, DWORD *pdwSize) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(ppSec); ASSERT(pdwSize); DWORD dwError; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; *pdwSize = 0; // we just want to get the right size during the first call. dwError = RegGetKeySecurity( m_hKey, // open handle of key to set SecurityInformation, // descriptor contents &pSecurityDescriptor, // address of descriptor for key pdwSize // address of size of buffer and descriptor ); // this call can not succeed. as we have set the size = 0 ASSERT(dwError != ERROR_SUCCESS); if (dwError != ERROR_INSUFFICIENT_BUFFER) { // something else has went wronng. // return the error code return dwError; } ASSERT(*pdwSize != 0); // now we have got the right size, allocate it. if (0 == Allocate(*pdwSize)) return ERROR_OUTOFMEMORY; dwError = RegGetKeySecurity( m_hKey, // open handle of key to set SecurityInformation, // descriptor contents m_pMemBlock, // address of descriptor for key pdwSize // address of size of buffer and descriptor ); ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER); if (dwError == ERROR_SUCCESS) *ppSec = m_pMemBlock; return dwError; } DWORD CRegistry::SetSecurity(PSECURITY_DESCRIPTOR pSec, SECURITY_INFORMATION SecurityInformation) { ASSERT(m_hKey != NULL); // call setkey before calling this function. return RegSetKeySecurity( m_hKey, // open handle of key to set SecurityInformation, // descriptor contents pSec // address of descriptor for key ); } // this function will fail miserably if the source and destination overlap. DWORD CRegistry::CopyTree(CRegistry ®Src) { DWORD dwSize; LPTSTR szKey; LPTSTR szValue; DWORD dwError; if (ERROR_SUCCESS == (dwError = regSrc.GetFirstSubKey(&szKey, &dwSize))) { do { CRegistry regSrcKey; CRegistry regDstKey; if (ERROR_SUCCESS == (dwError = regSrcKey.OpenKey(regSrc, szKey))) { if (ERROR_SUCCESS == (dwError = regDstKey.CreateKey(m_hKey, szKey))) { regDstKey.CopyTree(regSrcKey); } } } while (ERROR_SUCCESS == (dwError = regSrc.GetNextSubKey(&szKey, &dwSize))); } // // now copy values. // DWORD dwDataType; if (ERROR_SUCCESS == (dwError = regSrc.GetFirstValue(&szValue, &dwSize, &dwDataType))) { do { TCHAR *szValueName = new TCHAR[dwSize]; if (!szValueName) break; _tcscpy(szValueName, szValue); LPBYTE pData; if (ERROR_SUCCESS == (dwError = regSrc.ReadReg(szValueName, &pData, &dwSize, dwDataType))) { dwError = RegSetValueEx( m_hKey, // handle of key to set value for szValueName, // address of value to set 0, // Reserved dwDataType, // flag for value type pData, // address of value data dwSize // size of value data ); } } while (ERROR_SUCCESS == regSrc.GetNextValue(&szValue, &dwSize, &dwDataType)); } return TRUE; } DWORD CRegistry::WriteRegExString(LPCTSTR lpValueName, LPCTSTR lpStr) { ASSERT(m_hKey != NULL); // call setkey before calling this function. ASSERT(lpValueName); ASSERT(lpStr); DWORD dwSize = (_tcslen(lpStr) + 1) * sizeof(TCHAR) / sizeof(BYTE); return RegSetValueEx( m_hKey, // handle of key to set value for lpValueName, // address of value to set 0, // Reserved REG_EXPAND_SZ, // flag for value type (LPBYTE)lpStr, // address of value data dwSize // size of value data ); } #ifdef _Maks_AutoTest_ // // make sure that CRegistry does not support // Copy constructor & assignment operator // void TestRegistry (CRegistry reg) { CRegistry reg2 = reg; // should get error for copy constructor CRegistry reg3(reg); // should get error for copy constructor CRegistry reg4; reg4 = reg; // should get error for = operator. TestRegistry(reg); // should get error for copy construtor } #endif // _Maks_AutoTest_ // EOF