//#pragma title( "TReg.cpp - NT registry class" ) /* Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved. =============================================================================== Module - TReg.cpp System - Common Author - Tom Bernhardt, Rich Denham Created - 1995-09-01 Description - NT registry class. Updates - =============================================================================== */ #ifdef USE_STDAFX # include "stdafx.h" #else # include #endif #include #include #include #include "Common.hpp" #include "UString.hpp" #include "Err.hpp" #include "TNode.hpp" #include "TReg.hpp" // Short term solution #define MAX_REG_NAMELEN 512 #define MAX_REG_VALUELEN 2048 // Destructor function was formerly inline. // It is here to facilitate handle leak tracing. TRegKey::~TRegKey() { Close(); }; // Close function was formerly inline. // It is here to facilitate handle leak tracing. void TRegKey::Close() { if ( hKey != INVALID_HANDLE_VALUE ) { RegCloseKey( hKey ); hKey = (HKEY) INVALID_HANDLE_VALUE; } }; // open registry on remote computer DWORD TRegKey::Connect( HKEY hPreDefined ,// in -must be HKEY_LOCAL_MACHINE or HKEY_USERS TCHAR const * machineName // in -remote computer name ) { LONG rc; // return code if ( hKey != INVALID_HANDLE_VALUE ) { Close(); } rc = RegConnectRegistry( const_cast(machineName), hPreDefined, &hKey ); if ( rc ) { hKey = (HKEY) INVALID_HANDLE_VALUE; } return (DWORD)rc; } // create new key DWORD TRegKey::Create( TCHAR const * keyname ,// in -name/path of key to create/open HKEY hParent ,// in -handle of parent key DWORD * pDisp ,// out-disposition of create DWORD access // in -security access mask for key ) { DWORD disp; LONG rc; if ( hKey != INVALID_HANDLE_VALUE ) { Close(); } rc = RegCreateKeyEx( hParent, keyname, 0, NULL, REG_OPTION_NON_VOLATILE, access, NULL, &hKey, (pDisp!=NULL) ? pDisp : &disp ); if ( rc ) { hKey = (HKEY) INVALID_HANDLE_VALUE; } return (DWORD)rc; } // create new key (using backup/restore) DWORD TRegKey::CreateBR( TCHAR const * keyname ,// in -name/path of key to create/open HKEY hParent ,// in -handle of parent key DWORD * pDisp ,// out-disposition of create DWORD access // in -security access mask for key ) { DWORD disp; LONG rc; if ( hKey != INVALID_HANDLE_VALUE ) { Close(); } rc = RegCreateKeyEx( hParent, keyname, 0, NULL, REG_OPTION_BACKUP_RESTORE, access, NULL, &hKey, (pDisp!=NULL) ? pDisp : &disp ); if ( rc ) { hKey = (HKEY) INVALID_HANDLE_VALUE; } return (DWORD)rc; } // open existing key DWORD TRegKey::Open( TCHAR const * keyname ,// in -name/path of key to create/open HKEY hParent ,// in -handle of parent key DWORD access // in -security access mask for key ) { LONG rc; if ( hKey != INVALID_HANDLE_VALUE ) { Close(); } rc = RegOpenKeyEx( hParent, keyname, 0, access, &hKey ); if ( rc ) { hKey = (HKEY) INVALID_HANDLE_VALUE; } return (DWORD)rc; } // Gets the subkey value of the specified index number DWORD // ret-os return code TRegKey::SubKeyEnum( DWORD n ,// in -ordinal number of subkey TCHAR * keyname ,// out-key name DWORD keylen // in -max size of key name in TCHARs ) const { LONG rc; DWORD keyLen = keylen; FILETIME lastWrite; rc = RegEnumKeyEx( hKey, n, keyname, &keyLen, 0, NULL, NULL, &lastWrite ); return (DWORD)rc; } // Enumerate value DWORD // ret-0 or error code TRegKey::ValueEnum( DWORD index ,// in -ordinal number of subkey TCHAR * name ,// out-name DWORD namelen ,// in -name size in TCHARs void * value ,// out-value DWORD * valuelen ,// i/o-value size in BYTEs DWORD * type // out-value type code ) const { return (DWORD)RegEnumValue( hKey, index, name, &namelen, NULL, type, (BYTE *) value, valuelen ); } // Get REG_DWORD value DWORD // ret-OS return code TRegKey::ValueGetDWORD( TCHAR const * name ,// in -value name DWORD * value // out-returned DWORD value ) const { LONG osRc; // OS return code DWORD type; // type of value DWORD len = sizeof *value; // value length osRc = RegQueryValueEx( hKey, name, NULL, &type, (BYTE *) value, &len ); if ( !osRc && (type != REG_DWORD) ) { osRc = ERROR_FILE_NOT_FOUND; } return (DWORD)osRc; } // Get REG_SZ value DWORD // ret-OS return code TRegKey::ValueGetStr( TCHAR const * name ,// in -value name TCHAR * value ,// out-value buffer DWORD maxlen // in -sizeof value buffer ) const { LONG osRc; // OS return code DWORD type; // type of value DWORD len; // value length // force maxlen to an integral number of TEXT characters maxlen = maxlen / (sizeof value[0]) * (sizeof value[0]); if ( !maxlen ) { osRc = ERROR_FILE_NOT_FOUND; } else { len = maxlen; osRc = RegQueryValueEx( hKey, name, NULL, &type, (BYTE *) value, &len ); len = len / (sizeof value[0]) * (sizeof value[0]); if ( !osRc && (type != REG_SZ) ) { osRc = ERROR_FILE_NOT_FOUND; } if ( osRc ) { value[0] = TEXT('\0'); } else { // return of a null-terminated string is not guaranteed by API! // force null-terminated string, truncate string if necessary. if ( len >= maxlen ) { len = maxlen - sizeof value[0]; } value[len/(sizeof value[0])] = TEXT('\0'); } } return (DWORD)osRc; } DWORD TRegKey::ValueGet( TCHAR const * name ,// in -name void * value ,// out-value DWORD * lenvalue ,// i/o-length of value DWORD * typevalue // out-type of value ) const { return (DWORD)RegQueryValueEx( hKey, name, 0, typevalue, (UCHAR *) value, lenvalue ); } // Set REG_SZ value DWORD TRegKey::ValueSetStr( TCHAR const * name ,// in -value name TCHAR const * value ,// out-value DWORD type // in -value type ) const { return (DWORD)RegSetValueEx( hKey, name, NULL, type, (LPBYTE) value, (UStrLen(value) + 1) * sizeof value[0] ); } DWORD TRegKey::ValueSet( TCHAR const * name ,// in -name void const * value ,// in -value DWORD lenvalue ,// in -length of value DWORD typevalue // in -type of value ) const { return (DWORD)RegSetValueEx( hKey, name, 0, typevalue, (UCHAR const *) value, lenvalue ); } DWORD // ret-0 or error code TRegKey::ValueDel( TCHAR const * name // in -value name ) const { LONG rc; rc = (DWORD)RegDeleteValue(hKey, name); return rc; } DWORD // ret-OS return code TRegKey::HiveCopy( TRegKey const * source // in -source hive ) { DWORD retval=0; // returned value DWORD index; // key/value index TCHAR name[MAX_REG_NAMELEN]; // key name TCHAR value[MAX_REG_VALUELEN]; // value name DWORD valuelen; // value length DWORD type; // value type TRegKey srcNest; // nested source registry TRegKey trgNest; // nested target registry // process values at this level for ( index = 0; !retval; index++ ) { valuelen = sizeof value; retval = source->ValueEnum( index, name, MAX_REG_NAMELEN, value, &valuelen, &type ); if ( !retval ) { retval = this->ValueSet( name, value, valuelen, type ); } else if ( retval == ERROR_MORE_DATA ) { retval = 0; } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } // process keys at this level; for each key make a recursive call for ( index = 0; !retval; index++ ) { retval = source->SubKeyEnum( index, name, MAX_REG_NAMELEN ); if ( !retval ) { retval = srcNest.Open( name, source ); if ( !retval ) { retval = trgNest.Create( name, this ); if ( !retval ) { retval = trgNest.HiveCopy( &srcNest ); trgNest.Close(); } srcNest.Close(); } } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } return retval; } DWORD // ret-OS return code TRegKey::HiveDel() { DWORD retval = 0; // returned value DWORD index; // value/key index TCHAR name[MAX_REG_NAMELEN]; // name DWORD namelen; // name length BYTE value[MAX_REG_VALUELEN]; // value DWORD valuelen; // value length DWORD type; // value type code TRegKey trgNest; // nested target registry // delete values at this level for ( index = 0; !retval; /* index++ */ ) // note that index remains at zero { namelen = MAX_REG_NAMELEN; valuelen = sizeof value; retval = ValueEnum( index, name, namelen, value, &valuelen, &type ); if ( retval == ERROR_MORE_DATA ) { retval = 0; } if ( !retval ) { retval = ValueDel( name ); } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } // process keys at this level; for each key make a recursive call for ( index = 0; !retval; /* index++ */ ) // note that index remains at zero { retval = SubKeyEnum( index, name, MAX_REG_NAMELEN ); if ( !retval ) { retval = trgNest.Open( name, this ); if ( !retval ) { retval = trgNest.HiveDel(); trgNest.Close(); } retval = SubKeyDel( name ); } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } return retval; } // These four classes are used only by TRegReplicate // Class to represent one registry key class RKey : public TNode { friend class RKeyList; private: TCHAR * name; // key name protected: public: RKey() { name = NULL; }; ~RKey() { if ( name ) delete name; }; BOOL New( TCHAR const * aname ); TCHAR const * GetName() const { return name; }; }; BOOL RKey::New( TCHAR const * aname // in -key name ) { name = new TCHAR[UStrLen(aname)+1]; if ( name ) { UStrCpy( name, aname ); } return !!name; } // Class to represent the set of registry keys at one level class RKeyList : public TNodeListSortable { private: static TNodeCompare( Compare ) { return UStrICmp( ((RKey const *) v1)->name, ((RKey const *) v2)->name ); } protected: public: RKeyList() : TNodeListSortable( Compare ) {} ~RKeyList(); }; // RKeyList object destructor RKeyList::~RKeyList() { DeleteAllListItems( RKey ); } // Class to represent one registry value class RValue : public TNode { friend class RValueList; private: TCHAR * name; // value's name BYTE * value; // value's value DWORD valuelen; // value's value length DWORD type; // value's type protected: public: RValue() { name = NULL; value = NULL; valuelen = type = 0; }; ~RValue() { if ( name ) delete name; if ( value ) delete value; }; BOOL New( TCHAR const * aname, BYTE const * avalue, DWORD valuelen, DWORD type ); TCHAR const * GetName() const { return name; }; BYTE const * GetValue() const { return value; }; DWORD GetValueLen() const { return valuelen; }; DWORD GetType() const { return type; }; }; BOOL RValue::New( TCHAR const * aname ,// in -value's name BYTE const * avalue ,// in -value's value DWORD avaluelen ,// in -value's value length DWORD atype // in -value's type ) { name = new TCHAR[UStrLen(aname)+1]; if ( name ) { UStrCpy( name, aname ); } value = new BYTE[avaluelen]; if ( value ) { memcpy( value, avalue, avaluelen ); } valuelen = avaluelen; type = atype; return name && value; } // Class to represent the set of registry values at one level class RValueList : public TNodeListSortable { private: static TNodeCompare( Compare ) { return UStrICmp( ((RValue const *)v1)->name, ((RValue const *)v2)->name ); } protected: public: RValueList() : TNodeListSortable( Compare ) {} ~RValueList(); }; // RValueList object destructor RValueList::~RValueList() { DeleteAllListItems( RValue ); } // Static subroutine used only by TRegReplicate // collect all values at one registry level into a RValueList DWORD static CollectValues( RValueList * pValueList ,// out-value list to be built TRegKey const * pRegKey // in -registry key ) { DWORD retval=0; // returned value DWORD index; // value enum index TCHAR name[MAX_REG_NAMELEN]; // value name BYTE value[MAX_REG_VALUELEN]; // value value DWORD valuelen; // value length DWORD type; // value type RValue * pValue; // new value for ( index = 0; !retval; index++ ) { valuelen = sizeof value; retval = pRegKey->ValueEnum( index, name, MAX_REG_NAMELEN, value, &valuelen, &type ); if ( !retval ) { pValue = new RValue; if ( pValue ) { if ( pValue->New( name, value, valuelen, type ) ) { pValueList->Insert( pValue ); } else { delete pValue; pValue = NULL; } } if ( !pValue ) { retval = ERROR_NOT_ENOUGH_MEMORY; } } else if ( retval == ERROR_MORE_DATA ) { retval = 0; } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } return retval; } // Static subroutine used only by TRegReplicate // collect all keys at one registry level into a RKeyList DWORD static CollectKeys( RKeyList * pKeyList ,// out-key list to be built TRegKey const * pRegKey // in -registry key ) { DWORD retval=0; // returned value DWORD index; // key enum index TCHAR name[MAX_REG_NAMELEN]; // key name RKey * pKey; // new key object for ( index = 0; !retval; index++ ) { retval = pRegKey->SubKeyEnum( index, name, MAX_REG_NAMELEN ); if ( !retval ) { pKey = new RKey; if ( pKey ) { if ( pKey->New( name ) ) { pKeyList->Insert( pKey ); } else { delete pKey; pKey = NULL; } } if ( !pKey ) { retval = ERROR_NOT_ENOUGH_MEMORY; } } } if ( retval == ERROR_NO_MORE_ITEMS ) { retval = 0; } return retval; } // Replicate registry hive DWORD // ret-OS return code TRegKey::HiveReplicate( TRegKey const * source // in -source hive ) { DWORD retval=0; // returned value RValueList srcValues; // source values RValueList trgValues; // target values TNodeListEnum eSrcValue; // enumerate source values RValue const * pSrcValue; // source value TNodeListEnum eTrgValue; // enumerate target values RValue const * pTrgValue; // target value RKeyList srcKeys; // source keys RKeyList trgKeys; // target keys TNodeListEnum eSrcKey; // enumerate source keys RKey const * pSrcKey; // source key TNodeListEnum eTrgKey; // enumerate target keys RKey const * pTrgKey; // target key int cmpRc; // compare return code TRegKey srcNest; // nested source registry TRegKey trgNest; // nested target registry // handle replication of values at this level CollectValues( &srcValues, source ); CollectValues( &trgValues, this ); // now merge the values pSrcValue = (RValue const *) eSrcValue.OpenFirst( &srcValues ); pTrgValue = (RValue const *) eTrgValue.OpenFirst( &trgValues ); while ( !retval && (pSrcValue || pTrgValue) ) { if ( !pTrgValue ) { cmpRc = -1; } else if ( !pSrcValue ) { cmpRc = 1; } else { cmpRc = UStrICmp( pSrcValue->GetName(), pTrgValue->GetName() ); } if ( cmpRc < 0 ) { // source value only (copy) retval = this->ValueSet( pSrcValue->GetName(), pSrcValue->GetValue(), pSrcValue->GetValueLen(), pSrcValue->GetType() ); pSrcValue = (RValue const *) eSrcValue.Next(); } else if ( cmpRc > 0 ) { // target value only (delete) retval = this->ValueDel( pTrgValue->GetName() ); pTrgValue = (RValue const *) eTrgValue.Next(); } else /* if ( cmpRc == 0 ) */ { // identical value names (replicate) retval = this->ValueSet( pSrcValue->GetName(), pSrcValue->GetValue(), pSrcValue->GetValueLen(), pSrcValue->GetType() ); pSrcValue = (RValue const *) eSrcValue.Next(); pTrgValue = (RValue const *) eTrgValue.Next(); } } eSrcValue.Close(); eTrgValue.Close(); // handle replication of keys at this level CollectKeys( &srcKeys, source ); CollectKeys( &trgKeys, this ); // now merge the values pSrcKey = (RKey const *) eSrcKey.OpenFirst( &srcKeys ); pTrgKey = (RKey const *) eTrgKey.OpenFirst( &trgKeys ); while ( !retval && (pSrcKey || pTrgKey) ) { if ( !pTrgKey ) { cmpRc = -1; } else if ( !pSrcKey ) { cmpRc = 1; } else { cmpRc = UStrICmp( pSrcKey->GetName(), pTrgKey->GetName() ); } if ( cmpRc < 0 ) { // source key only (copy hive) retval = srcNest.Open( pSrcKey->GetName(), source ); if ( !retval ) { retval = trgNest.Create( pSrcKey->GetName(), this ); if ( !retval ) { retval = trgNest.HiveCopy( &srcNest ); trgNest.Close(); } srcNest.Close(); } pSrcKey = (RKey const *) eSrcKey.Next(); } else if ( cmpRc > 0 ) { // target key only (delete hive) retval = trgNest.Open( pTrgKey->GetName(), this ); if ( !retval ) { retval = trgNest.HiveDel(); trgNest.Close(); } retval = SubKeyDel( pTrgKey->GetName() ); pTrgKey = (RKey const *) eTrgKey.Next(); } else /* if ( cmpRc == 0 ) */ { // identical keys (replicate hive) retval = srcNest.Open( pSrcKey->GetName(), source ); if ( !retval ) { retval = trgNest.Open( pSrcKey->GetName(), this ); if ( !retval ) { retval = trgNest.HiveReplicate( &srcNest ); trgNest.Close(); } srcNest.Close(); } pSrcKey = (RKey const *) eSrcKey.Next(); pTrgKey = (RKey const *) eTrgKey.Next(); } } eSrcKey.Close(); eTrgKey.Close(); return retval; } // TReg.cpp - end of file