// AESEncRegKey.cpp : implementation file
//
#include "stdafx.h"
#include "AESEncRegKey.h"
// Crypto++ Includes
#pragma warning(push, 3)
# include "modes.h"
# include "aes.h"
# include "filters.h"
#pragma warning(pop)
// Crypto++ Library
#ifdef _DEBUG
# pragma comment ( lib, "cryptlibd" )
#else
# pragma comment ( lib, "cryptlib" )
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAESEncRegKey
CAESEncRegKey::CAESEncRegKey() : _hKey( NULL )
{
CString szCompanyName = AfxGetAppName();
CString szSubKey = _T("Software\\") + szCompanyName;
SetSubKey( szSubKey );
}
CAESEncRegKey::CAESEncRegKey(const BYTE* cbKey, UINT nKeyLength, const BYTE* cbIV, UINT nIVLength) : _hKey( NULL )
{
ASSERT( NULL != cbKey );
ASSERT( NULL != cbIV );
SetHKEY( NULL );
SetKey( cbKey, nKeyLength );
SetIV( cbIV, nIVLength );
}
CAESEncRegKey::CAESEncRegKey(HKEY hKey, LPCTSTR pszSubKey, LPCTSTR pszValueName)
{
SetHKEY( hKey );
SetSubKey( pszSubKey );
SetValueName( pszValueName );
}
CAESEncRegKey::~CAESEncRegKey() { }
const BYTE* CAESEncRegKey::GetKey() const
{
return _EncKey._cbKey;
}
const BYTE* CAESEncRegKey::GetIV() const
{
return _EncIV._cbIV;
}
UINT CAESEncRegKey::GetIVLength() const
{
return CryptoPP::AES::BLOCKSIZE;
}
UINT CAESEncRegKey::GetKeyLength() const
{
return CryptoPP::AES::DEFAULT_KEYLENGTH;
}
const CString& CAESEncRegKey::GetSubKey() const
{
return _szSubKey;
}
const CString& CAESEncRegKey::GetValueName() const
{
return _szValueName;
}
BOOL CAESEncRegKey::SetHKEY(HKEY hKey)
{
_hKey = hKey;
return TRUE;
}
BOOL CAESEncRegKey::DeleteKey(const CString& szSubKey)
{
long lResult = RegDeleteKey(_hKey, szSubKey);
return (ERROR_SUCCESS == lResult);
}
BOOL CAESEncRegKey::DeleteValue(const CString& szSubKey, const CString& szValue)
{
HKEY hKey = NULL;
long lResult = RegOpenKeyEx(_hKey, szSubKey, 0, KEY_ALL_ACCESS, &hKey);
if( ERROR_SUCCESS == lResult)
{
lResult = RegDeleteValue(hKey, szValue);
RegCloseKey(hKey);
}
return (ERROR_SUCCESS == lResult);
}
BOOL CAESEncRegKey::SetSubKey(LPCTSTR pszSubKey)
{
BOOL bResult = FALSE;
ASSERT( NULL != pszSubKey );
if( NULL != pszSubKey ) {
CString szTemp = pszSubKey;
// Strip leading slashes. Windows 9x can deal with them,
// but Windows NT/2000 cannot
while( 0 < szTemp.GetLength() && _T('\\') == szTemp.Left( 1 ) ) {
szTemp = szTemp.Right( szTemp.GetLength() - 1 );
}
_szSubKey = szTemp;
bResult = TRUE;
::OutputDebugString( _T("_szSubKey set to ") );
::OutputDebugString( _szSubKey );
::OutputDebugString( _T("\n") );
}
return bResult;
}
BOOL CAESEncRegKey::SetValueName(LPCTSTR pszValueName)
{
BOOL bResult = FALSE;
ASSERT( NULL != pszValueName );
if( NULL != pszValueName ) {
_szValueName = pszValueName;
bResult = TRUE;
::OutputDebugString( _T("_szValueName set to ") );
::OutputDebugString( _szValueName );
::OutputDebugString( _T("\n") );
}
return bResult;
}
BOOL CAESEncRegKey::SetIV(const BYTE *cbIV, UINT nLength)
{
BOOL bResult = FALSE;
ASSERT( CryptoPP::AES::BLOCKSIZE == nLength );
ASSERT( NULL != cbIV );
if( CryptoPP::AES::BLOCKSIZE == nLength && NULL != cbIV ) {
_EncIV = cbIV;
bResult = TRUE;
}
return bResult;
}
BOOL CAESEncRegKey::SetKey(const BYTE *cbKey, UINT nLength)
{
BOOL bResult = FALSE;
ASSERT( CryptoPP::AES::DEFAULT_KEYLENGTH == nLength );
ASSERT( NULL != cbKey );
if( CryptoPP::AES::DEFAULT_KEYLENGTH == nLength && NULL != cbKey ) {
_EncKey = cbKey;
bResult = TRUE;
}
return bResult;
}
LONG CAESEncRegKey::WriteString(LPCTSTR pszData, BOOL bEncrypt /*=FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypt ) {
lResult = WriteEncString( pszData );
} else {
lResult = WriteNonEncString( pszData );
}
return lResult;
}
LONG CAESEncRegKey::WriteDWORD(DWORD dwValue, BOOL bEncrypt /*=FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypt ) {
lResult = WriteEncDWORD( dwValue );
} else {
lResult = WriteNonEncDWORD( dwValue );
}
return lResult;
}
LONG CAESEncRegKey::WriteBinary(const BYTE *pcbData, UINT nSize, BOOL bEncrypt /*= FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypt ) {
lResult = WriteEncBinary( pcbData, nSize );
} else {
lResult = WriteNonEncBinary( pcbData, nSize );
}
return lResult;
}
LONG CAESEncRegKey::WriteNonEncString(LPCTSTR pszData) const
{
LONG lResult = ERROR_SUCCESS;
lResult = WriteData( reinterpret_cast<const BYTE*>( pszData ),
( ::lstrlen( pszData ) + 1 ) * sizeof( TCHAR ),
REG_SZ );
return lResult;
}
LONG CAESEncRegKey::WriteNonEncDWORD(DWORD dwData) const
{
LONG lResult = ERROR_SUCCESS;
lResult = WriteData( reinterpret_cast<const BYTE*>( &dwData ),
sizeof( DWORD ), REG_DWORD );
return lResult;
}
LONG CAESEncRegKey::WriteEncDWORD(DWORD dwData) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from EncryptData()
BYTE* pcbEncryptedData = NULL;
DWORD dwEncryptedSize = 0;
//
// Anti-snoop it...
lResult = EncryptData( reinterpret_cast<const BYTE*>(&dwData), sizeof( DWORD ),
&pcbEncryptedData, &dwEncryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Save it...
lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );
FINISHED:
//
// Cleanup...
if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }
return lResult;
}
LONG CAESEncRegKey::WriteEncString(LPCTSTR pszData) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from EncryptData()
BYTE* pcbEncryptedData = NULL;
DWORD dwEncryptedSize = 0;
//
// Anti-snoop it...
lResult = EncryptData( reinterpret_cast<const BYTE*>(pszData),
( ::lstrlen( pszData ) + 1 ) * sizeof( TCHAR ),
&pcbEncryptedData, &dwEncryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Save it...
lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );
FINISHED:
//
// Cleanup...
if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }
return lResult;
}
LONG CAESEncRegKey::WriteEncBinary(const BYTE *pcbData, UINT nSize) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from EncryptData()
BYTE* pcbEncryptedData = NULL;
DWORD dwEncryptedSize = 0;
//
// Anti-snoop it...
lResult = EncryptData( pcbData, nSize, &pcbEncryptedData, &dwEncryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Persit it...
lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );
FINISHED:
//
// Cleanup...
if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }
return lResult;
}
LONG CAESEncRegKey::WriteNonEncBinary(const BYTE *pcbData, UINT nSize) const
{
LONG lResult = ERROR_SUCCESS;
lResult = WriteData( pcbData, nSize, REG_BINARY );
return lResult;
}
LONG CAESEncRegKey::ReadDWORD(DWORD &dwValue, BOOL bEncrypted) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypted ) {
lResult = ReadEncDWORD( dwValue );
} else {
lResult = ReadNonEncDWORD( dwValue );
}
return lResult;
}
LONG CAESEncRegKey::ReadString(CString &szValue, BOOL bEncrypted /*=FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypted ) {
lResult = ReadEncString( szValue );
} else {
lResult = ReadNonEncString( szValue );
}
return lResult;
}
LONG CAESEncRegKey::ReadString(LPTSTR pszValue, DWORD *dwCharCount, BOOL bEncrypted /*=FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
CString szTemp;
DWORD dwRequiredSize = 0; // In TCHARs, not BYTEs
//
// Emulate the RegQueryValue(...) Function
// See http://msdn.microsoft.com/library/default.asp?
// url=/library/en-us/sysinfo/base/regqueryvalueex.asp
// It appears Caller is asking for dwType
if( NULL == pszValue && NULL == dwCharCount ) {
lResult = ERROR_SUCCESS;
goto FINISHED;
}
if( TRUE == bEncrypted ) {
lResult = ReadEncString( szTemp );
} else {
lResult = ReadNonEncString( szTemp );
}
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// '+ 1' to catch the trailing '\0'
dwRequiredSize = szTemp.GetLength() + 1;
//
// Emulate the RegQueryValue(...) Function
// See http://msdn.microsoft.com/library/default.asp?
// url=/library/en-us/sysinfo/base/regqueryvalueex.asp
// It appears Caller is asking for size of pszValue
if( *dwCharCount < dwRequiredSize && NULL != pszValue ) {
lResult = ERROR_MORE_DATA;
*dwCharCount = dwRequiredSize;
goto FINISHED;
}
//
// Emulate the RegQueryValue(...) Function
// See http://msdn.microsoft.com/library/default.asp?
// url=/library/en-us/sysinfo/base/regqueryvalueex.asp
// Caller is asking for size of pszValue
if( *dwCharCount < dwRequiredSize && NULL != pszValue ) {
lResult = ERROR_SUCCESS;
*dwCharCount = dwRequiredSize;
goto FINISHED;
}
*dwCharCount = dwRequiredSize;
::memcpy( pszValue, static_cast<LPCTSTR>( szTemp ), dwRequiredSize * sizeof( TCHAR ) );
FINISHED:
return lResult;
}
LONG CAESEncRegKey::ReadNonEncString(CString &szValue) const
{
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
DWORD dwSize = 0;
BYTE* pcbData = NULL;
//
// Open the key - do not create
lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Query for needed buffer size
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, &dwSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Add '+ sizeof(TCHAR)' in case the string is not
// stored in the registry with a trailing '\0'
pcbData = new BYTE[ dwSize + sizeof(TCHAR) ];
//
// Sanity Check
if( NULL == pcbData ) {
lResult = ERROR_NOT_ENOUGH_MEMORY;
goto FINISHED;
}
//
// Add the trailing '\0', taking into account UNICODEness
reinterpret_cast<TCHAR*>(pcbData)[ dwSize/sizeof(TCHAR) - 1 ] = _T('\0');
//
// Query for the actual value
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, pcbData, &dwSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Paydirt...
szValue = reinterpret_cast<TCHAR*>(pcbData);
FINISHED:
//
// Cleanup...
if( NULL != hKey ) { RegCloseKey( hKey ); }
if( NULL != pcbData ) { delete[] pcbData; }
return lResult;
}
LONG CAESEncRegKey::ReadEncString(CString &szValue) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from the Registry
DWORD dwSize = 0;
BYTE* pcbData = NULL;
// Returned from DecryptData(...)
DWORD dwDecryptedSize = 0;
BYTE* pcbDecryptedData = NULL;
// Read From the Registry
lResult = ReadData( &pcbData, &dwSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Undo it...
lResult = DecryptData( pcbData, dwSize, &pcbDecryptedData, &dwDecryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Paydirt...
szValue = reinterpret_cast<const TCHAR*>( pcbDecryptedData );
FINISHED:
//
// Cleanup...
if( NULL != pcbData ) { delete[] pcbData; }
if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }
return lResult;
}
////////////////////////////////
//
// EncryptData
//
LONG CAESEncRegKey::EncryptData(const BYTE *pcbPlainText, DWORD dwPlainTextSize, BYTE **pcbEncryptedData, DWORD *pdwEncryptedSize) const
{
LONG lResult = ERROR_SUCCESS;
ASSERT( NULL != pcbPlainText );
ASSERT( NULL != pcbEncryptedData );
ASSERT( NULL != pdwEncryptedSize );
if( NULL == pcbEncryptedData || NULL == pdwEncryptedSize ) {
lResult = ERROR_INVALID_PARAMETER;
}
try {
CryptoPP::AES::Encryption aesEncryption( _EncKey._cbKey, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, _EncIV._cbIV );
std::string cipher;
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( cipher ) );
stfEncryptor.Put( reinterpret_cast<const BYTE*>( pcbPlainText ), dwPlainTextSize );
stfEncryptor.MessageEnd();
if( ERROR_SUCCESS == lResult ) {
*pdwEncryptedSize = (DWORD)cipher.size();
*pcbEncryptedData = new BYTE[ *pdwEncryptedSize ];
::memcpy( *pcbEncryptedData, reinterpret_cast<const BYTE*>( cipher.data() ), *pdwEncryptedSize );
}
} catch( CryptoPP::Exception& e ) {
::OutputDebugString( _T("Caught Crypto++ exception: '") );
::OutputDebugStringA( e.what() );
::OutputDebugString( _T("'\n") );
lResult = ERROR_INVALID_DATA;
} catch( ... ) {
::OutputDebugString( _T("Caught other exception.") );
lResult = ERROR_INVALID_DATA;
}
return lResult;
}
////////////////////////////////
//
// DecryptData
//
LONG CAESEncRegKey::DecryptData(const BYTE *pcbEncryptedData, DWORD dwEncryptedSize, BYTE **pcbDecryptedData, DWORD *pdwDecryptedSize) const
{
LONG lResult = ERROR_SUCCESS;
*pcbDecryptedData = NULL;
*pdwDecryptedSize = 0;
try {
std::string decrypted;
CryptoPP::AES::Decryption aesDecryption( _EncKey._cbKey, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, _EncIV._cbIV );
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decrypted ) );
//
// Push our blob into the decryptor
stfDecryptor.Put( pcbEncryptedData, dwEncryptedSize );
stfDecryptor.MessageEnd();
*pcbDecryptedData = new BYTE[ decrypted.size() ];
if( NULL != *pcbDecryptedData ) {
*pdwDecryptedSize = (DWORD)decrypted.size();
::memcpy( *pcbDecryptedData, decrypted.data(), decrypted.size() );
}
}
catch( CryptoPP::Exception& e ) {
lResult = ERROR_INVALID_DATA;
::OutputDebugString( _T("Caught Crypto++ exception: '") );
::OutputDebugStringA( e.what() );
::OutputDebugString( _T("'\n") );
}
catch( ... ) {
lResult = ERROR_INVALID_DATA;
::OutputDebugString( _T("Caught other exception") );
}
return lResult;
}
LONG CAESEncRegKey::ReadData(BYTE **pcbData, DWORD *pdwSize) const
{
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
ASSERT( NULL != pcbData && NULL != pdwSize );
//
// Sanity Check
if( NULL == pcbData || NULL == pdwSize ) {
lResult = ERROR_INVALID_PARAMETER;
goto FINISHED;
}
//
// Open the Key
lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Query for needed buffer size
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, pdwSize );
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Allocate a buffer
*pcbData = new BYTE[ *pdwSize + sizeof(TCHAR) ];
//
// Sanity Check
if( NULL == *pcbData ) {
lResult = ERROR_NOT_ENOUGH_MEMORY;
goto FINISHED;
}
//
// Query for the actual value
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, *pcbData, pdwSize );
FINISHED:
if( NULL != hKey ) { RegCloseKey( hKey ); }
return lResult;
}
LONG CAESEncRegKey::ReadEncDWORD(DWORD &dwValue) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from the Registry by way of ReadData(...)
DWORD dwSize = 0;
BYTE* pcbData = NULL;
// Returned from DecryptData(...)
DWORD dwDecryptedSize = 0;
BYTE* pcbDecryptedData = NULL;
// Read From the Registry
lResult = ReadData( &pcbData, &dwSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Undo it...
lResult = DecryptData( pcbData, dwSize, &pcbDecryptedData, &dwDecryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Paydirt...
dwValue = *( reinterpret_cast<DWORD*>( pcbDecryptedData ) );
FINISHED:
//
// Cleanup...
if( NULL != pcbData ) { delete[] pcbData; }
if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }
return lResult;
}
LONG CAESEncRegKey::ReadNonEncDWORD(DWORD& dwValue) const
{
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
DWORD dwSize = sizeof( DWORD );
//
// Open the HKey
lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Query for the actual value
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL,
reinterpret_cast<BYTE*>(&dwValue), &dwSize );
FINISHED:
//
// Cleanup...
if( NULL != hKey ) { RegCloseKey( hKey ); }
return lResult;
}
LONG CAESEncRegKey::ReadBinary( BYTE* pcbData, DWORD* dwSize, BOOL bEncrypted /*=FALSE*/) const
{
LONG lResult = ERROR_SUCCESS;
if( TRUE == bEncrypted ) {
lResult = ReadEncBinary( pcbData, dwSize );
} else {
lResult = ReadNonEncBinary( pcbData, dwSize );
}
return lResult;
}
LONG CAESEncRegKey::ReadNonEncBinary(BYTE* pcbData, DWORD* dwSize) const
{
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
//
// Open the HKey
lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Query for the actual value
lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL,
reinterpret_cast<BYTE*>(pcbData), dwSize );
FINISHED:
//
// Cleanup...
if( NULL != hKey ) { RegCloseKey( hKey ); }
return lResult;
}
LONG CAESEncRegKey::ReadEncBinary(BYTE* pcbData, DWORD* dwSize) const
{
LONG lResult = ERROR_SUCCESS;
//
// Returned from ReadData(...)
DWORD dwRegistrySize = 0;
BYTE* pcbRegistryData = NULL;
//
// Returned from DecryptData(...)
DWORD dwDecryptedSize = 0;
BYTE* pcbDecryptedData = NULL;
//
// Read From the Registry
lResult = ReadData( &pcbRegistryData, &dwRegistrySize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Just undo it...
lResult = DecryptData( pcbRegistryData, dwRegistrySize, &pcbDecryptedData, &dwDecryptedSize );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Emulate the RegQueryValueEx(...) Function
// See http://msdn.microsoft.com/library/default.asp?
// url=/library/en-us/sysinfo/base/regqueryvalueex.asp
if( *dwSize < dwDecryptedSize && NULL != pcbData ) {
lResult = ERROR_MORE_DATA;
*dwSize = dwDecryptedSize;
goto FINISHED;
}
//
// Emulate the RegQueryValueEx(...) Function
// See http://msdn.microsoft.com/library/default.asp?
// url=/library/en-us/sysinfo/base/regqueryvalueex.asp
if( *dwSize < dwDecryptedSize && NULL == pcbData ) {
lResult = ERROR_SUCCESS;
*dwSize = dwDecryptedSize;
goto FINISHED;
}
//
// Inform Caller of size of pcbData
*dwSize = dwDecryptedSize;
//
// Copy the Data out
::memcpy( pcbData, pcbDecryptedData, dwDecryptedSize );
lResult = ERROR_SUCCESS;
FINISHED:
if( NULL != pcbRegistryData ) { delete[] pcbRegistryData; }
if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }
return lResult;
}
LONG CAESEncRegKey::WriteData( const BYTE *pcbData, UINT nSize, DWORD dwType /*=REG_BINARY*/) const
{
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
//
// When writing, create the Key if it does not exist
lResult = RegCreateKeyEx( _hKey, _szSubKey, 0, NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE, NULL, &hKey, NULL );
//
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
//
// Paydirt
lResult = RegSetValueEx( hKey, _szValueName, 0, dwType,
reinterpret_cast<const BYTE*>( pcbData ), nSize );
FINISHED:
//
// Cleanup...
if( NULL != hKey ) { RegCloseKey( hKey ); }
return lResult;
}