545 lines
13 KiB
C++
545 lines
13 KiB
C++
|
#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<CString> object.
|
||
|
//
|
||
|
HRESULT
|
||
|
RegKey::GetValue(
|
||
|
LPCTSTR pszValueName,
|
||
|
CArray<CString> *prgstrOut
|
||
|
) const
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
int cb = GetValueBufferSize(pszValueName);
|
||
|
if (NULL != prgstrOut && 0 < cb)
|
||
|
{
|
||
|
array_autoptr<TCHAR> 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<CString>& rgstrSrc
|
||
|
)
|
||
|
{
|
||
|
array_autoptr<TCHAR> 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<CString>& 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
|