412 lines
8.9 KiB
C++
412 lines
8.9 KiB
C++
|
//
|
||
|
// MODULE: "RegUtil.cpp"
|
||
|
//
|
||
|
// PURPOSE: class CRegUtil
|
||
|
// Encapsulates access to system registry.
|
||
|
// This is intended as generic access to the registry, independent of any particular
|
||
|
// application.
|
||
|
//
|
||
|
// PROJECT: first developed as part of Belief Network Editing Tools ("Argon")
|
||
|
// Later modified to provide more extensive features as part of version 3.0 of the
|
||
|
// Online Troubleshooter (APGTS)
|
||
|
//
|
||
|
// AUTHOR: Lonnie Gerrald (LDG), Oleg Kalosha, Joe Mabel
|
||
|
//
|
||
|
// ORIGINAL DATE: 3/25/98
|
||
|
//
|
||
|
// NOTES:
|
||
|
// 1. The Create, Open, and Close functions support a model where m_hKey represents a
|
||
|
// "position" in the registry. Successive calls to Create() or Open() migrate deeper
|
||
|
// into the registry hierarchy. Close closes all keys encountered on the way down to
|
||
|
// the current m_hKey.
|
||
|
//
|
||
|
//
|
||
|
// Version Date By Comments
|
||
|
//--------------------------------------------------------------------
|
||
|
// V0.1(Argon) 3/25/98 LDG
|
||
|
// V3.0 8/??/98 OK
|
||
|
// V3.0 9/9/98 JM
|
||
|
//
|
||
|
#include "stdafx.h"
|
||
|
#include "regutil.h"
|
||
|
#include "event.h"
|
||
|
#include "baseexception.h"
|
||
|
#include "CharConv.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CRegUtil
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
CRegUtil::CRegUtil()
|
||
|
: m_hKey(NULL),
|
||
|
m_WinError(ERROR_SUCCESS)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CRegUtil::CRegUtil(HKEY key)
|
||
|
: m_hKey(key),
|
||
|
m_WinError(ERROR_SUCCESS)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CRegUtil::~CRegUtil()
|
||
|
{
|
||
|
Close();
|
||
|
}
|
||
|
|
||
|
|
||
|
// creates the specified key. If the key already exists in the registry, the function opens it.
|
||
|
// returns true on success, false otherwise.
|
||
|
bool CRegUtil::Create(HKEY hKeyParent, const CString& strKeyName, bool* bCreatedNew, REGSAM access /*=KEY_ALL_ACCESS*/)
|
||
|
{
|
||
|
HKEY hRetKey = NULL;
|
||
|
DWORD dwDisposition = 0;
|
||
|
|
||
|
m_WinError = ::RegCreateKeyEx(
|
||
|
hKeyParent,
|
||
|
strKeyName,
|
||
|
0,
|
||
|
NULL,
|
||
|
REG_OPTION_NON_VOLATILE,
|
||
|
access,
|
||
|
NULL,
|
||
|
&hRetKey,
|
||
|
&dwDisposition
|
||
|
);
|
||
|
|
||
|
if(m_WinError == ERROR_SUCCESS)
|
||
|
{
|
||
|
m_hKey = hRetKey;
|
||
|
*bCreatedNew = dwDisposition == REG_CREATED_NEW_KEY ? true : false;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
m_arrKeysToClose.push_back(hRetKey);
|
||
|
}
|
||
|
catch (exception& x)
|
||
|
{
|
||
|
CString str;
|
||
|
// Note STL exception in event log.
|
||
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
||
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
||
|
SrcLoc.GetSrcFileLineStr(),
|
||
|
CCharConversion::ConvertACharToString(x.what(), str),
|
||
|
_T(""),
|
||
|
EV_GTS_STL_EXCEPTION );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Unlike CRegUtil::Create, CRegUtil::Open does not create the specified key if the key does not
|
||
|
// exist in the registry. Thus it can be used to test whether the key exists.
|
||
|
// returns true on success, false otherwise.
|
||
|
bool CRegUtil::Open(HKEY hKeyParent, const CString& strKeyName, REGSAM access /*=KEY_ALL_ACCESS*/)
|
||
|
{
|
||
|
HKEY hRetKey = NULL;
|
||
|
|
||
|
m_WinError = ::RegOpenKeyEx(
|
||
|
hKeyParent,
|
||
|
strKeyName,
|
||
|
0,
|
||
|
access,
|
||
|
&hRetKey
|
||
|
);
|
||
|
|
||
|
if(m_WinError == ERROR_SUCCESS)
|
||
|
{
|
||
|
m_hKey = hRetKey;
|
||
|
try
|
||
|
{
|
||
|
m_arrKeysToClose.push_back(hRetKey);
|
||
|
}
|
||
|
catch (exception& x)
|
||
|
{
|
||
|
CString str;
|
||
|
// Note STL exception in event log.
|
||
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
||
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
||
|
SrcLoc.GetSrcFileLineStr(),
|
||
|
CCharConversion::ConvertACharToString(x.what(), str),
|
||
|
_T(""),
|
||
|
EV_GTS_STL_EXCEPTION );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// creates the specified subkey of m_hKey. If the key already exists in the registry, the function opens it.
|
||
|
// returns true on success, false otherwise.
|
||
|
bool CRegUtil::Create(const CString& strKeyName, bool* bCreatedNew, REGSAM access /*=KEY_ALL_ACCESS*/)
|
||
|
{
|
||
|
return Create(m_hKey, strKeyName, bCreatedNew, access);
|
||
|
}
|
||
|
|
||
|
// opens the specified subkey of m_hKey.
|
||
|
// Unlike CRegUtil::Create, CRegUtil::Open does not create the specified key if the key does not
|
||
|
// exist in the registry. Thus it can be used to test whether the key exists.
|
||
|
// returns true on success, false otherwise.
|
||
|
bool CRegUtil::Open(const CString& strKeyName, REGSAM access /*=KEY_ALL_ACCESS*/)
|
||
|
{
|
||
|
return Open(m_hKey, strKeyName, access);
|
||
|
}
|
||
|
|
||
|
// Close all keys encountered on the way down to the current m_hKey.
|
||
|
void CRegUtil::Close()
|
||
|
{
|
||
|
for (vector<HKEY>::reverse_iterator i = m_arrKeysToClose.rbegin(); i != m_arrKeysToClose.rend(); i++)
|
||
|
::RegCloseKey( *i );
|
||
|
|
||
|
m_arrKeysToClose.clear();
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::DeleteSubKey(const CString& strSubKey)
|
||
|
{
|
||
|
// What does m_hKey point to after a successful deletion? RAB-981116.
|
||
|
m_WinError = ::RegDeleteKey(m_hKey, strSubKey);
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::DeleteValue(const CString& strValue)
|
||
|
{
|
||
|
m_WinError = ::RegDeleteValue(m_hKey, strValue);
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::SetNumericValue(const CString& strValueName, DWORD dwValue)
|
||
|
{
|
||
|
BYTE* pData = (BYTE*)&dwValue;
|
||
|
m_WinError = ::RegSetValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
0,
|
||
|
REG_DWORD,
|
||
|
pData,
|
||
|
sizeof(DWORD)
|
||
|
);
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::SetStringValue(const CString& strValueName, const CString& strValue)
|
||
|
{
|
||
|
BYTE* pData = (BYTE*)(LPCTSTR)strValue;
|
||
|
m_WinError = ::RegSetValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
pData,
|
||
|
strValue.GetLength()+sizeof(TCHAR)
|
||
|
);
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::SetBinaryValue(const CString& strValueName, char* buf, long buf_len)
|
||
|
{
|
||
|
BYTE* pData = (BYTE*)buf;
|
||
|
m_WinError = ::RegSetValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
0,
|
||
|
REG_BINARY,
|
||
|
pData,
|
||
|
buf_len
|
||
|
);
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::GetNumericValue(const CString& strValueName, DWORD& dwValue)
|
||
|
{
|
||
|
DWORD tmp = 0;
|
||
|
BYTE* pData = (BYTE*)&tmp;
|
||
|
DWORD type = 0;
|
||
|
DWORD size = sizeof(DWORD);
|
||
|
|
||
|
m_WinError = ::RegQueryValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
NULL,
|
||
|
&type,
|
||
|
pData,
|
||
|
&size
|
||
|
);
|
||
|
|
||
|
if (type != REG_DWORD)
|
||
|
return false;
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
{
|
||
|
dwValue = tmp;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CRegUtil::GetStringValue(const CString& strValueName, CString& strValue)
|
||
|
{
|
||
|
BYTE* pData = NULL;
|
||
|
DWORD type = 0;
|
||
|
DWORD size = 0;
|
||
|
|
||
|
// determine data size
|
||
|
m_WinError = ::RegQueryValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
NULL,
|
||
|
&type,
|
||
|
NULL,
|
||
|
&size
|
||
|
);
|
||
|
|
||
|
if (m_WinError != ERROR_SUCCESS)
|
||
|
return false;
|
||
|
|
||
|
if (type != REG_SZ && type != REG_EXPAND_SZ)
|
||
|
return false;
|
||
|
|
||
|
bool bRet = false; // should be only one return from here down: we're about to
|
||
|
// alloc pData and must make sure it's correctly cleaned up.
|
||
|
|
||
|
try
|
||
|
{
|
||
|
pData = new BYTE[size];
|
||
|
}
|
||
|
catch (bad_alloc&)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
memset(pData, 0, size);
|
||
|
m_WinError = ::RegQueryValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
NULL,
|
||
|
&type,
|
||
|
pData,
|
||
|
&size
|
||
|
);
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
{
|
||
|
if (type == REG_EXPAND_SZ )
|
||
|
{
|
||
|
BYTE* pDataExpanded = NULL;
|
||
|
DWORD dwExpandedSize;
|
||
|
|
||
|
// first we call ExpandEnvironmentStrings just to get the length
|
||
|
// casting away unsignedness
|
||
|
dwExpandedSize = ::ExpandEnvironmentStrings(
|
||
|
reinterpret_cast<const TCHAR *>(pData),
|
||
|
reinterpret_cast<TCHAR *>(pDataExpanded),
|
||
|
0);
|
||
|
if (dwExpandedSize > 0)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
pDataExpanded = new BYTE[dwExpandedSize];
|
||
|
|
||
|
// then we call ExpandEnvironmentStrings again to get the expanded value
|
||
|
// casting away unsignedness
|
||
|
if (::ExpandEnvironmentStrings(
|
||
|
reinterpret_cast<const TCHAR *>(pData),
|
||
|
reinterpret_cast<TCHAR *>(pDataExpanded),
|
||
|
dwExpandedSize))
|
||
|
{
|
||
|
strValue = (LPTSTR)pDataExpanded;
|
||
|
delete [] pDataExpanded;
|
||
|
bRet = true;
|
||
|
}
|
||
|
}
|
||
|
catch (bad_alloc&)
|
||
|
{
|
||
|
// Note memory failure in event log.
|
||
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
||
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
||
|
SrcLoc.GetSrcFileLineStr(),
|
||
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strValue = (LPTSTR)pData;
|
||
|
bRet = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] pData;
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
// The second parameter should be passed in as the address of a char *.
|
||
|
// Note that if this returns true, *ppBuf will point to a new buffer on the heap.
|
||
|
// The caller of this function is responsible for deleting that.
|
||
|
bool CRegUtil::GetBinaryValue(const CString& strValueName, char** ppBuf, long* pBufLen)
|
||
|
{
|
||
|
BYTE* pData = NULL;
|
||
|
DWORD type = 0;
|
||
|
DWORD size = 0;
|
||
|
|
||
|
// determine data size
|
||
|
m_WinError = ::RegQueryValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
NULL,
|
||
|
&type,
|
||
|
NULL,
|
||
|
&size
|
||
|
);
|
||
|
|
||
|
if (m_WinError != ERROR_SUCCESS || type != REG_BINARY)
|
||
|
return false;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// Increase the buffer size by one over what we need. Small price to
|
||
|
// pay for processing convenience elsewhere.
|
||
|
pData = new BYTE[size+1];
|
||
|
}
|
||
|
catch (bad_alloc&)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
memset(pData, 0, size);
|
||
|
m_WinError = ::RegQueryValueEx(
|
||
|
m_hKey,
|
||
|
strValueName,
|
||
|
NULL,
|
||
|
&type,
|
||
|
pData,
|
||
|
&size
|
||
|
);
|
||
|
|
||
|
if (m_WinError == ERROR_SUCCESS)
|
||
|
{
|
||
|
// Null terminate the binary string for processing convenience elsewhere.
|
||
|
pData[size]= 0;
|
||
|
*ppBuf = (char*)pData;
|
||
|
*pBufLen = size;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
delete [] pData;
|
||
|
return false;
|
||
|
}
|