#include #include #define REGISTRY_BASE_LOCATION L"Software\\Microsoft\\Fusion\\Installer\\" ////////////////////////////////////////////////////////////////////////////// // // Emitter // ////////////////////////////////////////////////////////////////////////////// // --------------------------------------------------------------------------- // CRegEmit ctor // --------------------------------------------------------------------------- CRegEmit::CRegEmit() : _hr(S_OK), _hBaseKey((HKEY) INVALID_HANDLE_VALUE) {} // --------------------------------------------------------------------------- // CRegEmit dtor // --------------------------------------------------------------------------- CRegEmit::~CRegEmit() { if (_hBaseKey != INVALID_HANDLE_VALUE) IF_FAILED_EXIT(RegCloseKey(_hBaseKey)); exit: return; } // --------------------------------------------------------------------------- // CRegEmit::Create // --------------------------------------------------------------------------- HRESULT CRegEmit::Create(CRegEmit **ppEmit, LPCWSTR pwzRelKeyPath, CRegEmit* pParentEmit) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; LONG lReturn = 0; DWORD dwDisposition = 0; CString sBasePath; CRegEmit *pEmit = NULL; if (!pParentEmit) { IF_FAILED_EXIT(sBasePath.Assign(REGISTRY_BASE_LOCATION)); if (pwzRelKeyPath) IF_FAILED_EXIT(sBasePath.Append(pwzRelKeyPath)); hKey = HKEY_CURRENT_USER; } else { IF_NULL_EXIT(pwzRelKeyPath, E_INVALIDARG); sBasePath.Assign(pwzRelKeyPath); hKey = pParentEmit->_hBaseKey; } IF_ALLOC_FAILED_EXIT(pEmit = new CRegEmit); lReturn = RegCreateKeyEx( hKey, sBasePath._pwz, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &pEmit->_hBaseKey, &dwDisposition); IF_WIN32_FAILED_EXIT(lReturn); *ppEmit = pEmit; exit: if (FAILED(hr)) SAFEDELETE(pEmit); return hr; } // --------------------------------------------------------------------------- // WriteDword // --------------------------------------------------------------------------- HRESULT CRegEmit::WriteDword(LPCWSTR pwzValue, DWORD dwData) { LONG lReturn = 0; lReturn = RegSetValueEx(_hBaseKey, pwzValue, 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)); IF_WIN32_FAILED_EXIT(lReturn); exit: return _hr; } // --------------------------------------------------------------------------- // WriteString // --------------------------------------------------------------------------- HRESULT CRegEmit::WriteString(LPCWSTR pwzValue, LPCWSTR pwzData, DWORD ccData) { LONG lReturn = 0; DWORD cbData = 0; IF_FALSE_EXIT(pwzData, E_INVALIDARG); if (ccData) cbData = ccData * sizeof(WCHAR); else cbData = (lstrlen(pwzData) + 1) * sizeof(WCHAR); lReturn = RegSetValueEx(_hBaseKey, pwzValue, 0, REG_SZ, (LPBYTE) pwzData, cbData); IF_WIN32_FAILED_EXIT(lReturn); exit: return _hr; } // --------------------------------------------------------------------------- // WriteString // --------------------------------------------------------------------------- HRESULT CRegEmit::WriteString(LPCWSTR pwzValue, CString &sData) { return WriteString(pwzValue, sData._pwz, sData._cc); } // --------------------------------------------------------------------------- // DeleteKey // The one and only place we use the lousy Shlwapi apis. // --------------------------------------------------------------------------- HRESULT CRegEmit::DeleteKey(LPCWSTR pwzSubKey) { IF_FAILED_EXIT(SHDeleteKey(_hBaseKey, pwzSubKey)); exit: return _hr; } ////////////////////////////////////////////////////////////////////////////// // // Importer // ////////////////////////////////////////////////////////////////////////////// // --------------------------------------------------------------------------- // CRegImport ctor // --------------------------------------------------------------------------- CRegImport::CRegImport() : _hr(S_OK), _hBaseKey((HKEY) INVALID_HANDLE_VALUE) {} // --------------------------------------------------------------------------- // CRegImport dtor // --------------------------------------------------------------------------- CRegImport::~CRegImport() { if (_hBaseKey != INVALID_HANDLE_VALUE) IF_FAILED_EXIT(RegCloseKey(_hBaseKey)); exit: return; } // --------------------------------------------------------------------------- // CRegImport::Create // --------------------------------------------------------------------------- HRESULT CRegImport::Create(CRegImport **ppImport, LPCWSTR pwzRelKeyPath, CRegImport *pParentImport) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; LONG lReturn = 0; DWORD dwDisposition = 0; CString sBasePath; CRegImport *pImport = NULL; if (!pParentImport) { IF_FAILED_EXIT(sBasePath.Assign(REGISTRY_BASE_LOCATION)); if (pwzRelKeyPath) IF_FAILED_EXIT(sBasePath.Append(pwzRelKeyPath)); hKey = HKEY_CURRENT_USER; } else { IF_NULL_EXIT(pwzRelKeyPath, E_INVALIDARG); sBasePath.Assign(pwzRelKeyPath); hKey = pParentImport->_hBaseKey; } IF_ALLOC_FAILED_EXIT(pImport = new CRegImport); lReturn = RegOpenKeyEx( hKey, sBasePath._pwz, 0, KEY_READ, &pImport->_hBaseKey); if (lReturn == ERROR_FILE_NOT_FOUND) { hr = S_FALSE; *ppImport = NULL; goto exit; } IF_WIN32_FAILED_EXIT(lReturn); *ppImport = pImport; exit: if (FAILED(hr)) SAFEDELETE(pImport); return hr; } // --------------------------------------------------------------------------- // CRegImport::Create // --------------------------------------------------------------------------- HRESULT CRegImport::Create(CRegImport **ppImport, LPCWSTR pwzRelKeyPath, HKEY hkeyRoot) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LONG lReturn = 0; DWORD dwDisposition = 0; CString sBasePath; CRegImport *pImport = NULL; IF_NULL_EXIT(pwzRelKeyPath, E_INVALIDARG); IF_FAILED_EXIT(sBasePath.Assign(pwzRelKeyPath)); IF_ALLOC_FAILED_EXIT(pImport = new CRegImport); lReturn = RegOpenKeyEx( hkeyRoot, sBasePath._pwz, 0, KEY_READ, &pImport->_hBaseKey); if (lReturn == ERROR_FILE_NOT_FOUND) { hr = S_FALSE; *ppImport = NULL; goto exit; } IF_WIN32_FAILED_EXIT(lReturn); *ppImport = pImport; exit: if (FAILED(hr)) SAFEDELETE(pImport); return hr; } // --------------------------------------------------------------------------- // Check // --------------------------------------------------------------------------- HRESULT CRegImport::Check(LPCWSTR pwzValue, BOOL &bExist) { LONG lReturn = 0; bExist = FALSE; lReturn = RegQueryValueEx(_hBaseKey, pwzValue, NULL, NULL, NULL, NULL); IF_TRUE_EXIT(lReturn == ERROR_FILE_NOT_FOUND, S_FALSE); IF_WIN32_FAILED_EXIT(lReturn); bExist = TRUE; exit: return _hr; } // --------------------------------------------------------------------------- // ReadDword // --------------------------------------------------------------------------- HRESULT CRegImport::ReadDword(LPCWSTR pwzValue, LPDWORD pdwData) { LONG lReturn = 0; DWORD dwType = REG_DWORD; DWORD cbData = sizeof(DWORD); lReturn = RegQueryValueEx(_hBaseKey, pwzValue, NULL, &dwType, (LPBYTE) pdwData, &cbData); IF_WIN32_FAILED_EXIT(lReturn); // Validate reg value type IF_FALSE_EXIT(dwType == REG_DWORD || dwType == REG_DWORD_LITTLE_ENDIAN, E_UNEXPECTED); exit: return _hr; } // --------------------------------------------------------------------------- // ReadString // --------------------------------------------------------------------------- HRESULT CRegImport::ReadString(LPCWSTR pwzValue, CString& sData) { LONG lReturn = 0; DWORD dwType = REG_SZ; DWORD cbData = 0; DWORD dwCC = 0; DWORD dwBufLen = 0; CStringAccessor acc; LPWSTR pwzData = NULL; // IF_FALSE_EXIT(pwzValue, E_INVALIDARG); // if pwzValue == NULL or "", the "default" value is returned lReturn = RegQueryValueEx(_hBaseKey, pwzValue, NULL, &dwType, NULL, &cbData); IF_WIN32_FAILED_EXIT(lReturn); IF_FALSE_EXIT(cbData, E_FAIL); // Validate reg value type IF_FALSE_EXIT(dwType == REG_SZ || dwType == REG_EXPAND_SZ, E_UNEXPECTED); // Allocate for call to RQEX, with one extra char in case // returned buffer is not null terminated. dwCC = cbData / sizeof(WCHAR); dwBufLen = dwCC+1; // check overflow IF_FALSE_EXIT(dwBufLen > dwCC, HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)); IF_ALLOC_FAILED_EXIT(pwzData = new WCHAR[dwBufLen]); lReturn = RegQueryValueEx(_hBaseKey, pwzValue, NULL, &dwType, (LPBYTE) pwzData, &cbData); IF_WIN32_FAILED_EXIT(lReturn); // Null terminate returned buffer. *(pwzData + dwCC) = L'\0'; if (*(pwzData + dwCC - 1) != L'\0') dwCC++; sData.FreeBuffer(); // Attach accessor, set buffer, detach with corrected length. IF_FAILED_EXIT(acc.Attach(sData)); *(&acc) = pwzData; // Buffer size could be dwCC+1 IF_FAILED_EXIT(acc.Detach(dwCC)); // If Detach succeeds, reset pointer so that it is freed once. pwzData = NULL; exit: SAFEDELETEARRAY(pwzData); return _hr; } // --------------------------------------------------------------------------- // EnumKeys // --------------------------------------------------------------------------- HRESULT CRegImport::EnumKeys(DWORD n, CString &sSubKey) { LONG lReturn = 0; DWORD cSubKeys = 0, ccMaxSubKeyLen = 0, cValues = 0, cMaxValueNameLen = 0, cMaxValueLen = 0; DWORD ccSubKey = 0; LPWSTR pwzSubKey = NULL; // ISSUE-2002/03/04-adriaanc // A race condition exists where a key could be added // between RegQueryInfoKey and RegEnumKey. If a key // greater than ccMaxSubKeyLen is added this will cause // the enum call to fail. Need synchronization. lReturn = RegQueryInfoKey( _hBaseKey, NULL, NULL, NULL, &cSubKeys, &ccMaxSubKeyLen, NULL, &cValues, &cMaxValueNameLen, &cMaxValueLen, NULL, NULL); IF_WIN32_FAILED_EXIT(lReturn); ccSubKey = ccMaxSubKeyLen + 1; IF_ALLOC_FAILED_EXIT(pwzSubKey = new WCHAR[ccSubKey]); lReturn = RegEnumKeyEx( _hBaseKey, n, pwzSubKey, &ccSubKey, 0, NULL, NULL, NULL); if (lReturn == ERROR_NO_MORE_ITEMS) { _hr = S_FALSE; goto exit; } IF_WIN32_FAILED_EXIT(lReturn); sSubKey.Assign(pwzSubKey); exit: SAFEDELETEARRAY(pwzSubKey); return _hr; } // --------------------------------------------------------------------------- // EnumKeys // --------------------------------------------------------------------------- HRESULT CRegImport::EnumKeys(DWORD n, CRegImport **ppImport) { CString sSubKey; CRegImport *pImport = NULL; IF_FAILED_EXIT(EnumKeys(n, sSubKey)); if (_hr == S_FALSE) { *ppImport = NULL; goto exit; } IF_FAILED_EXIT(CRegImport::Create(&pImport, sSubKey._pwz, this)); *ppImport = pImport; exit: return _hr; }