You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
371 lines
8.5 KiB
371 lines
8.5 KiB
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "registry.h"
|
|
|
|
RegKey::RegKey(
|
|
void
|
|
) : m_hkeyRoot(NULL),
|
|
m_hkey(NULL)
|
|
{
|
|
DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey [default]")));
|
|
}
|
|
|
|
|
|
RegKey::RegKey(
|
|
HKEY hkeyRoot,
|
|
LPCTSTR pszSubKey
|
|
) : m_hkeyRoot(hkeyRoot),
|
|
m_hkey(NULL),
|
|
m_strSubKey(pszSubKey)
|
|
{
|
|
DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey")));
|
|
//
|
|
// Nothing to do.
|
|
//
|
|
}
|
|
|
|
|
|
RegKey::~RegKey(
|
|
void
|
|
)
|
|
{
|
|
DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::~RegKey")));
|
|
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
|
|
{
|
|
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)
|
|
{
|
|
//
|
|
// Get a buffer 1 character larger than needed. Zero-out
|
|
// the entire buffer in case the data in the registry is not
|
|
// nul-terminated.
|
|
//
|
|
LPTSTR pszBuffer = pstrDataOut->GetBuffer(cch + 1);
|
|
ZeroMemory(pszBuffer, pstrDataOut->SizeBytes());
|
|
|
|
hr = GetValue(pszValueName,
|
|
REG_SZ,
|
|
(LPBYTE)pszBuffer,
|
|
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)
|
|
{
|
|
//
|
|
// Allocate a buffer one character larger than what we need
|
|
// and then zero-init that buffer. This is in case the data in the
|
|
// registry is not nul-terminated.
|
|
//
|
|
const size_t cch = cb / sizeof(TCHAR);
|
|
array_autoptr<TCHAR> ptrTemp(new TCHAR[cch + 1]);
|
|
LPTSTR psz = ptrTemp.get();
|
|
ZeroMemory(psz, (cch + 1) * sizeof(TCHAR));
|
|
|
|
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();
|
|
size_t 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];
|
|
StringCchCopyEx(pszWrite, cch, s, &pszWrite, &cch, 0);
|
|
//
|
|
// Advance one beyond terminating nul.
|
|
//
|
|
pszWrite++;
|
|
cch--;
|
|
}
|
|
DBGASSERT((1 == cch));
|
|
*pszWrite = TEXT('\0'); // Double nul term.
|
|
return pszBuf;
|
|
}
|