/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1995 - 1999 **/ /**********************************************************************/ /* FILE HISTORY: */ #include "stdafx.h" #include #include #include #include "tfschar.h" #include "tregkey.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif // Convert a CStringList to the REG_MULTI_SZ format DWORD StrList2MULTI_SZ(CStringList & strList, DWORD * pcbSize, BYTE ** ppbData) { DWORD dwErr = 0 ; POSITION pos ; CString * pstr ; int cbTotal = 0 ; // Walk the list accumulating sizes for ( pos = strList.GetHeadPosition() ; pos != NULL && (pstr = & strList.GetNext( pos )) ; ) { cbTotal += pstr->GetLength() + 1 ; } // Add on space for two NULL characters cbTotal += 2; // Allocate and fill a temporary buffer if (*pcbSize = (cbTotal * sizeof(TCHAR) ) ) { TRY { *ppbData = new BYTE[ *pcbSize] ; // NULL out the data buffer ::ZeroMemory(*ppbData, *pcbSize); BYTE * pbData = *ppbData ; // Populate the buffer with the strings. for ( pos = strList.GetHeadPosition() ; pos != NULL && (pstr = & strList.GetNext( pos )) ; ) { int cb = (pstr->GetLength() + 1) * sizeof(TCHAR) ; ::memcpy( pbData, (LPCTSTR) *pstr, cb ) ; pbData += cb ; } // Assert that we have not passed the end of the buffer Assert((pbData - *ppbData) < (int) *pcbSize); // Assert that we have an extra NULL character Assert(*((TCHAR *)pbData) == 0); } CATCH_ALL(e) { dwErr = ERROR_NOT_ENOUGH_MEMORY ; } END_CATCH_ALL } else { *ppbData = NULL; } return dwErr ; } // Convert a REG_MULTI_SZ format to the CStringList DWORD MULTI_SZ2StrList(LPCTSTR pstrMulti_Sz, CStringList& strList) { DWORD dwErr = NOERROR; strList.RemoveAll(); // Catch exceptions trying to build the list TRY { if (pstrMulti_Sz) { while ( StrLen(pstrMulti_Sz) ) { strList.AddTail( pstrMulti_Sz ) ; pstrMulti_Sz += StrLen( pstrMulti_Sz ) + 1 ; } } } CATCH_ALL(e) { dwErr = ERROR_NOT_ENOUGH_MEMORY ; } END_CATCH_ALL return dwErr; } /*!-------------------------------------------------------------------------- RegKey::RegKey Constructor Author: KennT ---------------------------------------------------------------------------*/ RegKey::RegKey() : m_hKey(0) { } /*!-------------------------------------------------------------------------- RegKey::~RegKey Destructor Author: KennT ---------------------------------------------------------------------------*/ RegKey::~RegKey () { Close(); } /*!-------------------------------------------------------------------------- RegKey::Open Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::Open( HKEY hKeyParent, LPCTSTR pszSubKey, REGSAM regSam, LPCTSTR pszServerName) { HKEY hkBase = NULL ; DWORD dwErr = 0; Close(); // If we have a server name, try to open a remote connection if ( pszServerName ) dwErr = ::RegConnectRegistry((LPTSTR) pszServerName, hKeyParent, &hkBase); else hkBase = hKeyParent ; if ( dwErr == 0 ) { if ( pszSubKey ) { dwErr = ::RegOpenKeyEx( hkBase, pszSubKey, 0, regSam, & m_hKey ) ; } else { m_hKey = hkBase ; hkBase = NULL ; // set to NULL so that the key doesn't get closed } if ( hkBase && (hkBase != hKeyParent) ) ::RegCloseKey( hkBase ) ; } if ( dwErr ) m_hKey = NULL ; return dwErr; } /*!-------------------------------------------------------------------------- RegKey::Create - Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::Create( HKEY hKeyBase, LPCTSTR pszSubKey, DWORD dwOptions, REGSAM regSam, LPSECURITY_ATTRIBUTES pSecAttr, LPCTSTR pszServerName ) { HKEY hkBase = NULL ; LONG dwErr = 0; DWORD dwDisposition; Close(); if ( pszServerName ) { // This is a remote connection. dwErr = ::RegConnectRegistry( (LPTSTR) pszServerName, hKeyBase, &hkBase ); } else hkBase = hKeyBase ; if (dwErr == 0) { LPTSTR szEmpty = _T(""); dwErr = ::RegCreateKeyEx( hkBase, pszSubKey, 0, szEmpty, dwOptions, regSam, pSecAttr, & m_hKey, & dwDisposition ) ; if ( hkBase && (hkBase != hKeyBase) ) ::RegCloseKey( hkBase ) ; } if ( dwErr ) m_hKey = NULL ; return dwErr; } /*!-------------------------------------------------------------------------- RegKey::Close - Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::Close() { DWORD dwErr = 0; if (m_hKey) dwErr = ::RegCloseKey(m_hKey); m_hKey = 0; return dwErr; } /*!-------------------------------------------------------------------------- RegKey::Detach - Author: KennT ---------------------------------------------------------------------------*/ HKEY RegKey::Detach() { HKEY hKey = m_hKey; m_hKey = NULL; return hKey; } /*!-------------------------------------------------------------------------- RegKey::Attach - Author: KennT ---------------------------------------------------------------------------*/ void RegKey::Attach(HKEY hKey) { Assert(m_hKey == NULL); m_hKey = hKey; } /*!-------------------------------------------------------------------------- RegKey::DeleteSubKey - Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::DeleteSubKey(LPCTSTR lpszSubKey) { Assert(m_hKey != NULL); return RegDeleteKey(m_hKey, lpszSubKey); } /*!-------------------------------------------------------------------------- RegKey::DeleteValue - Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::DeleteValue(LPCTSTR lpszValue) { Assert(m_hKey != NULL); return RegDeleteValue(m_hKey, (LPTSTR)lpszValue); } /*!-------------------------------------------------------------------------- RegKey::RecurseDeleteKey - Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::RecurseDeleteKey(LPCTSTR lpszKey) { RegKey key; DWORD dwRes = key.Open(m_hKey, lpszKey, KEY_READ | KEY_WRITE); if (dwRes != ERROR_SUCCESS) return dwRes; FILETIME time; TCHAR szBuffer[256]; DWORD dwSize = 256; while (RegEnumKeyEx(key, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time)==ERROR_SUCCESS) { dwRes = key.RecurseDeleteKey(szBuffer); if (dwRes != ERROR_SUCCESS) return dwRes; dwSize = 256; } key.Close(); return DeleteSubKey(lpszKey); } /*!-------------------------------------------------------------------------- RegKey::RecurseDeleteSubKeys Deletes the subkeys of the current key. Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::RecurseDeleteSubKeys() { FILETIME time; TCHAR szBuffer[256]; DWORD dwSize = 256; DWORD dwRes; while (RegEnumKeyEx(m_hKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time)==ERROR_SUCCESS) { dwRes = RecurseDeleteKey(szBuffer); if (dwRes != ERROR_SUCCESS) return dwRes; dwSize = 256; } return ERROR_SUCCESS; } /*!-------------------------------------------------------------------------- RegKey::PrepareValue Prepare to read a value by finding the value's size. This will allocate space for the data. The data needs to be freed separately by 'delete'. Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::PrepareValue( LPCTSTR pszValueName, DWORD * pdwType, DWORD * pcbSize, BYTE ** ppbData ) { DWORD dwErr = 0; BYTE chDummy[2] ; DWORD cbData = 0 ; do { // Set the resulting buffer size to 0. *pcbSize = 0 ; *ppbData = NULL ; dwErr = ::RegQueryValueEx( m_hKey, pszValueName, 0, pdwType, chDummy, & cbData ) ; // The only error we should get here is ERROR_MORE_DATA, but // we may get no error if the value has no data. if ( dwErr == 0 ) { cbData = sizeof (LONG) ; // Just a fudgy number } else if ( dwErr != ERROR_MORE_DATA ) break ; // Allocate a buffer large enough for the data. *ppbData = new BYTE [ (*pcbSize = cbData) + sizeof (LONG) ] ; Assert(*ppbData); // Now that have a buffer, re-fetch the value. dwErr = ::RegQueryValueEx( m_hKey, pszValueName, 0, pdwType, *ppbData, &cbData ) ; } while ( FALSE ) ; if ( dwErr ) { delete [] *ppbData ; *ppbData = NULL; *pcbSize = 0; } return dwErr ; } DWORD RegKey::QueryTypeAndSize(LPCTSTR pszValueName, DWORD *pdwType, DWORD *pdwSize) { return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, NULL, pdwSize); } DWORD RegKey::QueryValueExplicit(LPCTSTR pszValueName, DWORD *pdwType, DWORD *pdwSize, LPBYTE *ppbData) { DWORD dwErr = 0; DWORD dwType; DWORD cbData; BYTE * pbData = NULL; Assert(pdwType); Assert(pdwSize); Assert(ppbData); dwErr = PrepareValue( pszValueName, &dwType, &cbData, &pbData ); if (dwErr == ERROR_SUCCESS) { if (dwType != REG_MULTI_SZ) { dwErr = ERROR_INVALID_PARAMETER; } else { *pdwType = dwType; *pdwSize = cbData; *ppbData = pbData; pbData = NULL; } } delete pbData; return dwErr; } // Overloaded value query members; each returns ERROR_INVALID_PARAMETER // if data exists but not in correct form to deliver into result object. DWORD RegKey::QueryValue( LPCTSTR pszValueName, CString& strResult ) { DWORD dwErr = 0; DWORD dwType ; DWORD cbData ; BYTE * pabData = NULL ; do { if ( dwErr = PrepareValue( pszValueName, &dwType, &cbData, &pabData ) ) break ; if (( dwType != REG_SZ ) && (dwType != REG_EXPAND_SZ)) { dwErr = ERROR_INVALID_PARAMETER ; break ; } // Guarantee that the data looks like a string pabData[cbData] = 0 ; // Catch exceptions trying to assign to the caller's string TRY { strResult = (LPCTSTR) pabData ; } CATCH_ALL(e) { dwErr = ERROR_NOT_ENOUGH_MEMORY ; } END_CATCH_ALL } while ( FALSE ) ; delete [] pabData ; return dwErr ; } DWORD RegKey::QueryValue ( LPCTSTR pchValueName, CStringList & strList ) { DWORD dwErr = 0 ; DWORD dwType ; DWORD cbData ; BYTE * pabData = NULL ; LPTSTR pbTemp, pbTempLimit; do { if ( dwErr = PrepareValue( pchValueName, & dwType, & cbData, & pabData ) ) break ; if ( dwType != REG_MULTI_SZ ) { dwErr = ERROR_INVALID_PARAMETER ; break ; } // Guarantee that the trailing data looks like a string pabData[cbData] = 0 ; pbTemp = (LPTSTR) pabData ; pbTempLimit = & pbTemp[MaxCchFromCb(cbData)-1] ; dwErr = MULTI_SZ2StrList(pbTemp, strList); } while ( FALSE ) ; delete [] pabData ; return dwErr ; } /*!-------------------------------------------------------------------------- RegKey::QueryValue Gets the DWORD value for this key. Returns ERROR_INVALID_PARAMETER if the value is not a REG_DWORD. Author: KennT ---------------------------------------------------------------------------*/ DWORD RegKey::QueryValue( LPCTSTR pszValueName, DWORD& dwResult ) { DWORD dwErr; DWORD cbData = sizeof(DWORD); DWORD dwType = REG_DWORD; dwErr = ::RegQueryValueEx( m_hKey, pszValueName, 0, &dwType, (LPBYTE) &dwResult, &cbData ) ; if ((dwErr == ERROR_SUCCESS) && (dwType != REG_DWORD)) dwErr = ERROR_INVALID_PARAMETER; if ( dwErr ) dwResult = 0; return dwErr; } DWORD RegKey::QueryValue ( LPCTSTR pchValueName, LPTSTR pszDestBuffer, DWORD cchSize, BOOL fExpandSz) { DWORD dwErr; DWORD cbData = MinCbNeededForCch(cchSize); DWORD dwType = REG_SZ; TCHAR * pszBuffer = (TCHAR *) _alloca(MinCbNeededForCch(cchSize)); dwErr = ::RegQueryValueEx( m_hKey, pchValueName, 0, &dwType, (LPBYTE) pszBuffer, &cbData ) ; if ((dwErr == ERROR_SUCCESS) && (dwType != REG_SZ) && (dwType != REG_EXPAND_SZ) && (dwType != REG_MULTI_SZ)) dwErr = ERROR_INVALID_PARAMETER; if (dwErr == ERROR_SUCCESS) { if ((dwType == REG_EXPAND_SZ) && fExpandSz) ExpandEnvironmentStrings(pszBuffer, pszDestBuffer, cchSize); else ::CopyMemory(pszDestBuffer, pszBuffer, cbData); } return dwErr; } DWORD RegKey::QueryValue ( LPCTSTR pszValueName, CByteArray & abResult ) { DWORD dwErr = 0 ; DWORD dwType ; DWORD cbData ; BYTE * pabData = NULL ; do { if ( dwErr = PrepareValue( pszValueName, & dwType, & cbData, & pabData ) ) break ; if ( dwType != REG_BINARY ) { dwErr = ERROR_INVALID_PARAMETER ; break ; } // Catch exceptions trying to grow the result array TRY { abResult.SetSize( cbData ) ; } CATCH_ALL(e) { dwErr = ERROR_NOT_ENOUGH_MEMORY ; } END_CATCH_ALL if ( dwErr ) break ; // Move the data to the result array. for ( DWORD i = 0 ; i < cbData ; i++ ) { abResult[i] = pabData[i] ; } } while ( FALSE ) ; // Memory leak.... //if ( dwErr ) //{ delete [] pabData ; //} return dwErr ; } DWORD RegKey::QueryValue ( LPCTSTR pszValueName, void * pvResult, DWORD cbSize ) { DWORD dwErr; DWORD dwType = REG_BINARY; dwErr = ::RegQueryValueEx( m_hKey, pszValueName, 0, &dwType, (LPBYTE) pvResult, &cbSize ) ; if ((dwErr == ERROR_SUCCESS) && (dwType != REG_BINARY)) dwErr = ERROR_INVALID_PARAMETER; return dwErr; } DWORD RegKey::SetValueExplicit(LPCTSTR pszValueName, DWORD dwType, DWORD dwSize, LPBYTE pbData) { return ::RegSetValueEx( *this, pszValueName, 0, dwType, pbData, dwSize); } // Overloaded value setting members. DWORD RegKey::SetValue ( LPCTSTR pszValueName, LPCTSTR pszValue, BOOL fRegExpand) { DWORD dwErr = 0; DWORD dwType = fRegExpand ? REG_EXPAND_SZ : REG_SZ; dwErr = ::RegSetValueEx( *this, pszValueName, 0, dwType, (const BYTE *) pszValue, // This is not the correct string length // for DBCS strings pszValue ? CbStrLen(pszValue) : 0); return dwErr ; } DWORD RegKey::SetValue ( LPCTSTR pszValueName, CStringList & strList ) { DWORD dwErr = 0; DWORD cbSize ; BYTE * pbData = NULL ; dwErr = FlattenValue( strList, & cbSize, & pbData ) ; if ( dwErr == 0 ) { dwErr = ::RegSetValueEx( *this, pszValueName, 0, REG_MULTI_SZ, pbData, cbSize ) ; } delete pbData ; return dwErr ; } DWORD RegKey::SetValue ( LPCTSTR pszValueName, DWORD & dwResult ) { DWORD dwErr = 0; dwErr = ::RegSetValueEx( *this, pszValueName, 0, REG_DWORD, (const BYTE *) & dwResult, sizeof dwResult ) ; return dwErr ; } DWORD RegKey::SetValue ( LPCTSTR pszValueName, CByteArray & abResult ) { DWORD dwErr = 0; DWORD cbSize ; BYTE * pbData = NULL ; dwErr = FlattenValue( abResult, & cbSize, & pbData ) ; if ( dwErr == 0 ) { dwErr = ::RegSetValueEx( *this, pszValueName, 0, REG_BINARY, pbData, cbSize ) ; } delete pbData ; return dwErr ; } DWORD RegKey::SetValue ( LPCTSTR pszValueName, void * pvResult, DWORD cbSize ) { DWORD dwErr = 0; dwErr = ::RegSetValueEx( *this, pszValueName, 0, REG_BINARY, (const BYTE *)pvResult, cbSize ) ; return dwErr ; } DWORD RegKey::FlattenValue ( CStringList & strList, DWORD * pcbSize, BYTE ** ppbData ) { return StrList2MULTI_SZ(strList, pcbSize, ppbData); } DWORD RegKey::FlattenValue ( CByteArray & abData, DWORD * pcbSize, BYTE ** ppbData ) { DWORD dwErr = 0 ; DWORD i ; // Allocate and fill a temporary buffer if (*pcbSize = (DWORD)abData.GetSize()) { TRY { *ppbData = new BYTE[*pcbSize] ; for ( i = 0 ; i < *pcbSize ; i++ ) { (*ppbData)[i] = abData[i] ; } } CATCH_ALL(e) { dwErr = ERROR_NOT_ENOUGH_MEMORY ; } END_CATCH_ALL } else { *ppbData = NULL; } return dwErr ; } DWORD RegKey::QueryKeyInfo ( CREGKEY_KEY_INFO * pRegKeyInfo ) { DWORD dwErr = 0 ; pRegKeyInfo->dwClassNameSize = sizeof pRegKeyInfo->chBuff - 1 ; dwErr = ::RegQueryInfoKey( *this, pRegKeyInfo->chBuff, & pRegKeyInfo->dwClassNameSize, NULL, & pRegKeyInfo->dwNumSubKeys, & pRegKeyInfo->dwMaxSubKey, & pRegKeyInfo->dwMaxClass, & pRegKeyInfo->dwMaxValues, & pRegKeyInfo->dwMaxValueName, & pRegKeyInfo->dwMaxValueData, & pRegKeyInfo->dwSecDesc, & pRegKeyInfo->ftKey ) ; return dwErr ; } RegValueIterator::RegValueIterator() : m_pRegKey( NULL ), m_pszBuffer( NULL ), m_cbBuffer( 0 ) { } HRESULT RegValueIterator::Init(RegKey *pRegKey) { DWORD dwErr = 0 ; RegKey::CREGKEY_KEY_INFO regKeyInfo ; Reset() ; m_pRegKey= pRegKey; dwErr = pRegKey->QueryKeyInfo( & regKeyInfo ) ; if ( dwErr == 0 ) { m_cbBuffer = regKeyInfo.dwMaxValueName + sizeof (DWORD) ; delete [] m_pszBuffer; m_pszBuffer = new TCHAR [ m_cbBuffer ] ; Assert(m_pszBuffer); } return HRESULT_FROM_WIN32(dwErr); } RegValueIterator::~RegValueIterator() { delete [] m_pszBuffer ; } HRESULT RegValueIterator::Next( CString * pstrName, DWORD * pdwType ) { DWORD dwErr = 0 ; DWORD dwNameLength = m_cbBuffer ; dwErr = ::RegEnumValue( *m_pRegKey, m_dwIndex, m_pszBuffer, & dwNameLength, NULL, pdwType, NULL, NULL ) ; if ( dwErr == 0 ) { m_dwIndex++ ; *pstrName = m_pszBuffer ; } return HRESULT_FROM_WIN32(dwErr) ; } RegKeyIterator::RegKeyIterator() : m_pregkey(NULL), m_pszBuffer(NULL), m_cbBuffer( 0 ) { } HRESULT RegKeyIterator::Init(RegKey *pregkey) { DWORD dwErr = 0 ; RegKey::CREGKEY_KEY_INFO regKeyInfo ; Reset() ; m_pregkey= pregkey; dwErr = pregkey->QueryKeyInfo( & regKeyInfo ) ; if ( dwErr == 0 ) { m_cbBuffer = regKeyInfo.dwMaxSubKey + sizeof(DWORD); delete [] m_pszBuffer; m_pszBuffer = new TCHAR[m_cbBuffer]; } return HRESULT_FROM_WIN32(dwErr); } RegKeyIterator::~RegKeyIterator () { delete [] m_pszBuffer ; } HRESULT RegKeyIterator::Reset() { m_dwIndex = 0; return hrOK; } /*!-------------------------------------------------------------------------- RegKeyIterator::Next Returns the name (and optional last write time) of the next key. Return S_FALSE if there are no other items to be returned. Author: KennT ---------------------------------------------------------------------------*/ HRESULT RegKeyIterator::Next ( CString * pstrName, CTime * pTime ) { DWORD dwErr = 0; FILETIME ftDummy ; DWORD dwNameSize = m_cbBuffer; dwErr = ::RegEnumKeyEx( *m_pregkey, m_dwIndex, m_pszBuffer, & dwNameSize, NULL, NULL, NULL, & ftDummy ) ; if ( dwErr == 0 ) { m_dwIndex++ ; if ( pTime ) { *pTime = ftDummy ; } if (pstrName) { *pstrName = m_pszBuffer ; } } return (dwErr == ERROR_NO_MORE_ITEMS) ? S_FALSE : HRESULT_FROM_WIN32(dwErr); }