|
|
//-----------------------------------------------------------------------//
//
// File: compare.cpp
// Created: April 1999
// By: Zeyong Xu
// Purpose: Compare two registry key
//
//------------------------------------------------------------------------//
#include "stdafx.h"
#include "reg.h"
//
// defines / constants / enumerations
//
enum { OUTPUTTYPE_NONE = 1, OUTPUTTYPE_SAME = 2, OUTPUTTYPE_DIFF = 3, OUTPUTTYPE_ALL = 4 };
enum { PRINTTYPE_LEFT = 1, PRINTTYPE_RIGHT = 2, PRINTTYPE_SAME = 3, };
//
// function prototypes
//
BOOL CompareByteData( BYTE* pLeftData, BYTE* pRightData, DWORD dwSize ); BOOL CopyKeyNameFromLeftToRight( PTREG_PARAMS pParams, PTREG_PARAMS pRightParams ); LONG CompareEnumerateValueName( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, DWORD dwOutputType, BOOL* pbHasDifference ); LONG CompareValues( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, LPCWSTR pwszValueName, DWORD dwOutputType, BOOL* pbHasDifference ); LONG CompareEnumerateKey( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, DWORD dwOutputType, BOOL bRecurseSubKeys, BOOL* pbHasDifference, DWORD dwDepth ); BOOL ParseCompareCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, PTREG_PARAMS pRightParams, BOOL* pbUsage ); BOOL PrintValue( LPCWSTR pwszFullKeyName, LPCWSTR pwszValueName, DWORD dwType, BYTE* pData, DWORD dwSize, DWORD dwPrintType ); BOOL PrintKey( LPCWSTR pwszFullKeyName, LPCWSTR pwszSubKeyName, DWORD dwPrintType ); LONG OutputValue( HKEY hKey, LPCWSTR szFullKeyName, LPCWSTR szValueName, DWORD dwPrintType );
//
// implementation
//
//-----------------------------------------------------------------------//
//
// CompareRegistry()
//
//-----------------------------------------------------------------------//
LONG CompareRegistry( DWORD argc, LPCWSTR argv[] ) { // local variables
LONG lResult = 0; HKEY hLeftKey = NULL; HKEY hRightKey = NULL; BOOL bResult = FALSE; BOOL bUsage = FALSE; TREG_PARAMS params; TREG_PARAMS paramsRight; BOOL bHasDifference = FALSE;
if ( argc == 0 || argv == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); ShowLastError( stderr ); return 1; }
// initialize the global data structure
InitGlobalData( REG_COMPARE, ¶ms ); InitGlobalData( REG_COMPARE, ¶msRight );
//
// Parse the cmd-line
//
bResult = ParseCompareCmdLine( argc, argv, ¶ms, ¶msRight, &bUsage ); if( bResult == FALSE ) { ShowLastErrorEx( stderr, SLE_INTERNAL ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
// check whether we need to display the usage
if ( bUsage == TRUE ) { Usage( REG_COMPARE ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 0; }
//
// Connect to the Remote Machine(s) - if applicable
//
bResult = RegConnectMachine( ¶ms ); if( bResult == FALSE ) { SaveErrorMessage( -1 ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
bResult = RegConnectMachine( ¶msRight ); if( bResult == FALSE ) { SaveErrorMessage( -1 ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
// if try to compare the same keys
if ( params.hRootKey == paramsRight.hRootKey && StringCompare( params.pwszFullKey, paramsRight.pwszFullKey, TRUE, 0 ) == 0 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason( ERROR_COMPARESELF_COMPARE ); ShowLastErrorEx( stderr, SLE_INTERNAL ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
//
// Now implement the body of the Compare Operation
//
lResult = RegOpenKeyEx( params.hRootKey, params.pwszSubKey, 0, KEY_READ, &hLeftKey ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
lResult = RegOpenKeyEx( paramsRight.hRootKey, paramsRight.pwszSubKey, 0, KEY_READ, &hRightKey ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); SafeCloseKey( &hLeftKey ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight ); return 1; }
//
// compare a single value if pAppVars->szValueName is not NULL
//
if( params.pwszValueName != NULL ) { lResult = CompareValues( hLeftKey, params.pwszFullKey, hRightKey, paramsRight.pwszFullKey, params.pwszValueName, params.dwOutputType, &bHasDifference ); } else { //
// Recursively compare if pAppVars->bRecurseSubKeys is true
//
lResult = CompareEnumerateKey( hLeftKey, params.pwszFullKey, hRightKey, paramsRight.pwszFullKey, params.dwOutputType, params.bRecurseSubKeys, &bHasDifference, 0 ); }
if( lResult == ERROR_SUCCESS ) { if( bHasDifference == TRUE ) { lResult = 2; ShowMessage( stdout, KEYS_DIFFERENT_COMPARE ); } else { lResult = 0; ShowMessage( stdout, KEYS_IDENTICAL_COMPARE ); }
// ...
SaveErrorMessage( ERROR_SUCCESS ); ShowLastErrorEx( stdout, SLE_INTERNAL );
} else { lResult = 1; ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); }
//
// lets clean up
//
SafeCloseKey( &hLeftKey ); SafeCloseKey( &hRightKey ); FreeGlobalData( ¶ms ); FreeGlobalData( ¶msRight );
// return
return lResult; }
BOOL ParseCompareCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, PTREG_PARAMS pRightParams, BOOL* pbUsage ) { // local variables
DWORD dw = 0; DWORD dwLength = 0; BOOL bResult = FALSE;
// check the input
if ( argc == 0 || argv == NULL || pParams == NULL || pRightParams == NULL || pbUsage == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
// check whether this function is being called for
// valid operation or not
if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
//
// Do we have a *valid* number of cmd-line params
//
if ( argc == 3 && InString( argv[ 2 ], L"/?|-?|/h|-h", TRUE ) == TRUE ) { *pbUsage = TRUE; return TRUE; } else if( argc < 4 || argc > 8 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; } else if ( StringCompareEx( argv[ 1 ], L"COMPARE", TRUE, 0 ) != 0 ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
//
// Left Machine Name and Registry key
//
bResult = BreakDownKeyString( argv[ 2 ], pParams ); if( bResult == FALSE ) { return FALSE; }
//
// Right Machine Name and Registry key
//
bResult = BreakDownKeyString( argv[ 3 ], pRightParams ); if( bResult == FALSE ) { if ( GetLastError() == (DWORD) REGDB_E_KEYMISSING ) { // if no keyname for right side is specified,
// they are comparing the same key name
bResult = CopyKeyNameFromLeftToRight( pParams, pRightParams ); } else if ( pRightParams->pwszMachineName != NULL && StringCompareEx( pRightParams->pwszMachineName, L"\\\\.", TRUE, 0 ) == 0 ) { // reinitialize the global data (right only)
FreeGlobalData( pRightParams ); InitGlobalData( REG_COMPARE, pRightParams );
// parse the info using the left data (just the full key)
bResult = BreakDownKeyString( pParams->pwszFullKey, pRightParams ); } }
// ...
if( bResult == FALSE ) { return FALSE; }
// parsing
for( dw = 4; dw < argc; dw++ ) { if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
dw++; if( dw < argc ) { dwLength = StringLength( argv[ dw ], 0 ) + 1; pParams->pwszValueName = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return FALSE; }
StringCopy( pParams->pwszValueName, argv[ dw ], dwLength ); } else { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; } } else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->pwszValueName = (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; } } else if( StringCompareEx( argv[ dw ], L"/oa", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->dwOutputType = OUTPUTTYPE_ALL; } else if( StringCompareEx( argv[ dw ], L"/od", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->dwOutputType = OUTPUTTYPE_DIFF; } else if( StringCompareEx( argv[ dw ], L"/os", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->dwOutputType = OUTPUTTYPE_SAME; } else if( StringCompareEx( argv[ dw ], L"/on", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->dwOutputType = OUTPUTTYPE_NONE; } else if( StringCompareEx( argv[ dw ], L"/s", TRUE, 0 ) == 0 ) { if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
pParams->bRecurseSubKeys = TRUE; } else { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] ); return FALSE; } }
// default output is "DIFF"
if ( pParams->dwOutputType == 0 ) { pParams->dwOutputType = OUTPUTTYPE_DIFF; }
return TRUE; }
BOOL CopyKeyNameFromLeftToRight( PTREG_PARAMS pParams, PTREG_PARAMS pRightParams ) { // local variables
DWORD dwLength = 0;
// check the input
if ( pParams == NULL || pRightParams == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
// check if rootkey is remotable for right side
if( pRightParams->bUseRemoteMachine == TRUE && pParams->hRootKey != HKEY_USERS && pParams->hRootKey != HKEY_LOCAL_MACHINE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_NONREMOTABLEROOT, g_wszOptions[ REG_COMPARE ] ); return FALSE; }
//
// hive
pRightParams->hRootKey = pParams->hRootKey;
//
// full key
dwLength = StringLength( pParams->pwszFullKey, 0 ) + 1; pRightParams->pwszFullKey = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) ); if( pRightParams->pwszFullKey == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return FALSE; }
// ...
StringCopy( pRightParams->pwszFullKey, pParams->pwszFullKey, dwLength );
//
// sub key
dwLength = StringLength( pParams->pwszSubKey, 0 ) + 1; pRightParams->pwszSubKey = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) ); if( pRightParams->pwszSubKey == NULL) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return FALSE; }
// ...
StringCopy( pRightParams->pwszSubKey, pParams->pwszSubKey, dwLength );
// return
return TRUE; }
//-----------------------------------------------------------------------//
//
// EnumerateKey() - Recursive
//
//-----------------------------------------------------------------------//
LONG CompareEnumerateKey( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, DWORD dwOutputType, BOOL bRecurseSubKeys, BOOL* pbHasDifference, DWORD dwDepth ) { // local variables
DWORD dw = 0; DWORD dwSize = 0; LONG lIndex = 0; LONG lResult = 0; DWORD dwLeftKeys = 0; DWORD dwRightKeys = 0; TARRAY arrLeftKeys = NULL; TARRAY arrRightKeys = NULL; HKEY hLeftSubKey = NULL; HKEY hRightSubKey = NULL; DWORD dwLengthOfLeftKey = 0; DWORD dwLengthOfRightKey = 0; LPWSTR pwszBuffer = NULL; LPCWSTR pwszKey = NULL; LPWSTR pwszNewLeftFullKeyName = NULL; LPWSTR pwszNewRightFullKeyName = NULL;
// check the input
if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL || hRightKey == NULL || pwszRightFullKeyName == NULL || pbHasDifference == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; }
// enumerate all values under current key
lResult = CompareEnumerateValueName( hLeftKey, pwszLeftFullKeyName, hRightKey, pwszRightFullKeyName, dwOutputType, pbHasDifference ); if( bRecurseSubKeys == FALSE || lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
// optimizing the logic
// if user is not interested in seeing the differences,
// we will check whether the comparision done till now is same or not
// if not, there is no point in proceeding -- this is because, the final output
// of the tool is not going to be by continuing furthur
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( *pbHasDifference == TRUE ) { return ERROR_SUCCESS; } }
// query left key info
lResult = RegQueryInfoKey( hLeftKey, NULL, NULL, NULL, &dwLeftKeys, &dwLengthOfLeftKey, NULL, NULL, NULL, NULL, NULL, NULL ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
//
// SPECIAL CASE:
// -------------
// For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
// though there are subkeys underneath this -- to handle this, we are doing a workaround
// by assuming the max registry key length
//
if ( dwLeftKeys != 0 && dwLengthOfLeftKey == 0 ) { dwLengthOfLeftKey = 256; } else if ( dwLengthOfLeftKey < 256 ) { // always assume 100% more length that what is returned by the API
dwLengthOfLeftKey *= 2; }
// query right key info
lResult = RegQueryInfoKey( hRightKey, NULL, NULL, NULL, &dwRightKeys, &dwLengthOfRightKey, NULL, NULL, NULL, NULL, NULL, NULL ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
//
// SPECIAL CASE:
// -------------
// For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
// though there are subkeys underneath this -- to handle this, we are doing a workaround
// by assuming the max registry key length
//
if ( dwRightKeys != 0 && dwLengthOfRightKey == 0 ) { dwLengthOfRightKey = 256; } else if ( dwLengthOfRightKey < 256 ) { // always assume 100% more length that what is returned by the API
dwLengthOfRightKey *= 2; }
// furthur more optimizing the logic
// if user is not interested in seeing the differences,
// we will check the count and length information -- if they dont match, simply return
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( dwLeftKeys != dwRightKeys || dwLengthOfLeftKey != dwLengthOfRightKey ) { *pbHasDifference = TRUE; return ERROR_SUCCESS; } }
// make the length values point to the max. of both
dwLengthOfRightKey++; dwLengthOfLeftKey++; if ( dwLengthOfRightKey > dwLengthOfLeftKey ) { dwLengthOfLeftKey = dwLengthOfRightKey; } else { dwLengthOfRightKey = dwLengthOfLeftKey; }
//
// allocate memory
//
// left keys array
arrLeftKeys = CreateDynamicArray(); if ( arrLeftKeys == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
// right keys array
arrRightKeys = CreateDynamicArray(); if ( arrRightKeys == NULL ) { DestroyDynamicArray( &arrLeftKeys ); SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
// string buffer
pwszBuffer = (LPWSTR) AllocateMemory( dwLengthOfLeftKey * sizeof( WCHAR ) ); if ( pwszBuffer == NULL ) { DestroyDynamicArray( &arrRightKeys ); DestroyDynamicArray( &arrLeftKeys ); SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
//
// enumerate all of the subkeys in left key
//
lResult = ERROR_SUCCESS; for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; dw++ ) { dwSize = dwLengthOfLeftKey; SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) ); lResult = RegEnumKeyEx( hLeftKey, dw, pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
// add the current value to the list of values in the array
if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrLeftKeys, pwszBuffer, 0 ) == -1 ) { lResult = ERROR_OUTOFMEMORY; } } }
//
// enumerate all of the subkeys in right key
//
for( dw = 0; dw < dwRightKeys && lResult == ERROR_SUCCESS; dw++ ) { dwSize = dwLengthOfRightKey; SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) ); lResult = RegEnumKeyEx( hRightKey, dw, pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
// add the current value to the list of values in the array
if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrRightKeys, pwszBuffer, 0 ) == -1 ) { lResult = ERROR_OUTOFMEMORY; } } }
// we no longer require this memory -- release it
FreeMemory( &pwszBuffer );
// allocatte new buffers for storing the new left and right full key names
if ( lResult == ERROR_SUCCESS ) { // determine the lengths
dwLengthOfLeftKey += StringLength( pwszLeftFullKeyName, 0 ) + 5; dwLengthOfRightKey += StringLength( pwszRightFullKeyName, 0 ) +5;
// now allocate buffers
pwszNewLeftFullKeyName = (LPWSTR) AllocateMemory( dwLengthOfLeftKey * sizeof( WCHAR ) ); if ( pwszNewLeftFullKeyName == NULL ) { lResult = ERROR_OUTOFMEMORY; } else { pwszNewRightFullKeyName = (LPWSTR) AllocateMemory( dwLengthOfRightKey * sizeof( WCHAR ) ); if ( pwszNewRightFullKeyName == NULL ) { lResult = ERROR_OUTOFMEMORY; } } }
// compare two subkey name array to find the same subkey
for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; ) { // get the current value from the left array
pwszKey = DynArrayItemAsString( arrLeftKeys, dw );
// search for this value in the right values array
lIndex = DynArrayFindString( arrRightKeys, pwszKey, TRUE, 0 ); if ( lIndex != -1 ) { // print the key information
if ( dwOutputType == OUTPUTTYPE_ALL || dwOutputType == OUTPUTTYPE_SAME ) { PrintKey( pwszLeftFullKeyName, pwszKey, PRINTTYPE_SAME ); }
// prepare the new left subkey
StringCopy( pwszNewLeftFullKeyName, pwszLeftFullKeyName, dwLengthOfLeftKey ); StringConcat( pwszNewLeftFullKeyName, L"\\", dwLengthOfLeftKey ); StringConcat( pwszNewLeftFullKeyName, pwszKey,dwLengthOfLeftKey );
// prepare the new right subkey
StringCopy( pwszNewRightFullKeyName, pwszRightFullKeyName, dwLengthOfRightKey ); StringConcat( pwszNewRightFullKeyName, L"\\", dwLengthOfRightKey ); StringConcat( pwszNewRightFullKeyName, pwszKey, dwLengthOfRightKey );
//
// open new left key
lResult = RegOpenKeyEx( hLeftKey, pwszKey, 0, KEY_READ, &hLeftSubKey ); if( lResult != ERROR_SUCCESS ) { break; }
//
// open the new right key
lResult = RegOpenKeyEx( hRightKey, pwszKey, 0, KEY_READ, &hRightSubKey ); if( lResult != ERROR_SUCCESS ) { break; }
// recursive to compare subkeys
lResult = CompareEnumerateKey( hLeftSubKey, pwszNewLeftFullKeyName, hRightSubKey, pwszNewRightFullKeyName, dwOutputType, bRecurseSubKeys, pbHasDifference, dwDepth + 1 );
// release the keys
SafeCloseKey( &hLeftSubKey ); SafeCloseKey( &hRightSubKey );
if ( lResult == ERROR_SUCCESS ) { // comparision is done -- remove the current keys from
// left and right values array
DynArrayRemove( arrLeftKeys, dw ); DynArrayRemove( arrRightKeys, lIndex );
// update the count variables accordingly
dwLeftKeys--; dwRightKeys--; }
// check if the differences were found or not
if( *pbHasDifference == TRUE ) { if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { dw = 0; dwLeftKeys = 0; dwRightKeys = 0; break; } } }
// update the iteration variable
if ( lIndex == -1 ) { dw++; } }
// Output subkey name in left key
for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; dw++ ) { // get the current value from the left array
pwszKey = DynArrayItemAsString( arrLeftKeys, dw ); if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL ) { PrintKey( pwszLeftFullKeyName, pwszKey, PRINTTYPE_LEFT ); }
// ...
*pbHasDifference = TRUE; }
// Output subkey name in right key
for( dw = 0; dw < dwRightKeys && lResult == ERROR_SUCCESS; dw++ ) { // get the current value from the left array
pwszKey = DynArrayItemAsString( arrRightKeys, dw ); if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL ) { PrintKey( pwszRightFullKeyName, pwszKey, PRINTTYPE_RIGHT ); }
// ...
*pbHasDifference = TRUE; }
// release the memory allocated
FreeMemory( &pwszBuffer ); SafeCloseKey( &hLeftSubKey ); SafeCloseKey( &hRightSubKey ); FreeMemory( &pwszNewLeftFullKeyName ); FreeMemory( &pwszNewRightFullKeyName ); DestroyDynamicArray( &arrLeftKeys ); DestroyDynamicArray( &arrRightKeys );
// return
SaveErrorMessage( lResult ); return lResult; }
LONG CompareEnumerateValueName( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, DWORD dwOutputType, BOOL* pbHasDifference ) { // local variables
DWORD dw = 0; LONG lIndex = 0; LONG lResult = 0; DWORD dwSize = 0; DWORD dwLeftValues = 0; DWORD dwRightValues = 0; DWORD dwLengthOfLeftValue = 0; DWORD dwLengthOfRightValue = 0; TARRAY arrLeftValues = NULL; TARRAY arrRightValues = NULL; LPWSTR pwszBuffer = NULL; LPCWSTR pwszValue = NULL;
// check the input
if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL || hRightKey == NULL || pwszRightFullKeyName == NULL || pbHasDifference == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; }
// optimizing the logic
// if user is not interested in seeing the differences,
// we will check whether the comparision done till now is same or not
// if not, there is no point in proceeding -- this is because, the final output
// of the tool is not going to be by continuing furthur
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( *pbHasDifference == TRUE ) { return ERROR_SUCCESS; } }
// query left key info
lResult = RegQueryInfoKey( hLeftKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwLeftValues, &dwLengthOfLeftValue, NULL, NULL, NULL); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
// query right key info
lResult = RegQueryInfoKey( hRightKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwRightValues, &dwLengthOfRightValue, NULL, NULL, NULL); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
// furthur more optimizing the logic
// if user is not interested in seeing the differences,
// we will check the count and length information -- if they dont match, simply return
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( dwLeftValues != dwRightValues || dwLengthOfLeftValue != dwLengthOfRightValue ) { *pbHasDifference = TRUE; return ERROR_SUCCESS; } }
// make the length values point to the max. of both
dwLengthOfRightValue++; dwLengthOfLeftValue++; if ( dwLengthOfRightValue > dwLengthOfLeftValue ) { dwLengthOfLeftValue = dwLengthOfRightValue; } else { dwLengthOfRightValue = dwLengthOfLeftValue; }
//
// allocate bufferes
//
// left values array
arrLeftValues = CreateDynamicArray(); if ( arrLeftValues == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
// right values array
arrRightValues = CreateDynamicArray(); if ( arrRightValues == NULL ) { DestroyDynamicArray( &arrLeftValues ); SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
// string buffer
pwszBuffer = (LPWSTR) AllocateMemory( dwLengthOfLeftValue * sizeof( WCHAR ) ); if ( pwszBuffer == NULL ) { DestroyDynamicArray( &arrRightValues ); DestroyDynamicArray( &arrLeftValues ); SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
//
// enumerate all of the values in left key
//
lResult = ERROR_SUCCESS; for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; dw++ ) { dwSize = dwLengthOfLeftValue; SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) ); lResult = RegEnumValue( hLeftKey, dw, pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
// add the current value to the list of values in the array
if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrLeftValues, pwszBuffer, 0 ) == -1 ) { lResult = ERROR_OUTOFMEMORY; } } }
//
// enumerate all of the values in right key
//
for( dw = 0; dw < dwRightValues && lResult == ERROR_SUCCESS; dw++ ) { dwSize = dwLengthOfRightValue; SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) ); lResult = RegEnumValue( hRightKey, dw, pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
// add the current value to the list of values in the array
if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrRightValues, pwszBuffer, 0 ) == -1 ) { lResult = ERROR_OUTOFMEMORY; } } }
// we no longer require this memory -- release it
FreeMemory( &pwszBuffer );
// compare two valuename array to find the same valuename
for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; ) { // get the current value from the left array
pwszValue = DynArrayItemAsString( arrLeftValues, dw );
// search for this value in the right values array
lIndex = DynArrayFindString( arrRightValues, pwszValue, TRUE, 0 ); if ( lIndex != -1 ) { lResult = CompareValues( hLeftKey, pwszLeftFullKeyName, hRightKey, pwszRightFullKeyName, pwszValue, dwOutputType, pbHasDifference );
if ( lResult == ERROR_SUCCESS ) { // comparision is done -- remove the current keys from
// left and right values array
DynArrayRemove( arrLeftValues, dw ); DynArrayRemove( arrRightValues, lIndex );
// update the count variables accordingly
dwLeftValues--; dwRightValues--; } }
// update the iteration variable
if ( lIndex == -1 ) { dw++; } }
// Output different valuename in left key
for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; dw++ ) { // get the current value from the left array
pwszValue = DynArrayItemAsString( arrLeftValues, dw ); if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL ) { lResult = OutputValue( hLeftKey, pwszLeftFullKeyName, pwszValue, PRINTTYPE_LEFT ); }
// ...
*pbHasDifference = TRUE; }
// Output different valuename in left key
for( dw = 0; dw < dwRightValues && lResult == ERROR_SUCCESS; dw++ ) { // get the current value from the left array
pwszValue = DynArrayItemAsString( arrRightValues, dw ); if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL ) { lResult = OutputValue( hRightKey, pwszRightFullKeyName, pwszValue, PRINTTYPE_RIGHT ); }
// ...
*pbHasDifference = TRUE; }
// release the memory allocated
DestroyDynamicArray( &arrLeftValues ); DestroyDynamicArray( &arrRightValues );
// return
SaveErrorMessage( lResult ); return lResult; }
//-----------------------------------------------------------------------//
//
// CompareValues()
//
//-----------------------------------------------------------------------//
LONG CompareValues( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName, HKEY hRightKey, LPCWSTR pwszRightFullKeyName, LPCWSTR pwszValueName, DWORD dwOutputType, BOOL* pbHasDifference ) { // local variables
LONG lResult = 0; DWORD dwTypeLeft = 0; DWORD dwTypeRight = 0; DWORD dwSizeLeft = 0; DWORD dwSizeRight = 0; BYTE* pLeftData = NULL; BYTE* pRightData = NULL;
// check the input
if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL || hRightKey == NULL || pwszRightFullKeyName == NULL || pwszValueName == NULL || pbHasDifference == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; }
// optimizing the logic
// if user is not interested in seeing the differences,
// we will check whether the comparision done till now is same or not
// if not, there is no point in proceeding -- this is because, the final output
// of the tool is not going to be by continuing furthur
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( *pbHasDifference == TRUE ) { return ERROR_SUCCESS; } }
//
// First find out how much memory to allocate
//
lResult = RegQueryValueEx( hLeftKey, pwszValueName, 0, &dwTypeLeft, NULL, &dwSizeLeft ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
lResult = RegQueryValueEx( hRightKey, pwszValueName, 0, &dwTypeRight, NULL, &dwSizeRight ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
// furthur more optimizing the logic
// if user is not interested in seeing the differences,
// we will check the type and size information -- if they dont match, simply return
if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE ) { if ( dwTypeLeft != dwTypeRight || dwSizeLeft != dwSizeRight ) { *pbHasDifference = TRUE; return ERROR_SUCCESS; } }
// allocate memory for left data
// NOTE: always align the data on WCHAR boundary
dwSizeLeft = ALIGN_UP( dwSizeLeft, WCHAR ); pLeftData = (BYTE*) AllocateMemory( (dwSizeLeft + 2) * sizeof( BYTE ) ); if( pLeftData == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
// allocate memory for right data
// NOTE: always align the data on WCHAR boundary
dwSizeRight = ALIGN_UP( dwSizeRight, WCHAR ); pRightData = (BYTE*) AllocateMemory( (dwSizeRight + 2) * sizeof( BYTE ) ); if( pRightData == NULL ) { FreeMemory( &pLeftData ); SaveErrorMessage( ERROR_OUTOFMEMORY ); return ERROR_OUTOFMEMORY; }
//
// Now get the data
//
lResult = RegQueryValueEx( hLeftKey, pwszValueName, 0, &dwTypeLeft, pLeftData, &dwSizeLeft ); if( lResult == ERROR_SUCCESS ) { lResult = RegQueryValueEx( hRightKey, pwszValueName, 0, &dwTypeRight, pRightData, &dwSizeRight ); }
if( lResult != ERROR_SUCCESS ) { FreeMemory( &pLeftData ); FreeMemory( &pRightData ); SaveErrorMessage( lResult ); return lResult; }
if( dwTypeLeft != dwTypeRight || dwSizeLeft != dwSizeRight || CompareByteData( pLeftData, pRightData, dwSizeLeft ) == TRUE ) { if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL ) { // print left and right
PrintValue( pwszLeftFullKeyName, pwszValueName, dwTypeLeft, pLeftData, dwSizeLeft, PRINTTYPE_LEFT ); PrintValue( pwszRightFullKeyName, pwszValueName, dwTypeRight, pRightData, dwSizeRight, PRINTTYPE_RIGHT ); }
// ...
*pbHasDifference = TRUE; } else // they are the same
{ if( dwOutputType == OUTPUTTYPE_SAME || dwOutputType == OUTPUTTYPE_ALL ) { PrintValue( pwszLeftFullKeyName, pwszValueName, dwTypeLeft, pLeftData, dwSizeLeft, PRINTTYPE_SAME ); } }
// release memory allocate and return
FreeMemory( &pLeftData ); FreeMemory( &pRightData ); SaveErrorMessage( lResult ); return lResult; }
BOOL PrintKey( LPCWSTR pwszFullKeyName, LPCWSTR pwszSubKeyName, DWORD dwPrintType ) { // check the input
if ( pwszFullKeyName == NULL || pwszSubKeyName == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
// print type
if( dwPrintType == PRINTTYPE_LEFT ) { ShowMessage( stdout, L"< " ); } else if( dwPrintType == PRINTTYPE_RIGHT ) { ShowMessage( stdout, L"> " ); } else if( dwPrintType == PRINTTYPE_SAME ) { ShowMessage( stdout, L"= " ); }
// show the key
ShowMessageEx( stdout, 1, TRUE, GetResString2( IDS_KEY_COMPARE, 0 ), pwszFullKeyName, pwszSubKeyName );
// ...
ShowMessage( stdout, L"\n" );
return TRUE; }
LONG OutputValue( HKEY hKey, LPCWSTR pwszFullKeyName, LPCWSTR pwszValueName, DWORD dwPrintType ) { // local variables
LONG lResult = ERROR_SUCCESS; DWORD dwType = 0; DWORD dwSize = 0; BYTE* pByteData = NULL;
//
// First find out how much memory to allocate
//
lResult = RegQueryValueEx( hKey, pwszValueName, 0, &dwType, NULL, &dwSize ); if( lResult != ERROR_SUCCESS ) { return lResult; }
// allocate memory
// NOTE: always align the buffer on the WCHAR border
dwSize = ALIGN_UP( dwSize, WCHAR ); pByteData = (BYTE*) AllocateMemory( (dwSize + 2) * sizeof( BYTE ) ); if( pByteData == NULL ) { return ERROR_NOT_ENOUGH_MEMORY; }
//
// Now get the data
//
lResult = RegQueryValueEx( hKey, pwszValueName, 0, &dwType, (LPBYTE) pByteData, &dwSize ); if( lResult == ERROR_SUCCESS ) { PrintValue( pwszFullKeyName, pwszValueName, dwType, pByteData, dwSize, dwPrintType); }
// release memory
FreeMemory( &pByteData );
// return
return lResult; }
BOOL PrintValue( LPCWSTR pwszFullKeyName, LPCWSTR pwszValueName, DWORD dwType, BYTE* pData, DWORD dwSize, DWORD dwPrintType ) { // local variables
TREG_SHOW_INFO showinfo;
// check the input
if ( pwszFullKeyName == NULL || pwszValueName == NULL || pData == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
// print type
if( dwPrintType == PRINTTYPE_LEFT ) { ShowMessage( stdout, L"< " ); } else if( dwPrintType == PRINTTYPE_RIGHT ) { ShowMessage( stdout, L"> " ); } else if( dwPrintType == PRINTTYPE_SAME ) { ShowMessage( stdout, L"= " ); }
// first Print Key
ShowMessageEx( stdout, 1, TRUE, GetResString2( IDS_VALUE_COMPARE, 0 ), pwszFullKeyName );
// init to ZERO
SecureZeroMemory( &showinfo, sizeof( TREG_SHOW_INFO ) );
// set the data
showinfo.pwszValueName = pwszValueName; showinfo.dwType = dwType; showinfo.pByteData = pData; showinfo.pwszSeparator = NULL; showinfo.dwMaxValueNameLength = 0; showinfo.dwPadLength = 2; showinfo.dwSize = dwSize; showinfo.pwszMultiSzSeparator = NULL;
// show the value and return
return ShowRegistryValue( &showinfo ); }
BOOL CompareByteData( BYTE* pLeftData, BYTE* pRightData, DWORD dwSize ) { // local variables
DWORD dw = 0; BOOL bDifferent = FALSE;
// check the input
if ( pLeftData == NULL || pRightData == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
bDifferent = FALSE; for( dw = 0; dw < dwSize; dw++ ) { if( pLeftData[ dw ] != pRightData[ dw ] ) { bDifferent = TRUE; break; } }
return bDifferent; }
|