#include "pch.h" #pragma hdrstop #include "registry.h" RegKey::RegKey( void ) : m_hkeyRoot(NULL), m_hkey(NULL), m_hChangeEvent(NULL), m_bWatchSubtree(false), m_dwChangeFilter(0) { DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey [default]"))); } RegKey::RegKey( HKEY hkeyRoot, LPCTSTR pszSubKey ) : m_hkeyRoot(hkeyRoot), m_hkey(NULL), m_strSubKey(pszSubKey), m_hChangeEvent(NULL), m_bWatchSubtree(false), m_dwChangeFilter(0) { DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey"))); // // Nothing to do. // } RegKey::~RegKey( void ) { DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::~RegKey"))); Close(); if (NULL != m_hChangeEvent) CloseHandle(m_hChangeEvent); } HRESULT RegKey::Open( REGSAM samDesired, // Access mask (i.e. KEY_READ, KEY_WRITE etc.) bool bCreate // Create key if it doesn't exist? ) const { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Open"))); DBGPRINT((DM_REG, DL_HIGH, TEXT("\thkeyRoot = 0x%08X, SubKey = \"%s\""), m_hkeyRoot, m_strSubKey.Cstr())); DWORD dwResult = ERROR_SUCCESS; Close(); if (bCreate) { DWORD dwDisposition; dwResult = RegCreateKeyEx(m_hkeyRoot, (LPCTSTR)m_strSubKey, 0, NULL, 0, samDesired, NULL, &m_hkey, &dwDisposition); } else { dwResult = RegOpenKeyEx(m_hkeyRoot, (LPCTSTR)m_strSubKey, 0, samDesired, &m_hkey); } return HRESULT_FROM_WIN32(dwResult); } void RegKey::Attach( HKEY hkey ) { Close(); m_strSubKey.Empty(); m_hkeyRoot = NULL; m_hkey = hkey; } void RegKey::Detach( void ) { m_hkey = NULL; } void RegKey::Close( void ) const { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Close"))); DBGPRINT((DM_REG, DL_HIGH, TEXT("\thkeyRoot = 0x%08X, SubKey = \"%s\""), m_hkeyRoot, m_strSubKey.Cstr())); 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); } } // // 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) and write it to a CString object. // HRESULT RegKey::GetValue( LPCTSTR pszValueName, CString *pstrDataOut ) const { HRESULT hr = E_FAIL; int cch = GetValueBufferSize(pszValueName) / sizeof(TCHAR); if (NULL != pstrDataOut && 0 < cch) { hr = GetValue(pszValueName, REG_SZ, (LPBYTE)pstrDataOut->GetBuffer(cch), pstrDataOut->SizeBytes()); pstrDataOut->ReleaseBuffer(); } return hr; } // // Get a multi-text string value (REG_MULTI_SZ) and write it to a CArray object. // HRESULT RegKey::GetValue( LPCTSTR pszValueName, CArray *prgstrOut ) const { HRESULT hr = E_FAIL; int cb = GetValueBufferSize(pszValueName); if (NULL != prgstrOut && 0 < cb) { array_autoptr ptrTemp(new TCHAR[cb / sizeof(TCHAR)]); LPCTSTR psz = ptrTemp.get(); hr = GetValue(pszValueName, REG_MULTI_SZ, (LPBYTE)psz, cb); if (SUCCEEDED(hr)) { while(psz && TEXT('\0') != *psz) { prgstrOut->Append(CString(psz)); psz += lstrlen(psz) + 1; } } } 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, const CArray& rgstrSrc ) { array_autoptr ptrValues(CreateDoubleNulTermList(rgstrSrc)); int cch = 1; int n = rgstrSrc.Count(); for (int i = 0; i < n; i++) cch += rgstrSrc[i].Length() + 1; return SetValue(pszValueName, REG_MULTI_SZ, (const LPBYTE)ptrValues.get(), cch * sizeof(TCHAR)); } LPTSTR RegKey::CreateDoubleNulTermList( const CArray& rgstrSrc ) const { int cEntries = rgstrSrc.Count(); int cch = 1; // Account for 2nd nul term. int i; for (i = 0; i < cEntries; i++) cch += rgstrSrc[i].Length() + 1; LPTSTR pszBuf = new TCHAR[cch]; LPTSTR pszWrite = pszBuf; for (i = 0; i < cEntries; i++) { CString& s = rgstrSrc[i]; lstrcpy(pszWrite, s); pszWrite += s.Length() + 1; } *pszWrite = TEXT('\0'); // Double nul term. return pszBuf; } void RegKey::OnChange( HKEY hkey ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::OnChange"))); // // Default does nothing. // } DWORD RegKey::NotifyWaitThreadProc( LPVOID pvParam ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::NotifyWaitThreadProc"))); RegKey *pThis = (RegKey *)pvParam; while(NULL != pThis->m_hkey) { DBGPRINT((DM_REG, DL_HIGH, TEXT("RegNotifyChangeKey(0x%08X, %d, 0x%08X, 0x%08X, %d)"), pThis->m_hkey, pThis->m_bWatchSubtree, pThis->m_dwChangeFilter, pThis->m_hChangeEvent, true)); LONG lResult = RegNotifyChangeKeyValue(pThis->m_hkey, pThis->m_bWatchSubtree, pThis->m_dwChangeFilter, pThis->m_hChangeEvent, true); if (ERROR_SUCCESS != lResult) { DBGERROR((TEXT("RegNotifyChangeKeyValue failed with error %d"), lResult)); return 0; } else { DBGPRINT((DM_REG, DL_MID, TEXT("Waiting for reg change notification..."))); switch(WaitForSingleObject(pThis->m_hChangeEvent, INFINITE)) { case WAIT_OBJECT_0: if (NULL != pThis->m_hkey) { DBGPRINT((DM_REG, DL_MID, TEXT("Rcv'd reg change notification"))); pThis->OnChange(pThis->m_hkey); } break; case WAIT_FAILED: DBGERROR((TEXT("Registry chg wait failed with error %d"), GetLastError())); break; default: break; } } } return 0; } HRESULT RegKey::WatchForChange( DWORD dwChangeFilter, bool bWatchSubtree ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::WatchForChange"))); HRESULT hr = E_FAIL; if (NULL != m_hChangeEvent || NULL == m_hkey) return E_FAIL; m_hChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (NULL == m_hChangeEvent) { DBGERROR((TEXT("CreateEvent failed error %d"), GetLastError())); return HRESULT_FROM_WIN32(GetLastError()); } m_dwChangeFilter = dwChangeFilter; m_bWatchSubtree = bWatchSubtree; DWORD dwThreadId = 0; HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NotifyWaitThreadProc, this, 0, &dwThreadId); if (INVALID_HANDLE_VALUE != hThread) { DBGPRINT((DM_REG, DL_MID, TEXT("Reg key chg watch thread ID = %d"), dwThreadId)); CloseHandle(hThread); hr = NOERROR; } return hr; } HRESULT RegKey::WaitForChange( DWORD dwChangeFilter, bool bWatchSubtree ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::WaitForChange"))); HRESULT hr = NOERROR; LONG lResult = RegNotifyChangeKeyValue(m_hkey, bWatchSubtree, dwChangeFilter, NULL, false); if (ERROR_SUCCESS != lResult) { DBGERROR((TEXT("RegNotifyChangeKeyValue failed with error %d"), lResult)); hr = HRESULT_FROM_WIN32(lResult); } return hr; } #if DBG //----------------------------------------------------------------------------- // DEBUG ONLY //----------------------------------------------------------------------------- RegKeyChg::RegKeyChg( HKEY hkeyRoot, LPCTSTR pszSubKey ) : RegKey(hkeyRoot, pszSubKey) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::RegKeyChg"))); HRESULT hr = Open(KEY_READ | KEY_NOTIFY); if (SUCCEEDED(hr)) { hr = WatchForChange(REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME, true); if (FAILED(hr)) { DBGERROR((TEXT("WatchForChange failed with error 0x%08X"), hr)); } } else if (ERROR_FILE_NOT_FOUND != HRESULT_CODE(hr)) { DBGERROR((TEXT("Error 0x%08X opening key 0x%08X \"%s\""), hr, hkeyRoot, pszSubKey)); } } RegKeyChg::~RegKeyChg( void ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::~RegKeyChg"))); } void RegKeyChg::OnChange( HKEY hkey ) { DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::OnChange"))); RegKey key; key.Attach(hkey); DebugRegParams dp; HRESULT hr = key.GetValue(REGSTR_VAL_DEBUGPARAMS, (LPBYTE)&dp, sizeof(dp)); if (SUCCEEDED(hr)) { DBGPRINT((DM_REG, DL_HIGH, TEXT("Setting new debug parameters"))); DBGPRINTMASK(dp.PrintMask); DBGPRINTLEVEL(dp.PrintLevel); DBGPRINTVERBOSE(dp.PrintVerbose); DBGTRACEMASK(dp.TraceMask); DBGTRACELEVEL(dp.TraceLevel); DBGTRACEVERBOSE(dp.TraceVerbose); DBGTRACEONEXIT(dp.TraceOnExit); } else DBGERROR((TEXT("GetValue failed with error 0x%08X"), hr)); key.Detach(); } #endif // #if DBG