1183 lines
33 KiB
C
1183 lines
33 KiB
C
|
//-----------------------------------------------------------------------//
|
||
|
//
|
||
|
// File: compare.cpp
|
||
|
// Created: April 1999
|
||
|
// By: Zeyong Xu
|
||
|
// Purpose: Compare two registry key
|
||
|
//
|
||
|
//------------------------------------------------------------------------//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "reg.h"
|
||
|
#include "compare.h"
|
||
|
|
||
|
|
||
|
BOOL g_bHasDifference = FALSE;
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------//
|
||
|
//
|
||
|
// CompareRegistry()
|
||
|
//
|
||
|
//-----------------------------------------------------------------------//
|
||
|
|
||
|
LONG CompareRegistry(PAPPVARS pAppVars,
|
||
|
PAPPVARS pDstVars,
|
||
|
UINT argc,
|
||
|
TCHAR *argv[])
|
||
|
{
|
||
|
LONG nResult;
|
||
|
HKEY hLeftKey;
|
||
|
HKEY hRightKey;
|
||
|
|
||
|
//
|
||
|
// Parse the cmd-line
|
||
|
//
|
||
|
nResult = ParseCompareCmdLine(pAppVars, pDstVars, argc, argv);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Connect to the Remote Machine(s) - if applicable
|
||
|
//
|
||
|
nResult = RegConnectMachine(pAppVars);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
nResult = RegConnectMachine(pDstVars);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now implement the body of the Compare Operation
|
||
|
//
|
||
|
nResult = RegOpenKeyEx(pAppVars->hRootKey,
|
||
|
pAppVars->szSubKey,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hLeftKey);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
nResult = RegOpenKeyEx(pDstVars->hRootKey,
|
||
|
pDstVars->szSubKey,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRightKey);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
// if try to compare the same keys
|
||
|
if (pAppVars->hRootKey == pDstVars->hRootKey &&
|
||
|
_tcsicmp(pAppVars->szFullKey, pDstVars->szFullKey) == 0)
|
||
|
{
|
||
|
RegCloseKey(hLeftKey);
|
||
|
RegCloseKey(hRightKey);
|
||
|
return REG_STATUS_COMPARESELF;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// compare a single value if pAppVars->szValueName is not NULL
|
||
|
//
|
||
|
if(pAppVars->szValueName)
|
||
|
{
|
||
|
nResult = CompareValues(hLeftKey,
|
||
|
pAppVars->szFullKey,
|
||
|
hRightKey,
|
||
|
pDstVars->szFullKey,
|
||
|
pAppVars->szValueName,
|
||
|
pAppVars->nOutputType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Recursively compare if pAppVars->bRecurseSubKeys is true
|
||
|
//
|
||
|
nResult = CompareEnumerateKey(hLeftKey,
|
||
|
pAppVars->szFullKey,
|
||
|
hRightKey,
|
||
|
pDstVars->szFullKey,
|
||
|
pAppVars->nOutputType,
|
||
|
pAppVars->bRecurseSubKeys);
|
||
|
}
|
||
|
|
||
|
if(nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
pAppVars->bHasDifference = g_bHasDifference;
|
||
|
if(g_bHasDifference)
|
||
|
MyTPrintf(stdout,_T("\r\nResult Compared: Different\r\n"));
|
||
|
else
|
||
|
MyTPrintf(stdout,_T("\r\nResult Compared: Identical\r\n"));
|
||
|
}
|
||
|
//
|
||
|
// lets clean up
|
||
|
//
|
||
|
RegCloseKey(hLeftKey);
|
||
|
RegCloseKey(hRightKey);
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
REG_STATUS ParseCompareCmdLine(PAPPVARS pAppVars,
|
||
|
PAPPVARS pDstVars,
|
||
|
UINT argc,
|
||
|
TCHAR *argv[])
|
||
|
{
|
||
|
UINT i;
|
||
|
REG_STATUS nResult = ERROR_SUCCESS;
|
||
|
BOOL bInvalidParams = FALSE;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Do we have a *valid* number of cmd-line params
|
||
|
//
|
||
|
if(argc < 4)
|
||
|
{
|
||
|
return REG_STATUS_TOFEWPARAMS;
|
||
|
}
|
||
|
else if(argc > 8)
|
||
|
{
|
||
|
return REG_STATUS_TOMANYPARAMS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Left Machine Name and Registry key
|
||
|
//
|
||
|
nResult = BreakDownKeyString(argv[2], pAppVars);
|
||
|
if(nResult != ERROR_SUCCESS)
|
||
|
return nResult;
|
||
|
|
||
|
//
|
||
|
// Right Machine Name and Registry key
|
||
|
//
|
||
|
nResult = BreakDownKeyString(argv[3], pDstVars);
|
||
|
if(nResult == REG_STATUS_NOKEYNAME)
|
||
|
{
|
||
|
// if no keyname for right side is specified,
|
||
|
// they are comparing the same key name
|
||
|
nResult = CopyKeyNameFromLeftToRight(pAppVars, pDstVars);
|
||
|
}
|
||
|
if( nResult != ERROR_SUCCESS)
|
||
|
return nResult;
|
||
|
|
||
|
// parsing
|
||
|
for(i=4; i<argc; i++)
|
||
|
{
|
||
|
if(!_tcsicmp(argv[i], _T("/v")))
|
||
|
{
|
||
|
if(bInvalidParams || pAppVars->bRecurseSubKeys)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
i++;
|
||
|
if(i<argc)
|
||
|
{
|
||
|
pAppVars->szValueName = (TCHAR*) calloc(_tcslen(argv[i]) + 1,
|
||
|
sizeof(TCHAR));
|
||
|
if (!pAppVars->szValueName) {
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
_tcscpy(pAppVars->szValueName, argv[i]);
|
||
|
}
|
||
|
else
|
||
|
return REG_STATUS_TOFEWPARAMS;
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/ve")))
|
||
|
{
|
||
|
if(bInvalidParams || pAppVars->bRecurseSubKeys)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
pAppVars->szValueName = (TCHAR*) calloc(1, sizeof(TCHAR));
|
||
|
if (!pAppVars->szValueName) {
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/oa")))
|
||
|
{
|
||
|
if(bInvalidParams)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
pAppVars->nOutputType = OUTPUTTYPE_ALL;
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/od")))
|
||
|
{
|
||
|
if(bInvalidParams)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
pAppVars->nOutputType = OUTPUTTYPE_DIFF;
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/os")))
|
||
|
{
|
||
|
if(bInvalidParams)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
pAppVars->nOutputType = OUTPUTTYPE_SAME;
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/on")))
|
||
|
{
|
||
|
if(bInvalidParams)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
bInvalidParams = TRUE;
|
||
|
|
||
|
pAppVars->nOutputType = OUTPUTTYPE_NONE;
|
||
|
}
|
||
|
else if(!_tcsicmp(argv[i], _T("/s")))
|
||
|
{
|
||
|
if(pAppVars->szValueName)
|
||
|
return REG_STATUS_INVALIDPARAMS;
|
||
|
|
||
|
pAppVars->bRecurseSubKeys = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nResult = REG_STATUS_INVALIDPARAMS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
REG_STATUS CopyKeyNameFromLeftToRight(APPVARS* pAppVars, APPVARS* pDstVars)
|
||
|
{
|
||
|
// check if rootkey is remotable for right side
|
||
|
if( pDstVars->bUseRemoteMachine &&
|
||
|
!(pAppVars->hRootKey == HKEY_USERS ||
|
||
|
pAppVars->hRootKey == HKEY_LOCAL_MACHINE) )
|
||
|
{
|
||
|
return REG_STATUS_NONREMOTABLEROOT;
|
||
|
}
|
||
|
|
||
|
pDstVars->szFullKey = (TCHAR*) calloc(_tcslen(pAppVars->szFullKey) + 1,
|
||
|
sizeof(TCHAR));
|
||
|
|
||
|
if (!pDstVars->szFullKey)
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
pDstVars->szSubKey = (TCHAR*) calloc(_tcslen(pAppVars->szSubKey) + 1,
|
||
|
sizeof(TCHAR));
|
||
|
|
||
|
if (!pDstVars->szSubKey) {
|
||
|
free (pDstVars->szFullKey);
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
_tcscpy(pDstVars->szFullKey, pAppVars->szFullKey);
|
||
|
|
||
|
pDstVars->hRootKey = pAppVars->hRootKey;
|
||
|
|
||
|
_tcscpy(pDstVars->szSubKey, pAppVars->szSubKey);
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------//
|
||
|
//
|
||
|
// EnumerateKey() - Recursive
|
||
|
//
|
||
|
//-----------------------------------------------------------------------//
|
||
|
LONG CompareEnumerateKey(HKEY hLeftKey,
|
||
|
TCHAR* szLeftFullKeyName,
|
||
|
HKEY hRightKey,
|
||
|
TCHAR* szRightFullKeyName,
|
||
|
int nOutputType,
|
||
|
BOOL bRecurseSubKeys)
|
||
|
{
|
||
|
DWORD nResult;
|
||
|
DWORD dwSize;
|
||
|
TCHAR* pszLeftNameBuf;
|
||
|
TCHAR* pszRightNameBuf;
|
||
|
TCHAR** pLeftArray;
|
||
|
TCHAR** pRightArray;
|
||
|
DWORD dwIndex;
|
||
|
DWORD dwNumOfLeftKeyName;
|
||
|
DWORD dwLenOfLeftKeyName;
|
||
|
DWORD dwNumOfRightKeyName;
|
||
|
DWORD dwLenOfRightKeyName;
|
||
|
DWORD dw;
|
||
|
HKEY hLeftSubKey;
|
||
|
HKEY hRightSubKey;
|
||
|
|
||
|
|
||
|
// enumerate all values under current key
|
||
|
nResult = CompareEnumerateValueName(hLeftKey,
|
||
|
szLeftFullKeyName,
|
||
|
hRightKey,
|
||
|
szRightFullKeyName,
|
||
|
nOutputType);
|
||
|
|
||
|
if(!bRecurseSubKeys || nResult != ERROR_SUCCESS)
|
||
|
return nResult;
|
||
|
|
||
|
// enum all subkeys
|
||
|
|
||
|
// query left key info
|
||
|
nResult = RegQueryInfoKey(hLeftKey,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&dwNumOfLeftKeyName,
|
||
|
&dwLenOfLeftKeyName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
// query right key info
|
||
|
nResult = RegQueryInfoKey(hRightKey,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&dwNumOfRightKeyName,
|
||
|
&dwLenOfRightKeyName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
#ifndef REG_FOR_WIN2000 // ansi version for win98
|
||
|
// fix API bugs: RegQueryInfoKey() returns non-correct length values
|
||
|
// on remote Win98
|
||
|
if(dwLenOfLeftKeyName < MAX_PATH)
|
||
|
dwLenOfLeftKeyName = MAX_PATH;
|
||
|
if(dwLenOfRightKeyName < MAX_PATH)
|
||
|
dwLenOfRightKeyName = MAX_PATH;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// enumerate all of the subkeys in left key
|
||
|
//
|
||
|
dwLenOfLeftKeyName++;
|
||
|
pszLeftNameBuf = (TCHAR*) calloc(dwNumOfLeftKeyName *
|
||
|
dwLenOfLeftKeyName,
|
||
|
sizeof(TCHAR));
|
||
|
if (!pszLeftNameBuf) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
// index array of name buffer for compare
|
||
|
pLeftArray = (TCHAR**) calloc(dwNumOfLeftKeyName, sizeof(TCHAR*));
|
||
|
if (!pLeftArray) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwIndex = 0;
|
||
|
while(dwIndex < dwNumOfLeftKeyName && nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
pLeftArray[dwIndex] = pszLeftNameBuf +
|
||
|
(dwIndex * dwLenOfLeftKeyName);
|
||
|
dwSize = dwLenOfLeftKeyName;
|
||
|
nResult = RegEnumKeyEx(hLeftKey,
|
||
|
dwIndex,
|
||
|
pLeftArray[dwIndex],
|
||
|
&dwSize,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
dwIndex++;
|
||
|
}
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// enumerate all of the subkeys in right key
|
||
|
//
|
||
|
dwLenOfRightKeyName++;
|
||
|
pszRightNameBuf = (TCHAR*) calloc(dwNumOfRightKeyName *
|
||
|
dwLenOfRightKeyName,
|
||
|
sizeof(TCHAR));
|
||
|
if (!pszRightNameBuf) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
// index array of name buffer for compare
|
||
|
pRightArray = (TCHAR**) calloc(dwNumOfRightKeyName, sizeof(TCHAR*));
|
||
|
if (!pRightArray) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwIndex = 0;
|
||
|
while(dwIndex < dwNumOfRightKeyName && nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
pRightArray[dwIndex] = pszRightNameBuf +
|
||
|
(dwIndex * dwLenOfRightKeyName);
|
||
|
dwSize = dwLenOfRightKeyName;
|
||
|
nResult = RegEnumKeyEx(hRightKey,
|
||
|
dwIndex,
|
||
|
pRightArray[dwIndex],
|
||
|
&dwSize,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
dwIndex++;
|
||
|
}
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
if(pszRightNameBuf)
|
||
|
free(pszRightNameBuf);
|
||
|
if(pRightArray)
|
||
|
free(pRightArray);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
// compare two subkey name array to find the same subkey
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfLeftKeyName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pLeftArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
for(dw = 0;
|
||
|
dw < dwNumOfRightKeyName && nResult == ERROR_SUCCESS;
|
||
|
dw++)
|
||
|
{
|
||
|
if(pRightArray[dw] == NULL)
|
||
|
continue;
|
||
|
|
||
|
// if same subey name, recusive
|
||
|
if(_tcsicmp(pLeftArray[dwIndex], pRightArray[dw]) == 0)
|
||
|
{
|
||
|
TCHAR* szTempLeft;
|
||
|
TCHAR* szTempRight;
|
||
|
|
||
|
// print out key
|
||
|
if( nOutputType == OUTPUTTYPE_SAME ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
nResult = PrintKey(hLeftKey,
|
||
|
szLeftFullKeyName,
|
||
|
pLeftArray[dwIndex],
|
||
|
PRINTTYPE_SAME);
|
||
|
if(nResult != ERROR_SUCCESS)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now implement the body of the Compare Operation
|
||
|
//
|
||
|
nResult = RegOpenKeyEx(hLeftKey,
|
||
|
pLeftArray[dwIndex],
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hLeftSubKey);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
break;
|
||
|
|
||
|
nResult = RegOpenKeyEx(hRightKey,
|
||
|
pLeftArray[dwIndex],
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRightSubKey);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
break;
|
||
|
|
||
|
// create left full subkey
|
||
|
szTempLeft = (TCHAR*) calloc(_tcslen(szLeftFullKeyName) +
|
||
|
_tcslen(pLeftArray[dwIndex]) +
|
||
|
2,
|
||
|
sizeof(TCHAR));
|
||
|
if (!szTempLeft) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
_tcscpy(szTempLeft, szLeftFullKeyName);
|
||
|
_tcscat(szTempLeft, _T("\\"));
|
||
|
_tcscat(szTempLeft, pLeftArray[dwIndex]);
|
||
|
// create right full subkey
|
||
|
szTempRight = (TCHAR*) calloc(_tcslen(szRightFullKeyName) +
|
||
|
_tcslen(pLeftArray[dwIndex]) +
|
||
|
2,
|
||
|
sizeof(TCHAR));
|
||
|
if (!szTempRight) {
|
||
|
free (szTempLeft);
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
_tcscpy(szTempRight, szRightFullKeyName);
|
||
|
_tcscat(szTempRight, _T("\\"));
|
||
|
_tcscat(szTempRight, pLeftArray[dwIndex]);
|
||
|
|
||
|
// recursive to compare subkeys
|
||
|
nResult = CompareEnumerateKey(hLeftSubKey,
|
||
|
szLeftFullKeyName,
|
||
|
hRightSubKey,
|
||
|
szRightFullKeyName,
|
||
|
nOutputType,
|
||
|
bRecurseSubKeys);
|
||
|
|
||
|
if(szTempLeft) {
|
||
|
free(szTempLeft);
|
||
|
}
|
||
|
if(szTempRight) {
|
||
|
free(szTempRight);
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hLeftSubKey);
|
||
|
RegCloseKey(hRightSubKey);
|
||
|
|
||
|
pLeftArray[dwIndex] = NULL;
|
||
|
pRightArray[dw] = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Output subkey name in left key
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfLeftKeyName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pLeftArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
if( nOutputType == OUTPUTTYPE_DIFF ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
nResult = PrintKey(hLeftKey,
|
||
|
szLeftFullKeyName,
|
||
|
pLeftArray[dwIndex],
|
||
|
PRINTTYPE_LEFT);
|
||
|
}
|
||
|
g_bHasDifference = TRUE;
|
||
|
}
|
||
|
// Output subkey name in right key
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfRightKeyName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pRightArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
if( nOutputType == OUTPUTTYPE_DIFF ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
nResult = PrintKey(hRightKey,
|
||
|
szRightFullKeyName,
|
||
|
pRightArray[dwIndex],
|
||
|
PRINTTYPE_RIGHT);
|
||
|
}
|
||
|
g_bHasDifference = TRUE;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
if(pszRightNameBuf)
|
||
|
free(pszRightNameBuf);
|
||
|
if(pRightArray)
|
||
|
free(pRightArray);
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
LONG CompareEnumerateValueName(HKEY hLeftKey,
|
||
|
TCHAR* szLeftFullKeyName,
|
||
|
HKEY hRightKey,
|
||
|
TCHAR* szRightFullKeyName,
|
||
|
int nOutputType)
|
||
|
|
||
|
{
|
||
|
DWORD nResult = ERROR_SUCCESS;
|
||
|
DWORD dwSize;
|
||
|
TCHAR* pszLeftNameBuf = NULL;
|
||
|
TCHAR* pszRightNameBuf = NULL;
|
||
|
TCHAR** pLeftArray = NULL;
|
||
|
TCHAR** pRightArray = NULL;
|
||
|
DWORD dwIndex;
|
||
|
DWORD dwNumOfRightValueName;
|
||
|
DWORD dwLenOfRightValueName;
|
||
|
DWORD dw;
|
||
|
|
||
|
|
||
|
// query left key info
|
||
|
DWORD dwNumOfLeftValueName;
|
||
|
DWORD dwLenOfLeftValueName;
|
||
|
nResult = RegQueryInfoKey(hLeftKey,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&dwNumOfLeftValueName,
|
||
|
&dwLenOfLeftValueName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
// query right key info
|
||
|
nResult = RegQueryInfoKey(hRightKey,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&dwNumOfRightValueName,
|
||
|
&dwLenOfRightValueName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
#ifndef REG_FOR_WIN2000 // ansi version for win98
|
||
|
// fix API bugs: RegQueryInfoKey() returns non-correct length values
|
||
|
// on remote Win98
|
||
|
if(dwLenOfLeftValueName < MAX_PATH)
|
||
|
dwLenOfLeftValueName = MAX_PATH;
|
||
|
if(dwLenOfRightValueName < MAX_PATH)
|
||
|
dwLenOfRightValueName = MAX_PATH;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// enumerate all of the values in left key
|
||
|
//
|
||
|
dwLenOfLeftValueName++;
|
||
|
pszLeftNameBuf = (TCHAR*) calloc(dwNumOfLeftValueName *
|
||
|
dwLenOfLeftValueName,
|
||
|
sizeof(TCHAR));
|
||
|
if (!pszLeftNameBuf) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// index array of name buffer for compare
|
||
|
pLeftArray = (TCHAR**) calloc(dwNumOfLeftValueName, sizeof(TCHAR*));
|
||
|
if (!pLeftArray) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwIndex = 0;
|
||
|
while(dwIndex < dwNumOfLeftValueName && nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
pLeftArray[dwIndex] = pszLeftNameBuf +
|
||
|
(dwIndex * dwLenOfLeftValueName);
|
||
|
dwSize = dwLenOfLeftValueName;
|
||
|
nResult = RegEnumValue(hLeftKey,
|
||
|
dwIndex,
|
||
|
pLeftArray[dwIndex],
|
||
|
&dwSize,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
dwIndex++;
|
||
|
}
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// enumerate all of the values in right key
|
||
|
//
|
||
|
dwLenOfRightValueName++;
|
||
|
pszRightNameBuf = (TCHAR*) calloc(dwNumOfRightValueName *
|
||
|
dwLenOfRightValueName,
|
||
|
sizeof(TCHAR));
|
||
|
if (!pszRightNameBuf) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
// index array of name buffer for compare
|
||
|
pRightArray = (TCHAR**) calloc(dwNumOfRightValueName, sizeof(TCHAR*));
|
||
|
if (!pRightArray) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwIndex = 0;
|
||
|
while(dwIndex < dwNumOfRightValueName && nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
pRightArray[dwIndex] = pszRightNameBuf +
|
||
|
(dwIndex * dwLenOfRightValueName);
|
||
|
dwSize = dwLenOfRightValueName;
|
||
|
nResult = RegEnumValue(hRightKey,
|
||
|
dwIndex,
|
||
|
pRightArray[dwIndex],
|
||
|
&dwSize,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
dwIndex++;
|
||
|
}
|
||
|
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
if(pszRightNameBuf)
|
||
|
free(pszRightNameBuf);
|
||
|
if(pRightArray)
|
||
|
free(pRightArray);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
// compare two valuename array to find the same valuename
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfLeftValueName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pLeftArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
for(dw = 0;
|
||
|
dw < dwNumOfRightValueName && nResult == ERROR_SUCCESS;
|
||
|
dw++)
|
||
|
{
|
||
|
if(pRightArray[dw] == NULL)
|
||
|
continue;
|
||
|
|
||
|
// same valuename
|
||
|
if(_tcsicmp(pLeftArray[dwIndex], pRightArray[dw]) == 0)
|
||
|
{
|
||
|
nResult = CompareValues(hLeftKey,
|
||
|
szLeftFullKeyName,
|
||
|
hRightKey,
|
||
|
szRightFullKeyName,
|
||
|
pLeftArray[dwIndex],
|
||
|
nOutputType);
|
||
|
pLeftArray[dwIndex] = NULL;
|
||
|
pRightArray[dw] = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Output different valuename in left key
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfLeftValueName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pLeftArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
if( nOutputType == OUTPUTTYPE_DIFF ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
nResult = OutputValue(hLeftKey,
|
||
|
szLeftFullKeyName,
|
||
|
pLeftArray[dwIndex],
|
||
|
PRINTTYPE_LEFT);
|
||
|
}
|
||
|
g_bHasDifference = TRUE;
|
||
|
}
|
||
|
// Output different valuename in right key
|
||
|
for(dwIndex = 0;
|
||
|
dwIndex < dwNumOfRightValueName && nResult == ERROR_SUCCESS;
|
||
|
dwIndex++)
|
||
|
{
|
||
|
if(pRightArray[dwIndex] == NULL)
|
||
|
continue;
|
||
|
|
||
|
if( nOutputType == OUTPUTTYPE_DIFF ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
nResult = OutputValue(hRightKey,
|
||
|
szRightFullKeyName,
|
||
|
pRightArray[dwIndex],
|
||
|
PRINTTYPE_RIGHT);
|
||
|
}
|
||
|
g_bHasDifference = TRUE;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if(pszLeftNameBuf)
|
||
|
free(pszLeftNameBuf);
|
||
|
if(pLeftArray)
|
||
|
free(pLeftArray);
|
||
|
if(pszRightNameBuf)
|
||
|
free(pszRightNameBuf);
|
||
|
if(pRightArray)
|
||
|
free(pRightArray);
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------//
|
||
|
//
|
||
|
// CompareValues()
|
||
|
//
|
||
|
//-----------------------------------------------------------------------//
|
||
|
|
||
|
LONG CompareValues(HKEY hLeftKey,
|
||
|
TCHAR* szLeftFullKeyName,
|
||
|
HKEY hRightKey,
|
||
|
TCHAR* szRightFullKeyName,
|
||
|
TCHAR* szValueName,
|
||
|
int nOutputType)
|
||
|
{
|
||
|
|
||
|
LONG nResult;
|
||
|
DWORD dwTypeLeft;
|
||
|
DWORD dwTypeRight;
|
||
|
DWORD dwSizeLeft;
|
||
|
DWORD dwSizeRight;
|
||
|
BYTE* pDataBuffLeft = NULL;
|
||
|
BYTE* pDataBuffRight = NULL;
|
||
|
|
||
|
//
|
||
|
// First find out how much memory to allocate
|
||
|
//
|
||
|
nResult = RegQueryValueEx(hLeftKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwTypeLeft,
|
||
|
NULL,
|
||
|
&dwSizeLeft);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
nResult = RegQueryValueEx(hRightKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwTypeRight,
|
||
|
NULL,
|
||
|
&dwSizeRight);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
pDataBuffLeft = (BYTE*) calloc(dwSizeLeft + 1, sizeof(BYTE));
|
||
|
if (!pDataBuffLeft) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
pDataBuffRight = (BYTE*) calloc(dwSizeRight + 1, sizeof(BYTE));
|
||
|
|
||
|
if (!pDataBuffRight) {
|
||
|
nResult = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now get the data
|
||
|
//
|
||
|
nResult = RegQueryValueEx(hLeftKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwTypeLeft,
|
||
|
(LPBYTE) pDataBuffLeft,
|
||
|
&dwSizeLeft);
|
||
|
|
||
|
if (nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
nResult = RegQueryValueEx(hRightKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwTypeRight,
|
||
|
(LPBYTE) pDataBuffRight,
|
||
|
&dwSizeRight);
|
||
|
}
|
||
|
|
||
|
if(nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(pDataBuffLeft)
|
||
|
free(pDataBuffLeft);
|
||
|
if(pDataBuffRight)
|
||
|
free(pDataBuffRight);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
if( dwTypeLeft != dwTypeRight ||
|
||
|
dwSizeLeft != dwSizeRight ||
|
||
|
CompareByteData(pDataBuffLeft, pDataBuffRight, dwSizeLeft) )
|
||
|
{
|
||
|
if( nOutputType == OUTPUTTYPE_DIFF ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
// print left and right
|
||
|
PrintValue(szLeftFullKeyName,
|
||
|
szValueName,
|
||
|
dwTypeLeft,
|
||
|
pDataBuffLeft,
|
||
|
dwSizeLeft,
|
||
|
PRINTTYPE_LEFT);
|
||
|
PrintValue(szRightFullKeyName,
|
||
|
szValueName,
|
||
|
dwTypeRight,
|
||
|
pDataBuffRight,
|
||
|
dwSizeRight,
|
||
|
PRINTTYPE_RIGHT);
|
||
|
}
|
||
|
g_bHasDifference = TRUE;
|
||
|
}
|
||
|
else // they are the same
|
||
|
{
|
||
|
if( nOutputType == OUTPUTTYPE_SAME ||
|
||
|
nOutputType == OUTPUTTYPE_ALL )
|
||
|
{
|
||
|
PrintValue(szLeftFullKeyName,
|
||
|
szValueName,
|
||
|
dwTypeLeft,
|
||
|
pDataBuffLeft,
|
||
|
dwSizeLeft,
|
||
|
PRINTTYPE_SAME);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if(pDataBuffLeft)
|
||
|
free(pDataBuffLeft);
|
||
|
if(pDataBuffRight)
|
||
|
free(pDataBuffRight);
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
LONG PrintKey(HKEY hKey,
|
||
|
TCHAR* szFullKeyName,
|
||
|
TCHAR* szSubKeyName,
|
||
|
int nPrintType)
|
||
|
{
|
||
|
LONG nResult;
|
||
|
HKEY hSubKey;
|
||
|
|
||
|
// make sure key is there
|
||
|
nResult = RegOpenKeyEx(hKey,
|
||
|
szSubKeyName,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hSubKey);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
return nResult;
|
||
|
|
||
|
RegCloseKey(hSubKey);
|
||
|
|
||
|
// print type
|
||
|
if(nPrintType == PRINTTYPE_LEFT)
|
||
|
MyTPrintf(stdout,_T("< "));
|
||
|
else if(nPrintType == PRINTTYPE_RIGHT)
|
||
|
MyTPrintf(stdout,_T("> "));
|
||
|
else if(nPrintType == PRINTTYPE_SAME)
|
||
|
MyTPrintf(stdout,_T("= "));
|
||
|
|
||
|
MyTPrintf(stdout,_T("Key: %s\\%s\r\n"), szFullKeyName, szSubKeyName);
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
LONG OutputValue(HKEY hKey,
|
||
|
TCHAR* szFullKeyName,
|
||
|
TCHAR* szValueName,
|
||
|
int nPrintType)
|
||
|
{
|
||
|
LONG nResult = ERROR_SUCCESS;
|
||
|
DWORD dwType;
|
||
|
DWORD dwSize;
|
||
|
BYTE* pDataBuff;
|
||
|
|
||
|
//
|
||
|
// First find out how much memory to allocate
|
||
|
//
|
||
|
nResult = RegQueryValueEx(hKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwType,
|
||
|
NULL,
|
||
|
&dwSize);
|
||
|
if (nResult != ERROR_SUCCESS)
|
||
|
{
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
pDataBuff = (BYTE*) calloc(dwSize + 1, sizeof(BYTE));
|
||
|
|
||
|
if (!pDataBuff) {
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now get the data
|
||
|
//
|
||
|
nResult = RegQueryValueEx(hKey,
|
||
|
szValueName,
|
||
|
0,
|
||
|
&dwType,
|
||
|
(LPBYTE) pDataBuff,
|
||
|
&dwSize);
|
||
|
|
||
|
if(nResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
PrintValue(szFullKeyName,
|
||
|
szValueName,
|
||
|
dwType,
|
||
|
pDataBuff,
|
||
|
dwSize,
|
||
|
nPrintType);
|
||
|
}
|
||
|
|
||
|
if(pDataBuff)
|
||
|
free(pDataBuff);
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
void PrintValue(TCHAR* szFullKeyName,
|
||
|
TCHAR* szValueName,
|
||
|
DWORD dwType,
|
||
|
BYTE* pData,
|
||
|
DWORD dwSize,
|
||
|
int nPrintType)
|
||
|
{
|
||
|
DWORD i;
|
||
|
TCHAR szTypeStr[25];
|
||
|
|
||
|
|
||
|
|
||
|
// print type
|
||
|
if(nPrintType == PRINTTYPE_LEFT)
|
||
|
MyTPrintf(stdout,_T("< "));
|
||
|
else if(nPrintType == PRINTTYPE_RIGHT)
|
||
|
MyTPrintf(stdout,_T("> "));
|
||
|
else if(nPrintType == PRINTTYPE_SAME)
|
||
|
MyTPrintf(stdout,_T("= "));
|
||
|
|
||
|
// first Print Key
|
||
|
MyTPrintf(stdout,_T("Value: %s"), szFullKeyName);
|
||
|
|
||
|
// then print ValueName Type Data
|
||
|
GetTypeStrFromType(szTypeStr, dwType);
|
||
|
|
||
|
if(_tcslen(szValueName) == 0) // no name
|
||
|
{
|
||
|
MyTPrintf(stdout,_T(" <NO NAME> %s "), szTypeStr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MyTPrintf(stdout,_T(" %s %s "), szValueName, szTypeStr);
|
||
|
}
|
||
|
|
||
|
switch (dwType)
|
||
|
{
|
||
|
case REG_BINARY:
|
||
|
for(i=0; i<dwSize; i++)
|
||
|
{
|
||
|
MyTPrintf(stdout,_T("%02X"),pData[i]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case REG_DWORD:
|
||
|
case REG_DWORD_BIG_ENDIAN:
|
||
|
MyTPrintf(stdout,_T("0x%x"), *((DWORD*)pData) );
|
||
|
break;
|
||
|
|
||
|
case REG_MULTI_SZ:
|
||
|
{
|
||
|
//
|
||
|
// Replace '\0' with "\0" for MULTI_SZ
|
||
|
//
|
||
|
TCHAR* pEnd = (TCHAR*) pData;
|
||
|
while( (BYTE*)pEnd < pData + dwSize )
|
||
|
{
|
||
|
if(*pEnd == 0)
|
||
|
{
|
||
|
MyTPrintf(stdout,_T("\\0"));
|
||
|
pEnd++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MyTPrintf(stdout,_T("%s"), pEnd);
|
||
|
pEnd += _tcslen(pEnd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
MyTPrintf(stdout,_T("%s"), (TCHAR*) pData);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MyTPrintf(stdout,_T("\r\n"));
|
||
|
}
|
||
|
|
||
|
BOOL CompareByteData(BYTE* pDataBuffLeft, BYTE* pDataBuffRight, DWORD dwSize)
|
||
|
{
|
||
|
BOOL bDiff = FALSE;
|
||
|
DWORD dw;
|
||
|
|
||
|
for(dw=0; dw<dwSize; dw++)
|
||
|
{
|
||
|
if(pDataBuffLeft[dw] != pDataBuffRight[dw])
|
||
|
{
|
||
|
bDiff = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bDiff;
|
||
|
}
|