478 lines
13 KiB
C++
478 lines
13 KiB
C++
/*****************************************************************/
|
|
/** Microsoft Windows for Workgroups **/
|
|
/** Copyright (C) Microsoft Corp., 1995-1996 **/
|
|
/*****************************************************************/
|
|
|
|
/*
|
|
regentry.cpp
|
|
registry access classes
|
|
|
|
This file contains classes which enable
|
|
convenient access the registry for entries.
|
|
|
|
FILE HISTORY:
|
|
lens 10/15/95 Created
|
|
ChrisPi 6/21/96 Added GetBinary(), SetValue() for binary
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include <regentry.h>
|
|
#include <strutil.h>
|
|
|
|
RegEntry::RegEntry(LPCTSTR pszSubKey, HKEY hkey, BOOL fCreate, REGSAM samDesired)
|
|
: m_pbValueBuffer(NULL),
|
|
m_cbValueBuffer(0),
|
|
m_fValuesWritten(FALSE),
|
|
m_szNULL('\0')
|
|
{
|
|
// Open with desired access if it is specified explicitly; otherwise, use
|
|
// the default access.
|
|
if (samDesired) {
|
|
if (fCreate) {
|
|
DWORD dwDisposition;
|
|
|
|
m_error = ::RegCreateKeyEx(hkey,
|
|
pszSubKey,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
samDesired,
|
|
NULL,
|
|
&m_hkey,
|
|
&dwDisposition);
|
|
}
|
|
else {
|
|
m_error = ::RegOpenKeyEx(hkey, pszSubKey, 0, samDesired, &m_hkey);
|
|
}
|
|
}
|
|
else {
|
|
if (fCreate) {
|
|
m_error = ::RegCreateKey(hkey, pszSubKey, &m_hkey);
|
|
}
|
|
else {
|
|
m_error = ::RegOpenKey(hkey, pszSubKey, &m_hkey);
|
|
}
|
|
}
|
|
|
|
m_fhkeyValid = (m_error == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
RegEntry::~RegEntry()
|
|
{
|
|
ChangeKey(NULL);
|
|
delete [] m_pbValueBuffer;
|
|
}
|
|
|
|
|
|
VOID RegEntry::ChangeKey(HKEY hNewKey)
|
|
{
|
|
// hNewKey assumed to be valid or never used
|
|
// (as in destructor).
|
|
|
|
if (m_fValuesWritten) {
|
|
FlushKey();
|
|
}
|
|
if (m_fhkeyValid) {
|
|
::RegCloseKey(m_hkey);
|
|
}
|
|
m_hkey = hNewKey;
|
|
}
|
|
|
|
VOID RegEntry::UpdateWrittenStatus()
|
|
{
|
|
if (m_error == ERROR_SUCCESS) {
|
|
m_fValuesWritten = TRUE;
|
|
}
|
|
}
|
|
|
|
long RegEntry::SetValue(LPCTSTR pszValue, LPCTSTR string)
|
|
{
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegSetValueEx(m_hkey, pszValue, 0, REG_SZ,
|
|
(LPBYTE)string, (lstrlen(string)+1) * sizeof(*string));
|
|
UpdateWrittenStatus();
|
|
}
|
|
return m_error;
|
|
}
|
|
|
|
long RegEntry::SetValue(LPCTSTR pszValue, unsigned long dwNumber)
|
|
{
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegSetValueEx(m_hkey, pszValue, 0, REG_BINARY,
|
|
(LPBYTE)&dwNumber, sizeof(dwNumber));
|
|
UpdateWrittenStatus();
|
|
}
|
|
return m_error;
|
|
}
|
|
|
|
long RegEntry::SetValue(LPCTSTR pszValue,
|
|
void* pData,
|
|
DWORD cbLength)
|
|
{
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegSetValueEx( m_hkey,
|
|
pszValue,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE) pData,
|
|
cbLength);
|
|
UpdateWrittenStatus();
|
|
}
|
|
return m_error;
|
|
}
|
|
|
|
long RegEntry::DeleteValue(LPCTSTR pszValue)
|
|
{
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegDeleteValue(m_hkey, pszValue);
|
|
UpdateWrittenStatus();
|
|
}
|
|
return m_error;
|
|
}
|
|
|
|
long RegEntry::GetNumber(LPCTSTR pszValue, long dwDefault)
|
|
{
|
|
DWORD dwType = REG_BINARY;
|
|
long dwNumber = 0L;
|
|
DWORD dwSize = sizeof(dwNumber);
|
|
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegQueryValueEx(m_hkey, pszValue, 0, &dwType, (LPBYTE)&dwNumber,
|
|
&dwSize);
|
|
}
|
|
|
|
// If the call succeeded, make sure that the returned data matches our
|
|
// expectations.
|
|
ASSERT(m_error != ERROR_SUCCESS ||
|
|
(REG_BINARY == dwType && sizeof(dwNumber) == dwSize) ||
|
|
REG_DWORD == dwType);
|
|
|
|
if (m_error != ERROR_SUCCESS)
|
|
dwNumber = dwDefault;
|
|
|
|
return dwNumber;
|
|
}
|
|
|
|
|
|
// The GetNumberIniStyle method performs the same function as GetNumber,
|
|
// but in a style compatible with the old GetPrivateProfileInt API.
|
|
// Specfically it means:
|
|
// - If the value is stored in the registry as a string, it attempts to
|
|
// convert it to an integer.
|
|
// - If the value is negative, it returns 0.
|
|
|
|
ULONG RegEntry::GetNumberIniStyle(LPCTSTR pszValueName, ULONG dwDefault)
|
|
{
|
|
DWORD dwType = REG_BINARY;
|
|
ULONG dwNumber = 0L;
|
|
DWORD cbLength = m_cbValueBuffer;
|
|
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegQueryValueEx(m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&cbLength);
|
|
|
|
// Try again with a larger buffer if the first one is too small,
|
|
// or if there wasn't already a buffer allocated.
|
|
if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
|
|
|| ERROR_MORE_DATA == m_error) {
|
|
|
|
ASSERT(cbLength > m_cbValueBuffer);
|
|
|
|
ResizeValueBuffer(cbLength);
|
|
|
|
m_error = RegQueryValueEx( m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&cbLength );
|
|
}
|
|
|
|
if (ERROR_SUCCESS == m_error) {
|
|
switch(dwType) {
|
|
case REG_DWORD:
|
|
case REG_BINARY:
|
|
ASSERT(sizeof(dwNumber) == cbLength);
|
|
|
|
dwNumber = * (LPDWORD) m_pbValueBuffer;
|
|
break;
|
|
|
|
case REG_SZ:
|
|
{
|
|
LONG lNumber = RtStrToInt((LPCTSTR) m_pbValueBuffer);
|
|
|
|
// Convert negative numbers to zero, to match
|
|
// GetPrivateProfileInt's behavior.
|
|
dwNumber = lNumber < 0 ? 0 : lNumber;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("Invalid value type (%lu) returned by RegQueryValueEx()",
|
|
dwType));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_error != ERROR_SUCCESS) {
|
|
dwNumber = dwDefault;
|
|
}
|
|
|
|
return dwNumber;
|
|
}
|
|
|
|
|
|
LPTSTR RegEntry::GetString(LPCTSTR pszValueName)
|
|
{
|
|
DWORD dwType = REG_SZ;
|
|
DWORD length = m_cbValueBuffer;
|
|
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegQueryValueEx( m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&length );
|
|
// Try again with a larger buffer if the first one is too small,
|
|
// or if there wasn't already a buffer allocated.
|
|
if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
|
|
|| ERROR_MORE_DATA == m_error) {
|
|
|
|
ASSERT(length > m_cbValueBuffer);
|
|
|
|
ResizeValueBuffer(length);
|
|
|
|
m_error = ::RegQueryValueEx( m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&length );
|
|
}
|
|
if (m_error == ERROR_SUCCESS) {
|
|
if ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ)) {
|
|
m_error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
if ((m_error != ERROR_SUCCESS) || (length == 0)) {
|
|
return &m_szNULL;
|
|
}
|
|
return (LPTSTR) m_pbValueBuffer;
|
|
}
|
|
|
|
DWORD RegEntry::GetBinary( LPCTSTR pszValueName,
|
|
void** ppvData)
|
|
{
|
|
ASSERT(ppvData);
|
|
DWORD dwType = REG_BINARY;
|
|
DWORD length = m_cbValueBuffer;
|
|
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegQueryValueEx( m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&length );
|
|
// Try again with a larger buffer if the first one is too small,
|
|
// or if there wasn't already a buffer allocated.
|
|
if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
|
|
|| ERROR_MORE_DATA == m_error) {
|
|
|
|
ASSERT(length > m_cbValueBuffer);
|
|
|
|
ResizeValueBuffer(length);
|
|
|
|
m_error = ::RegQueryValueEx( m_hkey,
|
|
pszValueName,
|
|
0,
|
|
&dwType,
|
|
m_pbValueBuffer,
|
|
&length );
|
|
}
|
|
if (m_error == ERROR_SUCCESS) {
|
|
if (dwType != REG_BINARY) {
|
|
m_error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
if ((m_error != ERROR_SUCCESS) || (length == 0)) {
|
|
*ppvData = NULL;
|
|
length = 0;
|
|
}
|
|
else
|
|
{
|
|
*ppvData = m_pbValueBuffer;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
// BUGBUG - Use LocalReAlloc instead of new/delete?
|
|
VOID RegEntry::ResizeValueBuffer(DWORD length)
|
|
{
|
|
LPBYTE pbNewBuffer;
|
|
|
|
if ((m_error == ERROR_SUCCESS || m_error == ERROR_MORE_DATA)
|
|
&& (length > m_cbValueBuffer)) {
|
|
pbNewBuffer = new BYTE[length];
|
|
if (pbNewBuffer) {
|
|
delete [] m_pbValueBuffer;
|
|
m_pbValueBuffer = pbNewBuffer;
|
|
m_cbValueBuffer = length;
|
|
}
|
|
else {
|
|
m_error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
// BUGBUG - Support other OpenKey switches from constructor
|
|
VOID RegEntry::MoveToSubKey(LPCTSTR pszSubKeyName)
|
|
{
|
|
HKEY _hNewKey;
|
|
|
|
if (m_fhkeyValid) {
|
|
m_error = ::RegOpenKey ( m_hkey,
|
|
pszSubKeyName,
|
|
&_hNewKey );
|
|
if (m_error == ERROR_SUCCESS) {
|
|
ChangeKey(_hNewKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
RegEnumValues::RegEnumValues(RegEntry *pReqRegEntry)
|
|
: m_pRegEntry(pReqRegEntry),
|
|
m_iEnum(0),
|
|
m_pchName(NULL),
|
|
m_pbValue(NULL)
|
|
{
|
|
m_error = m_pRegEntry->GetError();
|
|
if (m_error == ERROR_SUCCESS) {
|
|
m_error = ::RegQueryInfoKey (m_pRegEntry->GetKey(), // Key
|
|
NULL, // Buffer for class string
|
|
NULL, // Size of class string buffer
|
|
NULL, // Reserved
|
|
NULL, // Number of subkeys
|
|
NULL, // Longest subkey name
|
|
NULL, // Longest class string
|
|
&m_cEntries, // Number of value entries
|
|
&m_cMaxValueName, // Longest value name
|
|
&m_cMaxData, // Longest value data
|
|
NULL, // Security descriptor
|
|
NULL ); // Last write time
|
|
}
|
|
if (m_error == ERROR_SUCCESS) {
|
|
if (m_cEntries != 0) {
|
|
m_cMaxValueName++; // REG_SZ needs one more for null
|
|
m_cMaxData++; // REG_SZ needs one more for null
|
|
m_pchName = new TCHAR[m_cMaxValueName];
|
|
if (!m_pchName) {
|
|
m_error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
if (m_cMaxData) {
|
|
m_pbValue = new BYTE[m_cMaxData];
|
|
if (!m_pbValue) {
|
|
m_error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RegEnumValues::~RegEnumValues()
|
|
{
|
|
delete m_pchName;
|
|
delete m_pbValue;
|
|
}
|
|
|
|
long RegEnumValues::Next()
|
|
{
|
|
if (m_error != ERROR_SUCCESS) {
|
|
return m_error;
|
|
}
|
|
if (m_cEntries == m_iEnum) {
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
|
|
DWORD cchName = m_cMaxValueName;
|
|
|
|
m_dwDataLength = m_cMaxData;
|
|
m_error = ::RegEnumValue ( m_pRegEntry->GetKey(), // Key
|
|
m_iEnum, // Index of value
|
|
m_pchName, // Address of buffer for value name
|
|
&cchName, // Address for size of buffer
|
|
NULL, // Reserved
|
|
&m_dwType, // Data type
|
|
m_pbValue, // Address of buffer for value data
|
|
&m_dwDataLength ); // Address for size of data
|
|
m_iEnum++;
|
|
return m_error;
|
|
}
|
|
|
|
RegEnumSubKeys::RegEnumSubKeys(RegEntry *pReqRegEntry)
|
|
: m_pRegEntry(pReqRegEntry),
|
|
m_iEnum(0),
|
|
m_pchName(NULL)
|
|
{
|
|
m_error = m_pRegEntry->GetError();
|
|
if (m_error == ERROR_SUCCESS) {
|
|
m_error = ::RegQueryInfoKey ( m_pRegEntry->GetKey(), // Key
|
|
NULL, // Buffer for class string
|
|
NULL, // Size of class string buffer
|
|
NULL, // Reserved
|
|
&m_cEntries, // Number of subkeys
|
|
&m_cMaxKeyName, // Longest subkey name
|
|
NULL, // Longest class string
|
|
NULL, // Number of value entries
|
|
NULL, // Longest value name
|
|
NULL, // Longest value data
|
|
NULL, // Security descriptor
|
|
NULL ); // Last write time
|
|
}
|
|
if (m_error == ERROR_SUCCESS) {
|
|
if (m_cEntries != 0) {
|
|
m_cMaxKeyName = m_cMaxKeyName + 1; // needs one more for null
|
|
m_pchName = new TCHAR[m_cMaxKeyName];
|
|
if (!m_pchName) {
|
|
m_error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RegEnumSubKeys::~RegEnumSubKeys()
|
|
{
|
|
delete m_pchName;
|
|
}
|
|
|
|
long RegEnumSubKeys::Next()
|
|
{
|
|
if (m_error != ERROR_SUCCESS) {
|
|
return m_error;
|
|
}
|
|
if (m_cEntries == m_iEnum) {
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
|
|
DWORD cchName = m_cMaxKeyName;
|
|
|
|
m_error = ::RegEnumKey ( m_pRegEntry->GetKey(), // Key
|
|
m_iEnum, // Index of value
|
|
m_pchName, // Address of buffer for subkey name
|
|
cchName); // Size of buffer
|
|
m_iEnum++;
|
|
return m_error;
|
|
}
|