//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: registry.cpp // //-------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "registry.h" RegKey::RegKey( void ) : m_hkeyRoot(NULL), m_hkey(NULL) { m_szSubKey[0] = TEXT('\0'); } RegKey::RegKey( HKEY hkeyRoot, LPCTSTR pszSubKey ) : m_hkeyRoot(hkeyRoot), m_hkey(NULL) { lstrcpyn(m_szSubKey, pszSubKey, ARRAYSIZE(m_szSubKey)); } RegKey::~RegKey( void ) { Close(); } HRESULT RegKey::Open( REGSAM samDesired, // Access mask (i.e. KEY_READ, KEY_WRITE etc.) bool bCreate // Create key if it doesn't exist? ) const { DWORD dwResult = ERROR_SUCCESS; HKEY hkeyRoot = m_hkeyRoot; // Assume we'll use m_hkeyRoot; bool bCloseRootKey = false; Close(); if (HKEY_CURRENT_USER == hkeyRoot) { // // Special-case HKEY_CURRENT_USER. // Since we're running from winlogon and need to open // the user hive during tricky times we need to // call RegOpenCurrentUser(). If it's successful all // we do is replace the hkeyRoot member with the // returned key. From here on out things remain // unchanged. // if (ERROR_SUCCESS == RegOpenCurrentUser(samDesired, &hkeyRoot)) { bCloseRootKey = true; } } dwResult = RegOpenKeyEx(hkeyRoot, m_szSubKey, 0, samDesired, &m_hkey); if ((ERROR_FILE_NOT_FOUND == dwResult) && bCreate) { DWORD dwDisposition; dwResult = RegCreateKeyEx(hkeyRoot, m_szSubKey, 0, NULL, 0, samDesired, NULL, &m_hkey, &dwDisposition); } if (bCloseRootKey) { RegCloseKey(hkeyRoot); } return HRESULT_FROM_WIN32(dwResult); } void RegKey::Attach( HKEY hkey ) { Close(); m_szSubKey[0] = TEXT('\0'); m_hkeyRoot = NULL; m_hkey = hkey; } void RegKey::Detach( void ) { m_hkey = NULL; } void RegKey::Close( void ) const { if (NULL != m_hkey) { // // Do this little swap so that the m_hkey member is NULL // when the actual key is being closed. This lets the async // change proc determine if it was signaled because of a true // change or because the key was being closed. // HKEY hkeyTemp = m_hkey; m_hkey = NULL; RegCloseKey(hkeyTemp); } } // // Determine if a particular registry value exists. // HRESULT RegKey::ValueExists( LPCTSTR pszValueName ) const { DWORD dwResult = ERROR_SUCCESS; int iValue = 0; TCHAR szValue[MAX_PATH]; DWORD cchValue; while(ERROR_SUCCESS == dwResult) { cchValue = ARRAYSIZE(szValue); dwResult = RegEnumValue(m_hkey, iValue++, szValue, &cchValue, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == dwResult && (0 == lstrcmpi(pszValueName, szValue))) { return S_OK; } } if (ERROR_NO_MORE_ITEMS == dwResult) { return S_FALSE; } return HRESULT_FROM_WIN32(dwResult); } // // This is the basic form of GetValue. All other forms of // GetValue() call into this one. // HRESULT RegKey::GetValue( LPCTSTR pszValueName, DWORD dwTypeExpected, LPBYTE pbData, int cbData ) const { DWORD dwType; DWORD dwResult = RegQueryValueEx(m_hkey, pszValueName, 0, &dwType, pbData, (LPDWORD)&cbData); if (ERROR_SUCCESS == dwResult && dwType != dwTypeExpected) dwResult = ERROR_INVALID_DATATYPE; return HRESULT_FROM_WIN32(dwResult); } // // Get a DWORD value (REG_DWORD). // HRESULT RegKey::GetValue( LPCTSTR pszValueName, DWORD *pdwDataOut ) const { return GetValue(pszValueName, REG_DWORD, (LPBYTE)pdwDataOut, sizeof(DWORD)); } // // Get a byte buffer value (REG_BINARY). // HRESULT RegKey::GetValue( LPCTSTR pszValueName, LPBYTE pbDataOut, int cbDataOut ) const { return GetValue(pszValueName, REG_BINARY, pbDataOut, cbDataOut); } // // Get a text string value (REG_SZ). // HRESULT RegKey::GetValue( LPCTSTR pszValueName, LPTSTR pszDataOut, UINT cchDataOut ) const { return GetValue(pszValueName, REG_SZ, (LPBYTE)pszDataOut, cchDataOut * sizeof(*pszDataOut)); } // // Get a multi-text string value (REG_MULTI_SZ). // HRESULT RegKey::GetValue( LPCTSTR pszValueName, HDPA hdpaStringsOut ) const { HRESULT hr = E_FAIL; int cb = GetValueBufferSize(pszValueName); if (NULL != hdpaStringsOut && 0 < cb) { LPTSTR psz = (LPTSTR)LocalAlloc(LPTR, cb); if (NULL != psz) { hr = GetValue(pszValueName, REG_MULTI_SZ, (LPBYTE)psz, cb); if (SUCCEEDED(hr)) { while(psz && TEXT('\0') != *psz && SUCCEEDED(hr)) { LPTSTR pszCopy = StrDup(psz); if (NULL != pszCopy) { if (-1 == DPA_AppendPtr(hdpaStringsOut, pszCopy)) { LocalFree(pszCopy); hr = E_OUTOFMEMORY; } } psz += lstrlen(psz) + 1; } } if (FAILED(hr)) { // // Something failed. Clean up the DPA. // const int cStrings = DPA_GetPtrCount(hdpaStringsOut); for (int i = 0; i < cStrings; i++) { LPTSTR pszDel = (LPTSTR)DPA_GetPtr(hdpaStringsOut, i); if (NULL != pszDel) { LocalFree(pszDel); } DPA_DeletePtr(hdpaStringsOut, i); } } LocalFree(psz); } } return hr; } // // Return the required buffer size for a given registry value. // int RegKey::GetValueBufferSize( LPCTSTR pszValueName ) const { DWORD dwType; int cbData = 0; DWORD dwDummy; DWORD dwResult = RegQueryValueEx(m_hkey, pszValueName, 0, &dwType, (LPBYTE)&dwDummy, (LPDWORD)&cbData); if (ERROR_MORE_DATA != dwResult) cbData = 0; return cbData; } // // This is the basic form of SetValue. All other forms of // SetValue() call into this one. // HRESULT RegKey::SetValue( LPCTSTR pszValueName, DWORD dwValueType, const LPBYTE pbData, int cbData ) { DWORD dwResult = RegSetValueEx(m_hkey, pszValueName, 0, dwValueType, pbData, cbData); return HRESULT_FROM_WIN32(dwResult); } // // Set a DWORD value (REG_DWORD). // HRESULT RegKey::SetValue( LPCTSTR pszValueName, DWORD dwData ) { return SetValue(pszValueName, REG_DWORD, (const LPBYTE)&dwData, sizeof(dwData)); } // // Set a byte buffer value (REG_BINARY). // HRESULT RegKey::SetValue( LPCTSTR pszValueName, const LPBYTE pbData, int cbData ) { return SetValue(pszValueName, REG_BINARY, pbData, cbData); } // // Set a text string value (REG_SZ). // HRESULT RegKey::SetValue( LPCTSTR pszValueName, LPCTSTR pszData ) { return SetValue(pszValueName, REG_SZ, (const LPBYTE)pszData, (lstrlen(pszData) + 1) * sizeof(TCHAR)); } // // Set a text string value (REG_MULTI_SZ). // HRESULT RegKey::SetValue( LPCTSTR pszValueName, HDPA hdpaStrings ) { HRESULT hr = E_OUTOFMEMORY; LPTSTR pszDblNul = CreateDoubleNulTermList(hdpaStrings); if (NULL != pszDblNul) { int cch = 1; LPTSTR psz = pszDblNul; while(*psz) { while(*psz++) cch++; psz++; } hr = SetValue(pszValueName, REG_MULTI_SZ, (const LPBYTE)pszDblNul, cch * sizeof(TCHAR)); LocalFree(pszDblNul); } return hr; } LPTSTR RegKey::CreateDoubleNulTermList( HDPA hdpaStrings ) const { LPTSTR pszBuf = NULL; if (NULL != hdpaStrings) { const int cEntries = DPA_GetPtrCount(hdpaStrings); int cch = 1; // Account for 2nd nul term. int i; for (i = 0; i < cEntries; i++) { LPTSTR psz = (LPTSTR)DPA_GetPtr(hdpaStrings, i); if (NULL != psz) { cch += lstrlen(psz) + 1; } } pszBuf = (LPTSTR)LocalAlloc(LPTR, cch * sizeof(*pszBuf)); if (NULL != pszBuf) { LPTSTR pszWrite = pszBuf; for (i = 0; i < cEntries; i++) { LPTSTR psz = (LPTSTR)DPA_GetPtr(hdpaStrings, i); if (NULL != psz) { lstrcpy(pszWrite, psz); pszWrite += lstrlen(psz) + 1; } } *pszWrite = TEXT('\0'); // Double nul term. } } return pszBuf; } HRESULT RegKey::DeleteAllValues( int *pcNotDeleted ) { HRESULT hr; KEYINFO ki; if (NULL != pcNotDeleted) *pcNotDeleted = 0; hr = QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT); if (FAILED(hr)) return hr; TCHAR szName[MAX_PATH]; DWORD cchValueName; DWORD dwError = ERROR_SUCCESS; int cNotDeleted = 0; int iValue = 0; while(ERROR_SUCCESS == dwError) { cchValueName = ARRAYSIZE(szName); dwError = RegEnumValue(m_hkey, iValue, szName, &cchValueName, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == dwError) { if (FAILED(hr = DeleteValue(szName))) { cNotDeleted++; iValue++; // Skip to next value to avoid infinite loop. Trace((TEXT("Error %d deleting reg value \"%s\""), HRESULT_CODE(hr), szName)); } } } if (ERROR_NO_MORE_ITEMS == dwError) dwError = ERROR_SUCCESS; if (pcNotDeleted) *pcNotDeleted = cNotDeleted; return HRESULT_FROM_WIN32(dwError); } HRESULT RegKey::DeleteValue( LPCTSTR pszValue ) { LONG lRet = RegDeleteValue(m_hkey, pszValue); return HRESULT_FROM_WIN32(lRet); } HRESULT RegKey::QueryInfo( RegKey::KEYINFO *pInfo, DWORD fMask ) const { LONG lResult = RegQueryInfoKey(m_hkey, NULL, NULL, NULL, (QIM_SUBKEYCNT & fMask) ? &pInfo->cSubKeys : NULL, (QIM_SUBKEYMAXCHARCNT & fMask) ? &pInfo->cchSubKeyMax : NULL, (QIM_CLASSMAXCHARCNT & fMask) ? &pInfo->cchClassMax : NULL, (QIM_VALUECNT & fMask) ? &pInfo->cValues : NULL, (QIM_VALUENAMEMAXCHARCNT & fMask) ? &pInfo->cchValueNameMax : NULL, (QIM_VALUEMAXBYTECNT & fMask) ? &pInfo->cbValueMax : NULL, (QIM_SECURITYBYTECNT & fMask) ? &pInfo->cbSecurityDesc : NULL, (QIM_LASTWRITETIME & fMask) ? &pInfo->LastWriteTime : NULL); return HRESULT_FROM_WIN32(lResult); } RegKey::ValueIterator::ValueIterator( RegKey& key ) : m_key(key), m_iValue(0), m_cchValueName(0) { KEYINFO ki; if (SUCCEEDED(key.QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT))) { m_cchValueName = ki.cchValueNameMax + 1; } } // // Returns: S_OK = More items. // S_FALSE = No more items. HRESULT RegKey::ValueIterator::Next( LPTSTR pszNameOut, UINT cchNameOut, LPDWORD pdwType, LPBYTE pbData, LPDWORD pcbData ) { HRESULT hr = S_OK; DWORD cchName = cchNameOut; LONG lResult = RegEnumValue(m_key, m_iValue, pszNameOut, &cchName, NULL, pdwType, pbData, pcbData); switch(lResult) { case ERROR_SUCCESS: m_iValue++; break; case ERROR_NO_MORE_ITEMS: hr = S_FALSE; break; default: Trace((TEXT("Error %d enumerating reg value \"%s\""), lResult, m_key.SubKeyName())); hr = HRESULT_FROM_WIN32(lResult); break; } return hr; }; RegKeyCU::RegKeyCU( REGSAM samDesired ) : m_hkey(NULL) { RegOpenCurrentUser(samDesired, &m_hkey); } RegKeyCU::~RegKeyCU( void ) { if (NULL != m_hkey) RegCloseKey(m_hkey); } // // Version of RegEnumValue that expands environment variables // in all string values. // LONG _RegEnumValueExp( HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { DWORD cchNameDest = lpcbValueName ? *lpcbValueName / sizeof(TCHAR) : 0; DWORD cchDataDest = lpcbData ? *lpcbData / sizeof(TCHAR) : 0; DWORD dwType; if (NULL == lpType) lpType = &dwType; LONG lResult = RegEnumValue(hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); if (ERROR_SUCCESS == lResult) { HRESULT hr = ExpandStringInPlace(lpValueName, cchNameDest); if ((NULL != lpData) && (REG_SZ == *lpType || REG_EXPAND_SZ == *lpType)) { hr = ExpandStringInPlace((LPTSTR)lpData, cchDataDest); } lResult = HRESULT_CODE(hr); } return lResult; }