427 lines
12 KiB
C++
427 lines
12 KiB
C++
//
|
|
// Registry.cpp
|
|
//
|
|
// Wrapper class to make the registry less painful.
|
|
//
|
|
// 3/04/1998 KenSh Created
|
|
// 3/28/1999 KenSh Added DeleteAllValues, CloneSubKey
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "Registry.h"
|
|
|
|
#ifdef _DEBUG
|
|
#ifdef DEBUG_NEW
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#ifndef ASSERT
|
|
#define ASSERT(x)
|
|
#endif
|
|
|
|
#ifndef _countof
|
|
#define _countof(ar) (sizeof(ar) / sizeof((ar)[0]))
|
|
#endif
|
|
|
|
|
|
CRegistry::CRegistry(HKEY hkeyParent, LPCTSTR pszKey, REGSAM dwAccessFlags /*=KEY_ALL_ACCESS*/, BOOL bCreateIfMissing /*=TRUE*/)
|
|
{
|
|
m_hKey = NULL;
|
|
|
|
ASSERT(hkeyParent != NULL);
|
|
ASSERT(pszKey != NULL);
|
|
|
|
if (bCreateIfMissing)
|
|
CreateKey(hkeyParent, pszKey, dwAccessFlags);
|
|
else
|
|
OpenKey(hkeyParent, pszKey, dwAccessFlags);
|
|
}
|
|
|
|
CRegistry::~CRegistry()
|
|
{
|
|
CloseKey();
|
|
}
|
|
|
|
void CRegistry::CloseKey()
|
|
{
|
|
if (m_hKey != NULL)
|
|
{
|
|
RegCloseKey(m_hKey);
|
|
m_hKey = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL CRegistry::OpenKey(HKEY hkeyParent, LPCTSTR pszKey, REGSAM dwAccessFlags /*=KEY_ALL_ACCESS*/)
|
|
{
|
|
CloseKey();
|
|
return (ERROR_SUCCESS == RegOpenKeyEx(hkeyParent, pszKey, 0, dwAccessFlags, &m_hKey));
|
|
}
|
|
|
|
BOOL CRegistry::CreateKey(HKEY hkeyParent, LPCTSTR pszKey, REGSAM dwAccessFlags /*=KEY_ALL_ACCESS*/)
|
|
{
|
|
DWORD dwDisposition;
|
|
CloseKey();
|
|
return (ERROR_SUCCESS == RegCreateKeyEx(hkeyParent, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
dwAccessFlags, NULL, &m_hKey, &dwDisposition));
|
|
}
|
|
|
|
BOOL CRegistry::OpenSubKey(LPCTSTR pszKey, REGSAM dwAccessFlags /*=KEY_ALL_ACCESS*/)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
if (m_hKey)
|
|
{
|
|
HKEY hkey = m_hKey;
|
|
m_hKey = NULL;
|
|
bResult = OpenKey(hkey, pszKey, dwAccessFlags);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL CRegistry::CreateSubKey(LPCTSTR pszKey, REGSAM dwAccessFlags /*=KEY_ALL_ACCESS*/)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
if (m_hKey)
|
|
{
|
|
HKEY hkey = m_hKey;
|
|
m_hKey = NULL;
|
|
bResult = CreateKey(hkey, pszKey, dwAccessFlags);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
DWORD RegDeleteSubKey(HKEY hkey, LPCTSTR pszSubKey)
|
|
{
|
|
{
|
|
HKEY hSubKey;
|
|
LONG err = RegOpenKeyEx(hkey, pszSubKey, 0, KEY_ALL_ACCESS, &hSubKey);
|
|
if (ERROR_SUCCESS == err)
|
|
{
|
|
DWORD dwNumSubKeys;
|
|
RegQueryInfoKey(hSubKey, NULL, NULL, NULL, &dwNumSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
for (DWORD iSubKey = dwNumSubKeys; iSubKey > 0; iSubKey--)
|
|
{
|
|
TCHAR szSubKey[260];
|
|
DWORD cchSubKey = _countof(szSubKey);
|
|
if (ERROR_SUCCESS == RegEnumKeyEx(hSubKey, iSubKey-1, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
|
|
{
|
|
RegDeleteSubKey(hSubKey, szSubKey);
|
|
}
|
|
}
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
}
|
|
|
|
return RegDeleteKey(hkey, pszSubKey);
|
|
}
|
|
|
|
BOOL CRegistry::DeleteSubKey(LPCTSTR pszKey)
|
|
{
|
|
if (m_hKey && RegDeleteSubKey(m_hKey, pszKey) == ERROR_SUCCESS)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Zero is returned if and only if the value does not exist.
|
|
DWORD CRegistry::GetValueSize(LPCTSTR pszValueName)
|
|
{
|
|
DWORD dwSize = 0;
|
|
if (m_hKey)
|
|
RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, NULL, &dwSize);
|
|
return dwSize;
|
|
}
|
|
|
|
#ifdef _AFX
|
|
BOOL CRegistry::QueryStringValue(LPCTSTR pszValueName, CString& strResult)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if (m_hKey)
|
|
{
|
|
TCHAR szBuf[50]; // default buffer for short strings
|
|
DWORD dwSize = sizeof(szBuf);
|
|
LONG lResult;
|
|
|
|
#if _REG_STRONGTYPES
|
|
DWORD dwType;
|
|
lResult = RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
|
|
if ((lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA) && dwType == REG_SZ)
|
|
#else
|
|
lResult = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)szBuf, &dwSize);
|
|
if (lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
|
|
#endif
|
|
{
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
strResult = szBuf;
|
|
bSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
int cch = (dwSize / sizeof(TCHAR)) - 1;
|
|
LPTSTR psz = strResult.GetBufferSetLength(cch);
|
|
bSuccess = (ERROR_SUCCESS == RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)psz, &dwSize));
|
|
strResult.ReleaseBuffer(cch);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
strResult.Empty();
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
#endif // _AFX
|
|
|
|
#ifdef _AFX
|
|
CString CRegistry::QueryStringValue(LPCTSTR pszValueName)
|
|
{
|
|
CString str;
|
|
QueryStringValue(pszValueName, str);
|
|
return str;
|
|
}
|
|
#endif // _AFX
|
|
|
|
#ifdef _AFX
|
|
BOOL CRegistry::SetStringValue(LPCTSTR pszValueName, const CString& strData)
|
|
{
|
|
return m_hKey && (ERROR_SUCCESS == RegSetValueEx(m_hKey, pszValueName, 0, REG_SZ, (LPBYTE)(LPCTSTR)strData, (DWORD)strData.GetLength() + 1));
|
|
}
|
|
#endif // _AFX
|
|
|
|
BOOL CRegistry::QueryStringValue(LPCTSTR pszValueName, LPTSTR pszBuf, int cchBuf, int* pNumCharsWritten)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
if (m_hKey)
|
|
{
|
|
#if _REG_STRONGTYPES
|
|
DWORD dwType;
|
|
bSuccess = (ERROR_SUCCESS == RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, (LPBYTE)pszBuf, (DWORD*)&cchBuf)
|
|
&& dwType == REG_SZ);
|
|
#else
|
|
bSuccess = (ERROR_SUCCESS == RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)pszBuf, (DWORD*)&cchBuf));
|
|
#endif
|
|
if (pNumCharsWritten != NULL)
|
|
{
|
|
if (!bSuccess)
|
|
*pNumCharsWritten = 0;
|
|
else
|
|
*pNumCharsWritten = (int)((DWORD)cchBuf / sizeof(TCHAR)) - 1;
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
// string is allocated with new TCHAR[], use delete[] to delete it.
|
|
#if _REG_ALLOCMEM
|
|
LPTSTR CRegistry::QueryStringValue(LPCTSTR pszValueName, int* pNumCharsWritten /*=NULL*/)
|
|
{
|
|
LPTSTR pszResult = NULL;
|
|
int cch = 0;
|
|
|
|
if (m_hKey)
|
|
{
|
|
TCHAR szBuf[50]; // default buffer for short strings
|
|
DWORD dwSize = sizeof(szBuf);
|
|
LONG lResult;
|
|
|
|
#if _REG_STRONGTYPES
|
|
DWORD dwType;
|
|
lResult = RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
|
|
if ((lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA) && dwType == REG_SZ)
|
|
#else
|
|
lResult = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)szBuf, &dwSize);
|
|
if (lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
|
|
#endif
|
|
{
|
|
cch = (dwSize / sizeof(TCHAR)) - 1;
|
|
pszResult = new TCHAR[cch+1];
|
|
|
|
if (pszResult != NULL)
|
|
{
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
memcpy(pszResult, szBuf, dwSize);
|
|
}
|
|
else
|
|
{
|
|
if (ERROR_SUCCESS != RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)pszResult, &dwSize))
|
|
{
|
|
delete [] pszResult;
|
|
pszResult = NULL;
|
|
cch = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pNumCharsWritten != NULL)
|
|
*pNumCharsWritten = cch;
|
|
|
|
return pszResult;
|
|
}
|
|
#endif // _REG_ALLOCMEM
|
|
|
|
BOOL CRegistry::SetStringValue(LPCTSTR pszValueName, LPCTSTR pszData)
|
|
{
|
|
return m_hKey && (ERROR_SUCCESS == RegSetValueEx(m_hKey, pszValueName, 0, REG_SZ, (LPBYTE)pszData, (DWORD)(lstrlen(pszData)+1) * sizeof(TCHAR)));
|
|
}
|
|
|
|
BOOL CRegistry::QueryDwordValue(LPCTSTR pszValueName, DWORD* pVal)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if (m_hKey)
|
|
{
|
|
DWORD dwSize = sizeof(DWORD);
|
|
|
|
#if _REG_STRONGTYPES
|
|
DWORD dwType;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, (LPBYTE)pVal, &dwSize))
|
|
{
|
|
if (dwType == REG_DWORD || (dwType == REG_BINARY && dwSize == sizeof(DWORD)))
|
|
bSuccess = TRUE;
|
|
}
|
|
#else
|
|
bSuccess = (ERROR_SUCCESS == RegQueryValueEx(m_hKey, pszValueName, NULL, NULL, (LPBYTE)pVal, &dwSize));
|
|
#endif
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL CRegistry::SetDwordValue(LPCTSTR pszValueName, DWORD dwVal)
|
|
{
|
|
return m_hKey && (ERROR_SUCCESS == RegSetValueEx(m_hKey, pszValueName, 0, REG_DWORD, (LPBYTE)&dwVal, sizeof(DWORD)));
|
|
}
|
|
|
|
BOOL CRegistry::SetBinaryValue(LPCTSTR pszValueName, LPCVOID pvData, DWORD cbData)
|
|
{
|
|
return m_hKey && (ERROR_SUCCESS == RegSetValueEx(m_hKey, pszValueName, 0, REG_BINARY, (LPBYTE)pvData, cbData));
|
|
}
|
|
|
|
BOOL CRegistry::DeleteAllValues()
|
|
{
|
|
if (m_hKey)
|
|
{
|
|
TCHAR szValueName[MAX_PATH];
|
|
for (;;)
|
|
{
|
|
DWORD cbValueName = _countof(szValueName);
|
|
if (ERROR_SUCCESS != RegEnumValue(m_hKey, 0, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
|
|
return TRUE;
|
|
if (!DeleteValue(szValueName))
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Copies the named subkey from this registry key to the named subkey in the target registry key.
|
|
BOOL CRegistry::CloneSubKey(LPCTSTR pszExistingSubKey, CRegistry& regDest, BOOL bRecursive)
|
|
{
|
|
ASSERT(pszExistingSubKey != NULL);
|
|
|
|
if (!m_hKey || !regDest.m_hKey)
|
|
return FALSE;
|
|
|
|
CRegistry regSrc;
|
|
if (!regSrc.OpenKey(m_hKey, pszExistingSubKey, KEY_READ))
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD cbAlloc = 256;
|
|
HANDLE hHeap = GetProcessHeap();
|
|
BYTE* pbData = (BYTE*)HeapAlloc(hHeap, 0, cbAlloc);
|
|
if (pbData)
|
|
{
|
|
// Copy values first
|
|
for (DWORD iValue = 0; ; iValue++)
|
|
{
|
|
TCHAR szValueName[MAX_PATH];
|
|
DWORD cbValueName = _countof(szValueName);
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
|
|
if (ERROR_SUCCESS != RegEnumValue(regSrc.m_hKey, iValue, szValueName, &cbValueName, NULL, &dwType, NULL, &cbData))
|
|
break;
|
|
|
|
if (cbData > cbAlloc)
|
|
{
|
|
BYTE* pbDataNew = (BYTE*)HeapReAlloc(hHeap, 0, pbData, cbData + 256);
|
|
if (pbDataNew == NULL)
|
|
{
|
|
HeapFree(hHeap, 0, pbData);
|
|
return FALSE;
|
|
}
|
|
pbData = pbDataNew;
|
|
cbAlloc = cbData + 256;
|
|
}
|
|
|
|
if (ERROR_SUCCESS != RegQueryValueEx(regSrc.m_hKey, szValueName, NULL, NULL, pbData, &cbData))
|
|
break; // REVIEW: return FALSE?
|
|
|
|
if (ERROR_SUCCESS != RegSetValueEx(regDest.m_hKey, szValueName, 0, dwType, pbData, cbData))
|
|
break; // REVIEW: return FALSE? (need to free memory)
|
|
}
|
|
|
|
HeapFree(hHeap, 0, pbData);
|
|
}
|
|
|
|
// Copy subkeys
|
|
if (bRecursive)
|
|
{
|
|
for (DWORD iSubKey = 0; ; iSubKey++)
|
|
{
|
|
TCHAR szKeyName[MAX_PATH];
|
|
DWORD cbKeyName = _countof(szKeyName);
|
|
if (ERROR_SUCCESS != RegEnumKeyEx(regSrc.m_hKey, iSubKey, szKeyName, &cbKeyName, NULL, NULL, NULL, NULL))
|
|
break;
|
|
|
|
CRegistry regDest2;
|
|
if (!regDest2.CreateKey(regDest.m_hKey, szKeyName, KEY_ALL_ACCESS))
|
|
return FALSE;
|
|
|
|
if (!regSrc.CloneSubKey(szKeyName, regDest2, TRUE))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Copies the named subkey to a new subkey of this registry class, with a new name.
|
|
BOOL CRegistry::CloneSubKey(LPCTSTR pszExistingSubKey, LPCTSTR pszNewSubKey, BOOL bRecursive)
|
|
{
|
|
ASSERT(pszExistingSubKey != NULL);
|
|
ASSERT(pszNewSubKey != NULL);
|
|
ASSERT(0 != lstrcmpi(pszExistingSubKey, pszNewSubKey)); // names can't be the same
|
|
|
|
CRegistry regDest;
|
|
if (!m_hKey || !regDest.CreateKey(m_hKey, pszNewSubKey, KEY_ALL_ACCESS))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return CloneSubKey(pszExistingSubKey, regDest, bRecursive);
|
|
}
|