|
|
/*++
Copyright (c) 1994-1998 Microsoft Corporation
Module Name :
registry.cpp
Abstract:
Registry classes
Author:
Ronald Meijer (ronaldm)
Project:
Internet Services Manager
Revision History:
--*/
//
// Include Files
//
#include "stdafx.h"
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include "comprop.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__; #endif
CRMCRegKey::CRMCRegKey ( IN HKEY hKeyBase, IN LPCTSTR lpszSubKey OPTIONAL, IN REGSAM regSam OPTIONAL, IN LPCTSTR lpszServerName OPTIONAL ) /*++
Routine Description:
Constructor registry key object for an existing key. Optionally provide a computer name to open a registry key on a remote computer.
Arguments:
HKEY hKeyBase : Base key handle LPCTSTR lpszSubKey : Name of the subkey REGSAM regSam : Security access mask for registry key LPCTSTR lpszServerName : Optional computer name whose registry to open
Return Value:
N/A
--*/ : m_hKey(NULL), m_dwDisposition(REG_OPENED_EXISTING_KEY) { HKEY hkBase = NULL; CError err;
//
// Change to NULL if server name is really local
//
lpszServerName = ::NormalizeServerName(lpszServerName); if (m_fLocal = (lpszServerName != NULL)) { //
// Remote connection.
//
err = ::RegConnectRegistry((LPTSTR)lpszServerName, hKeyBase, &hkBase); if (err.Failed()) { hkBase = NULL; } } else { hkBase = hKeyBase; }
if (err.Succeeded()) { if (lpszSubKey != NULL) { err = ::RegOpenKeyEx(hkBase, lpszSubKey, 0, regSam, &m_hKey); } else { m_hKey = hkBase; hkBase = NULL; }
if (hkBase && hkBase != hKeyBase) { ::RegCloseKey(hkBase); } }
if (err.Failed()) { m_hKey = NULL; } }
CRMCRegKey::CRMCRegKey( OUT BOOL * pfNewKeyCreated OPTIONAL, IN HKEY hKeyBase, IN LPCTSTR lpszSubKey OPTIONAL, IN DWORD dwOptions OPTIONAL, IN REGSAM regSam OPTIONAL, IN LPSECURITY_ATTRIBUTES pSecAttr OPTIONAL, IN LPCTSTR lpszServerName OPTIONAL ) /*++
Routine Description:
Constructor registry key object to create a new key. Optionally provide a computer name to open a registry key on a remote computer.
Arguments:
BOOL * pfNewKeyCreated : If specified, returns TRUE if a new key was created, FALSE if an existing one was opened. HKEY hKeyBase : Base key handle LPCTSTR lpszSubKey : Name of the subkey DWORD dwOptions : Option flags REGSAM regSam : Security access mask for registry key LPSECURITY_ATTRIBUTES pSecAttr : Security attributes LPCTSTR lpszServerName : Optional computer name whose registry to open
Return Value:
N/A
--*/ : m_hKey(NULL), m_dwDisposition(0L) { HKEY hkBase = NULL; CError err;
//
// Change to NULL if server name is really local
//
lpszServerName = NormalizeServerName(lpszServerName); if (m_fLocal = (lpszServerName != NULL)) { //
// Remote connection.
//
err = ::RegConnectRegistry((LPTSTR)lpszServerName, hKeyBase, &hkBase); if (err.Failed()) { hkBase = NULL; } } else { hkBase = hKeyBase; }
if (err.Succeeded()) { LPCTSTR szEmpty = _T("");
err = ::RegCreateKeyEx( hkBase, lpszSubKey, 0, // Reserved
(LPTSTR)szEmpty, dwOptions, regSam, pSecAttr, &m_hKey, &m_dwDisposition ); }
if (err.Failed()) { m_hKey = NULL; }
if (pfNewKeyCreated) { *pfNewKeyCreated = m_dwDisposition == REG_CREATED_NEW_KEY; } }
#ifdef _DEBUG
/* virtual */ void CRMCRegKey::AssertValid() const /*++
Routine Description:
Assert the object is in a valid state.
Arguments:
None
Return Value:
None
--*/ { ASSERT(m_hKey != NULL); }
/* virtual */ void CRMCRegKey::Dump( IN OUT CDumpContext & dc ) const /*++
Routine Description:
Dump the contents of the object to the debug string
Arguments:
CDumpContext & dc : debug context
Return Value:
None
--*/ { dc << _T("HKEY = ") << m_hKey << _T("Disposition = ") << m_dwDisposition << _T(" \r\n"); }
#endif // _DEBUG
CRMCRegKey::~CRMCRegKey() /*++
Routine Description:
Destructor. Close the key if it's open.
Arguments:
N/A
Return Value:
N/A
--*/ { if (m_hKey != NULL) { ::RegCloseKey(m_hKey); } }
/* protected */ DWORD CRMCRegKey::PrepareValue( IN LPCTSTR lpszValueName, OUT DWORD * pdwType, OUT DWORD * pcbSize, OUT BYTE ** ppbData ) /*++
Routine Description:
Prepare to read a value by finding the value's size.
Arguments:
LPCTSTR lpszValueName : Name of the value DWORD * pdwType : Returns the type registry value DWORD * pcbSize : Returns the size of the value BYTE ** ppbData : Will allocate and return the the value here
Return Value:
Error return code.
--*/ { CError err;
BYTE chDummy[2]; DWORD cbData = 0L;
do { //
// Set the resulting buffer size to 0.
//
*pcbSize = 0; *ppbData = NULL;
err = ::RegQueryValueEx( *this, (LPTSTR)lpszValueName, 0, pdwType, chDummy, &cbData );
//
// The only error we should get here is ERROR_MORE_DATA, but
// we may get no error if the value has no data.
//
if (err.Succeeded()) { //
// Just a fudgy number
//
cbData = sizeof(LONG); } else { if (err.Win32Error() != ERROR_MORE_DATA) { break; } }
//
// Allocate a buffer large enough for the data.
//
*ppbData = (LPBYTE)AllocMem((*pcbSize = cbData) + sizeof(LONG));
if (*ppbData == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; }
//
// Now that have a buffer, re-fetch the value.
//
err = ::RegQueryValueEx( *this, (LPTSTR)lpszValueName, 0, pdwType, *ppbData, pcbSize );
} while(FALSE);
if (err.Failed() && *ppbData != NULL) { FreeMem(*ppbData); }
return err; }
//
// Overloaded value query members; each returns ERROR_INVALID_PARAMETER
// if data exists but not in correct form to deliver into result object.
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DWORD CRMCRegKey::QueryValue( IN LPCTSTR lpszValueName, OUT CString & strResult, IN BOOL fAutoExpand, OPTIONAL OUT BOOL * pfExpanded OPTIONAL ) /*++
Routine Description:
Get a CString registry value.
Arguments:
LPCTSTR lpszValueName : Name of the value CString & strResult : String return value BOOL fAutoExpand : If TRUE auto expand REG_EXPAND_SZ on local computer. BOOL * pfExpanded : Optionally returns TRUE if expanded
Return Value:
Error return code.
--*/ { CError err;
DWORD dwType; DWORD cbData; BYTE * pabData = NULL;
try { do { err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData); if (err.Failed()) { break; }
//
// Guarantee that the data looks like a string
//
pabData[cbData] = 0;
switch(dwType) { case REG_EXPAND_SZ: if (IsLocal() && fAutoExpand) { int cchBuff = (cbData / sizeof(TCHAR)) + 2048; int cchRequired;
while(TRUE) { cchRequired = ExpandEnvironmentStrings( (LPCTSTR)pabData, strResult.GetBuffer(cchBuff), cchBuff );
if (cchRequired == 0) { //
// Never a valid result (even an empty
// string has a terminating null).
//
err.GetLastWinError(); break; }
if (cchRequired > cchBuff) { //
// Buffer too small -- try again
//
cchBuff = cchRequired; continue; }
//
// Successfully expanded environment string.
//
strResult.ReleaseBuffer(); break; }
if (err.Succeeded() && pfExpanded) { *pfExpanded = TRUE; } break; }
//
// Fall through
//
case REG_SZ: strResult = (LPTSTR)pabData; if (pfExpanded) { *pfExpanded = FALSE; } break;
default: err = ERROR_INVALID_PARAMETER; break; } } while(FALSE); } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); }
if (pabData) { FreeMem(pabData); }
return err; }
DWORD CRMCRegKey::QueryValue( IN LPCTSTR lpszValueName, OUT CStringListEx & strList ) /*++
Routine Description:
Read REG_MULTI_SZ as a CStringListEx
Arguments:
LPCTSTR lpszValueName : Name of the value CStringListEx & strList : String list return value
Return Value:
Error return code.
--*/ { CError err;
DWORD dwType; DWORD cbData; BYTE * pabData = NULL; LPTSTR pbTemp, pbTempLimit;
do { err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData); if (err.Failed()) { break; }
ASSERT(dwType == REG_MULTI_SZ); if (dwType != REG_MULTI_SZ) { err = ERROR_INVALID_PARAMETER; break; }
//
// Guarantee that the trailing data looks like a string
//
pabData[cbData] = 0; pbTemp = (LPTSTR)pabData; pbTempLimit = &(pbTemp[cbData]);
try { while (pbTemp < pbTempLimit) { strList.AddTail(pbTemp); pbTemp += ::_tcslen(pbTemp) + 1; } } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } } while (FALSE);
if (pabData) { FreeMem(pabData); }
return err; }
DWORD CRMCRegKey::QueryValue( IN LPCTSTR lpszValueName, OUT DWORD & dwResult ) /*++
Routine Description:
Read a DWORD from the registry value
Arguments:
LPCTSTR lpszValueName : Name of the value DWORD & dwResult : DWORD to be returned
Return Value:
Error return code.
--*/ { CError err;
DWORD dwType; DWORD cbData; BYTE * pabData = NULL;
do { err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData); if (err.Failed()) { break; }
ASSERT(dwType == REG_DWORD && cbData == sizeof(dwResult)); if (dwType != REG_DWORD || cbData != sizeof(dwResult)) { err = ERROR_INVALID_PARAMETER; break; }
dwResult = *((DWORD *)pabData); } while (FALSE);
if (pabData) { FreeMem(pabData); }
return err; }
DWORD CRMCRegKey::QueryValue( IN LPCTSTR lpszValueName, OUT CByteArray & abResult ) /*++
Routine Description:
Read a byte stream from the registry as a CByteArray
Arguments:
LPCTSTR lpszValueName : Name of the value CByteArray & abResult : Byte array result
Return Value:
Error return code.
--*/ { CError err;
DWORD dwType; DWORD cbData; BYTE * pabData = NULL;
do { err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData); if (err.Failed()) { break; }
ASSERT(dwType == REG_BINARY); if (dwType != REG_BINARY) { err = ERROR_INVALID_PARAMETER; break; }
try { abResult.SetSize(cbData); } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); }
if (err.Failed()) { break; }
//
// Move the data to the result array.
//
for (DWORD i = 0; i < cbData; ++i) { abResult[i] = pabData[i]; } } while (FALSE);
if (pabData) { FreeMem(pabData); }
return err; }
DWORD CRMCRegKey::QueryValue( IN LPCTSTR lpszValueName, IN void * pvResult, IN DWORD cbSize ) /*++
Routine Description:
Read a byte stream from the registry into a previously allocated buffer.
Arguments:
LPCTSTR lpszValueName : Name of the value void * pvResult : Generic buffer DWORD cbSize : Size of the buffer
Return Value:
Error return code.
--*/ { CError err;
DWORD dwType; DWORD cbData; BYTE * pabData = NULL;
do { err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData); if (err.Failed()) { break; }
ASSERT(dwType == REG_BINARY && pvResult != NULL); if (dwType != REG_BINARY || pvResult == NULL) { err = ERROR_INVALID_PARAMETER; break; }
if (cbSize < cbData) { err = ERROR_MORE_DATA; break; }
::CopyMemory(pvResult, pabData, cbData); } while (FALSE);
if (pabData) { FreeMem(pabData); }
return err; }
//
// Overloaded value setting members.
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DWORD CRMCRegKey::SetValue( IN LPCTSTR lpszValueName, IN CString & strResult, IN BOOL fAutoDeflate, OPTIONAL IN OUT BOOL * pfDeflated OPTIONAL ) /*++
Routine Description:
Write a CString as REG_SZ or REG_EXPAND_SZ registry value.
Arguments:
LPCTSTR lpszValueName : Name of the value CString & strResult : String to be written BOOL fAutoDeflate : If TRUE write as REG_EXPAND_SZ and try using %SystemRoot% path BOOL * pfDeflated : Optionally return whether item was deflated.
If *TRUE on input, use REG_EXPAND_SZ regardless.
Return Value:
Error return code.
--*/ { TRACEEOLID(strResult); CError err; DWORD dwType = REG_SZ;
if (fAutoDeflate || (pfDeflated && *pfDeflated)) { err = DeflateEnvironmentVariablePath( _T("SystemRoot"), strResult );
if (err.Failed()) { err = DeflateEnvironmentVariablePath( _T("SystemDrive"), strResult ); }
dwType = REG_EXPAND_SZ; }
return ::RegSetValueEx( *this, lpszValueName, 0, // Reserved
dwType, (const LPBYTE)(LPCTSTR)strResult, (strResult.GetLength() + 1) * sizeof(TCHAR) ); }
DWORD CRMCRegKey::SetValue( IN LPCTSTR lpszValueName, IN CStringListEx & strList ) /*++
Routine Description:
Write a CStringListEx as REG_MULTI_SZ registry value.
Arguments:
LPCTSTR lpszValueName : Name of the value CStringListEx & strList : Strings to be written
Return Value:
Error return code.
--*/ { DWORD cbSize; BYTE * pbData = NULL;
CError err(FlattenValue(strList, &cbSize, &pbData));
if (err.Succeeded()) { err = ::RegSetValueEx( *this, lpszValueName, 0, // Reserved
REG_MULTI_SZ, pbData, cbSize ); }
if (pbData != NULL) { FreeMem(pbData); }
return err; }
DWORD CRMCRegKey::SetValue( IN LPCTSTR lpszValueName, IN DWORD & dwResult ) /*++
Routine Description:
Write a DWORD to the registry value
Arguments:
LPCTSTR lpszValueName : Name of the value DWORD & dwResult : DWORD to be written
Return Value:
Error return code.
--*/ { return ::RegSetValueEx( *this, lpszValueName, 0, // Reserved
REG_DWORD, (const LPBYTE)&dwResult, sizeof(dwResult) ); }
DWORD CRMCRegKey::SetValue( IN LPCTSTR lpszValueName, IN CByteArray & abResult ) /*++
Routine Description:
Write a CByteArray of bytes to the registry value
Arguments:
LPCTSTR lpszValueName : Name of the value CByteArray & abResult : Bytes to be written
Return Value:
Error return code.
--*/ { DWORD cbSize; BYTE * pbData = NULL;
CError err(FlattenValue(abResult, &cbSize, &pbData));
if (err.Succeeded()) { err = ::RegSetValueEx( *this, lpszValueName, 0, // Reserved
REG_BINARY, pbData, cbSize ); }
if (pbData != NULL) { FreeMem(pbData); }
return err; }
DWORD CRMCRegKey::SetValue( IN LPCTSTR lpszValueName, IN void * pvResult, IN DWORD cbSize ) /*++
Routine Description:
Write a generic stream of bytes to the registry value
Arguments:
LPCTSTR lpszValueName : Name of the value CByteArray & abResult : Bytes to be written
Return Value:
Error return code.
--*/ { return ::RegSetValueEx( *this, lpszValueName, 0, // Reserved
REG_BINARY, (const LPBYTE)pvResult, cbSize ); }
/* static */ /* protected */ /* INTRINSA suppress=null_pointers, uninitialized */ DWORD CRMCRegKey::FlattenValue( IN CStringListEx & strList, OUT DWORD * pcbSize, OUT BYTE ** ppbData ) /*++
Routine Description:
Spread out the stringlist over a generic buffer. Buffer will be allocated by this function.
Arguments:
CStringListEx & strList : List of strings to be used DWORD * pcbSize : Returns the byte size of the buffer allocated BYTE ** ppbData : Buffer which will be allocated
Return Value:
Error return code.
--*/ { CError err;
POSITION pos; CString * pstr; int cbTotal = 0;
//
// CODEWORK: Try using ConvertStringListToDoubleNullList here
//
//
// Walk the list accumulating sizes
//
for (pos = strList.GetHeadPosition(); pos != NULL && (pstr = & strList.GetNext(pos)); /**/ ) { cbTotal += (pstr->GetLength() + 1) * sizeof(TCHAR); }
//
// Allocate and fill a temporary buffer
//
if (*pcbSize = cbTotal) { try { *ppbData = (LPBYTE)AllocMem(*pcbSize);
BYTE * pbData = *ppbData;
if (pbData == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; }
//
// Populate the buffer with the strings.
//
else for (pos = strList.GetHeadPosition(); pos != NULL && (pstr = & strList.GetNext(pos)); /**/ ) { int cb = (pstr->GetLength() + 1) * sizeof(TCHAR); ::CopyMemory(pbData, (LPCTSTR)*pstr, cb); pbData += cb; } } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } } else { *ppbData = NULL; }
return err; }
/* static */ /* protected */ /* INTRINSA suppress=null_pointers, uninitialized */ DWORD CRMCRegKey::FlattenValue( IN CByteArray & abData, OUT DWORD * pcbSize, OUT BYTE ** ppbData ) /*++
Routine Description:
Spread out the CByteArray over a generic buffer. Buffer will be allocated by this function.
Arguments:
CByteArray * abData : Byte stream DWORD * pcbSize : Returns the byte size of the buffer allocated BYTE ** ppbData : Buffer which will be allocated
Return Value:
Error return code.
--*/ { CError err;
//
// Allocate and fill a temporary buffer
//
if (*pcbSize = (DWORD) abData.GetSize()) { try { *ppbData = (LPBYTE)AllocMem(*pcbSize);
if (*ppbData == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; } else for (DWORD i = 0; i < *pcbSize; i++) { (*ppbData)[i] = abData[i]; }
} catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } } else { *ppbData = NULL; }
return err; }
DWORD CRMCRegKey::QueryKeyInfo( OUT CREGKEY_KEY_INFO * pRegKeyInfo ) /*++
Routine Description:
Find out information about this given key.
Arguments:
CREGKEY_KEY_INFO * pRegKeyInfo : Registry key structure
Return Value:
Error return code.
--*/ { ASSERT(pRegKeyInfo != NULL); if (pRegKeyInfo == NULL) { return ERROR_INVALID_PARAMETER; }
pRegKeyInfo->dwClassNameSize = sizeof(pRegKeyInfo->chBuff) - 1;
return ::RegQueryInfoKey( *this, pRegKeyInfo->chBuff, &pRegKeyInfo->dwClassNameSize, NULL, &pRegKeyInfo->dwNumSubKeys, &pRegKeyInfo->dwMaxSubKey, &pRegKeyInfo->dwMaxClass, &pRegKeyInfo->dwMaxValues, &pRegKeyInfo->dwMaxValueName, &pRegKeyInfo->dwMaxValueData, &pRegKeyInfo->dwSecDesc, &pRegKeyInfo->ftKey ); }
CRMCRegKeyIter::CRMCRegKeyIter( IN CRMCRegKey & regKey ) /*++
Routine Description:
Constructor for the registry keys iteration class.
Arguments:
CRMCRegKey & regKey : Parent registry key to be enumerated.
Return Value:
N/A
--*/ : m_rkIter(regKey), m_pBuffer(NULL), m_cbBuffer(0) { CRMCRegKey::CREGKEY_KEY_INFO regKeyInfo;
Reset();
CError err(regKey.QueryKeyInfo(®KeyInfo));
if (err.Succeeded()) { try { m_cbBuffer = regKeyInfo.dwMaxSubKey + sizeof(DWORD); m_pBuffer = AllocTString(m_cbBuffer); } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } }
err.MessageBoxOnFailure(); }
CRMCRegKeyIter::~CRMCRegKeyIter() /*++
Routine Description:
Destructor for key iteration class
Arguments:
N/A
Return Value:
N/A
--*/ { if (m_pBuffer != NULL) { FreeMem(m_pBuffer); } }
DWORD CRMCRegKeyIter::Next( OUT CString * pstrName, OUT CTime * pTime OPTIONAL ) /*++
Routine Description:
Get the name (and optional last write time) of the next key.
Arguments:
CString * pstrName : Next key name CTime * pTime : Time structure or NULL
Return Value:
ERROR_SUCCESS if the next key was found, ERROR_NO_MORE_ITEMS if no further items are available.
--*/ { if (m_pBuffer == NULL) { return ERROR_NO_MORE_ITEMS; }
FILETIME ftDummy; DWORD dwNameSize = m_cbBuffer;
CError err(::RegEnumKeyEx( m_rkIter, m_dwIndex, m_pBuffer, &dwNameSize, NULL, NULL, NULL, &ftDummy ));
if (err.Succeeded()) { ++m_dwIndex;
if (pTime != NULL) { *pTime = ftDummy; }
try { *pstrName = m_pBuffer; } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } }
return err; }
CRMCRegValueIter::CRMCRegValueIter( IN CRMCRegKey & regKey ) /*++
Routine Description:
Constructor for the Iterate through registry values class.
Arguments:
CRMCRegKey & regKey : Parent registry key to be enumerated.
Return Value:
N/A
--*/ : m_rkIter(regKey), m_pBuffer(NULL), m_cbBuffer(0) { CRMCRegKey::CREGKEY_KEY_INFO regKeyInfo;
Reset();
CError err(regKey.QueryKeyInfo(®KeyInfo));
if (err.Succeeded()) { try { m_cbBuffer = regKeyInfo.dwMaxValueName + sizeof(DWORD); m_pBuffer = AllocTString(m_cbBuffer); } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } }
err.MessageBoxOnFailure(); }
CRMCRegValueIter::~CRMCRegValueIter() /*++
Routine Description:
Destructor for values iteration class
Arguments:
N/A
Return Value:
N/A
--*/ { if (m_pBuffer != NULL) { FreeMem(m_pBuffer); } }
DWORD CRMCRegValueIter::Next( OUT CString * pstrName, OUT DWORD * pdwType ) /*++
Routine Description:
Get the name and type of the next registry value
Arguments:
CString * pstrName : Next value name DWORD * pdwType : Registry value type
Return Value:
ERROR_SUCCESS if the next key was found, ERROR_NO_MORE_ITEMS if no further items are available.
--*/ { if (m_pBuffer == NULL) { return ERROR_NO_MORE_ITEMS; }
DWORD dwNameLength = m_cbBuffer;
CError err(::RegEnumValue( m_rkIter, m_dwIndex, m_pBuffer, &dwNameLength, NULL, pdwType, NULL, NULL ));
if (err.Succeeded()) { ++m_dwIndex;
try { *pstrName = m_pBuffer; } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } }
return err; }
|