1551 lines
27 KiB
C++
1551 lines
27 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|