Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1401 lines
42 KiB

  1. //-----------------------------------------------------------------------//
  2. //
  3. // File: compare.cpp
  4. // Created: April 1999
  5. // By: Zeyong Xu
  6. // Purpose: Compare two registry key
  7. //
  8. //------------------------------------------------------------------------//
  9. #include "stdafx.h"
  10. #include "reg.h"
  11. //
  12. // defines / constants / enumerations
  13. //
  14. enum
  15. {
  16. OUTPUTTYPE_NONE = 1,
  17. OUTPUTTYPE_SAME = 2,
  18. OUTPUTTYPE_DIFF = 3,
  19. OUTPUTTYPE_ALL = 4
  20. };
  21. enum
  22. {
  23. PRINTTYPE_LEFT = 1,
  24. PRINTTYPE_RIGHT = 2,
  25. PRINTTYPE_SAME = 3,
  26. };
  27. //
  28. // function prototypes
  29. //
  30. BOOL CompareByteData( BYTE* pLeftData, BYTE* pRightData, DWORD dwSize );
  31. BOOL CopyKeyNameFromLeftToRight( PTREG_PARAMS pParams, PTREG_PARAMS pRightParams );
  32. LONG CompareEnumerateValueName( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName,
  33. HKEY hRightKey, LPCWSTR pwszRightFullKeyName,
  34. DWORD dwOutputType, BOOL* pbHasDifference );
  35. LONG CompareValues( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName,
  36. HKEY hRightKey, LPCWSTR pwszRightFullKeyName,
  37. LPCWSTR pwszValueName, DWORD dwOutputType, BOOL* pbHasDifference );
  38. LONG CompareEnumerateKey( HKEY hLeftKey, LPCWSTR pwszLeftFullKeyName,
  39. HKEY hRightKey, LPCWSTR pwszRightFullKeyName,
  40. DWORD dwOutputType, BOOL bRecurseSubKeys,
  41. BOOL* pbHasDifference, DWORD dwDepth );
  42. BOOL ParseCompareCmdLine( DWORD argc,
  43. LPCWSTR argv[],
  44. PTREG_PARAMS pParams,
  45. PTREG_PARAMS pRightParams, BOOL* pbUsage );
  46. BOOL PrintValue( LPCWSTR pwszFullKeyName, LPCWSTR pwszValueName,
  47. DWORD dwType, BYTE* pData, DWORD dwSize, DWORD dwPrintType );
  48. BOOL PrintKey( LPCWSTR pwszFullKeyName, LPCWSTR pwszSubKeyName, DWORD dwPrintType );
  49. LONG OutputValue( HKEY hKey, LPCWSTR szFullKeyName, LPCWSTR szValueName, DWORD dwPrintType );
  50. //
  51. // implementation
  52. //
  53. //-----------------------------------------------------------------------//
  54. //
  55. // CompareRegistry()
  56. //
  57. //-----------------------------------------------------------------------//
  58. LONG
  59. CompareRegistry( DWORD argc, LPCWSTR argv[] )
  60. {
  61. // local variables
  62. LONG lResult = 0;
  63. HKEY hLeftKey = NULL;
  64. HKEY hRightKey = NULL;
  65. BOOL bResult = FALSE;
  66. BOOL bUsage = FALSE;
  67. TREG_PARAMS params;
  68. TREG_PARAMS paramsRight;
  69. BOOL bHasDifference = FALSE;
  70. if ( argc == 0 || argv == NULL )
  71. {
  72. SetLastError( ERROR_INVALID_PARAMETER );
  73. ShowLastError( stderr );
  74. return 1;
  75. }
  76. // initialize the global data structure
  77. InitGlobalData( REG_COMPARE, &params );
  78. InitGlobalData( REG_COMPARE, &paramsRight );
  79. //
  80. // Parse the cmd-line
  81. //
  82. bResult = ParseCompareCmdLine( argc, argv, &params, &paramsRight, &bUsage );
  83. if( bResult == FALSE )
  84. {
  85. ShowLastErrorEx( stderr, SLE_INTERNAL );
  86. FreeGlobalData( &params );
  87. FreeGlobalData( &paramsRight );
  88. return 1;
  89. }
  90. // check whether we need to display the usage
  91. if ( bUsage == TRUE )
  92. {
  93. Usage( REG_COMPARE );
  94. FreeGlobalData( &params );
  95. FreeGlobalData( &paramsRight );
  96. return 0;
  97. }
  98. //
  99. // Connect to the Remote Machine(s) - if applicable
  100. //
  101. bResult = RegConnectMachine( &params );
  102. if( bResult == FALSE )
  103. {
  104. SaveErrorMessage( -1 );
  105. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  106. FreeGlobalData( &params );
  107. FreeGlobalData( &paramsRight );
  108. return 1;
  109. }
  110. bResult = RegConnectMachine( &paramsRight );
  111. if( bResult == FALSE )
  112. {
  113. SaveErrorMessage( -1 );
  114. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  115. FreeGlobalData( &params );
  116. FreeGlobalData( &paramsRight );
  117. return 1;
  118. }
  119. // if try to compare the same keys
  120. if ( params.hRootKey == paramsRight.hRootKey &&
  121. StringCompare( params.pwszFullKey, paramsRight.pwszFullKey, TRUE, 0 ) == 0 )
  122. {
  123. SetLastError( (DWORD) MK_E_SYNTAX );
  124. SetReason( ERROR_COMPARESELF_COMPARE );
  125. ShowLastErrorEx( stderr, SLE_INTERNAL );
  126. FreeGlobalData( &params );
  127. FreeGlobalData( &paramsRight );
  128. return 1;
  129. }
  130. //
  131. // Now implement the body of the Compare Operation
  132. //
  133. lResult = RegOpenKeyEx( params.hRootKey, params.pwszSubKey, 0, KEY_READ, &hLeftKey );
  134. if( lResult != ERROR_SUCCESS )
  135. {
  136. SaveErrorMessage( lResult );
  137. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  138. FreeGlobalData( &params );
  139. FreeGlobalData( &paramsRight );
  140. return 1;
  141. }
  142. lResult = RegOpenKeyEx( paramsRight.hRootKey,
  143. paramsRight.pwszSubKey, 0, KEY_READ, &hRightKey );
  144. if( lResult != ERROR_SUCCESS )
  145. {
  146. SaveErrorMessage( lResult );
  147. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  148. SafeCloseKey( &hLeftKey );
  149. FreeGlobalData( &params );
  150. FreeGlobalData( &paramsRight );
  151. return 1;
  152. }
  153. //
  154. // compare a single value if pAppVars->szValueName is not NULL
  155. //
  156. if( params.pwszValueName != NULL )
  157. {
  158. lResult = CompareValues(
  159. hLeftKey, params.pwszFullKey,
  160. hRightKey, paramsRight.pwszFullKey,
  161. params.pwszValueName, params.dwOutputType, &bHasDifference );
  162. }
  163. else
  164. {
  165. //
  166. // Recursively compare if pAppVars->bRecurseSubKeys is true
  167. //
  168. lResult = CompareEnumerateKey(
  169. hLeftKey, params.pwszFullKey,
  170. hRightKey, paramsRight.pwszFullKey,
  171. params.dwOutputType, params.bRecurseSubKeys, &bHasDifference, 0 );
  172. }
  173. if( lResult == ERROR_SUCCESS )
  174. {
  175. if( bHasDifference == TRUE )
  176. {
  177. lResult = 2;
  178. ShowMessage( stdout, KEYS_DIFFERENT_COMPARE );
  179. }
  180. else
  181. {
  182. lResult = 0;
  183. ShowMessage( stdout, KEYS_IDENTICAL_COMPARE );
  184. }
  185. // ...
  186. SaveErrorMessage( ERROR_SUCCESS );
  187. ShowLastErrorEx( stdout, SLE_INTERNAL );
  188. }
  189. else
  190. {
  191. lResult = 1;
  192. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  193. }
  194. //
  195. // lets clean up
  196. //
  197. SafeCloseKey( &hLeftKey );
  198. SafeCloseKey( &hRightKey );
  199. FreeGlobalData( &params );
  200. FreeGlobalData( &paramsRight );
  201. // return
  202. return lResult;
  203. }
  204. BOOL
  205. ParseCompareCmdLine( DWORD argc, LPCWSTR argv[],
  206. PTREG_PARAMS pParams, PTREG_PARAMS pRightParams, BOOL* pbUsage )
  207. {
  208. // local variables
  209. DWORD dw = 0;
  210. DWORD dwLength = 0;
  211. BOOL bResult = FALSE;
  212. // check the input
  213. if ( argc == 0 || argv == NULL ||
  214. pParams == NULL || pRightParams == NULL || pbUsage == NULL )
  215. {
  216. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  217. return FALSE;
  218. }
  219. // check whether this function is being called for
  220. // valid operation or not
  221. if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT )
  222. {
  223. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  224. return FALSE;
  225. }
  226. //
  227. // Do we have a *valid* number of cmd-line params
  228. //
  229. if ( argc == 3 &&
  230. InString( argv[ 2 ], L"/?|-?|/h|-h", TRUE ) == TRUE )
  231. {
  232. *pbUsage = TRUE;
  233. return TRUE;
  234. }
  235. else if( argc < 4 || argc > 8 )
  236. {
  237. SetLastError( (DWORD) MK_E_SYNTAX );
  238. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  239. return FALSE;
  240. }
  241. else if ( StringCompareEx( argv[ 1 ], L"COMPARE", TRUE, 0 ) != 0 )
  242. {
  243. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  244. return FALSE;
  245. }
  246. //
  247. // Left Machine Name and Registry key
  248. //
  249. bResult = BreakDownKeyString( argv[ 2 ], pParams );
  250. if( bResult == FALSE )
  251. {
  252. return FALSE;
  253. }
  254. //
  255. // Right Machine Name and Registry key
  256. //
  257. bResult = BreakDownKeyString( argv[ 3 ], pRightParams );
  258. if( bResult == FALSE )
  259. {
  260. if ( GetLastError() == (DWORD) REGDB_E_KEYMISSING )
  261. {
  262. // if no keyname for right side is specified,
  263. // they are comparing the same key name
  264. bResult = CopyKeyNameFromLeftToRight( pParams, pRightParams );
  265. }
  266. else if ( pRightParams->pwszMachineName != NULL &&
  267. StringCompareEx( pRightParams->pwszMachineName, L"\\\\.", TRUE, 0 ) == 0 )
  268. {
  269. // reinitialize the global data (right only)
  270. FreeGlobalData( pRightParams );
  271. InitGlobalData( REG_COMPARE, pRightParams );
  272. // parse the info using the left data (just the full key)
  273. bResult = BreakDownKeyString( pParams->pwszFullKey, pRightParams );
  274. }
  275. }
  276. // ...
  277. if( bResult == FALSE )
  278. {
  279. return FALSE;
  280. }
  281. // parsing
  282. for( dw = 4; dw < argc; dw++ )
  283. {
  284. if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 )
  285. {
  286. if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE )
  287. {
  288. SetLastError( (DWORD) MK_E_SYNTAX );
  289. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  290. return FALSE;
  291. }
  292. dw++;
  293. if( dw < argc )
  294. {
  295. dwLength = StringLength( argv[ dw ], 0 ) + 1;
  296. pParams->pwszValueName = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
  297. if ( pParams->pwszValueName == NULL )
  298. {
  299. SaveErrorMessage( ERROR_OUTOFMEMORY );
  300. return FALSE;
  301. }
  302. StringCopy( pParams->pwszValueName, argv[ dw ], dwLength );
  303. }
  304. else
  305. {
  306. SetLastError( (DWORD) MK_E_SYNTAX );
  307. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  308. return FALSE;
  309. }
  310. }
  311. else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 )
  312. {
  313. if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE )
  314. {
  315. SetLastError( (DWORD) MK_E_SYNTAX );
  316. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  317. return FALSE;
  318. }
  319. pParams->pwszValueName = (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) );
  320. if ( pParams->pwszValueName == NULL )
  321. {
  322. SetLastError( (DWORD) MK_E_SYNTAX );
  323. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  324. return FALSE;
  325. }
  326. }
  327. else if( StringCompareEx( argv[ dw ], L"/oa", TRUE, 0 ) == 0 )
  328. {
  329. if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 )
  330. {
  331. SetLastError( (DWORD) MK_E_SYNTAX );
  332. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  333. return FALSE;
  334. }
  335. pParams->dwOutputType = OUTPUTTYPE_ALL;
  336. }
  337. else if( StringCompareEx( argv[ dw ], L"/od", TRUE, 0 ) == 0 )
  338. {
  339. if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 )
  340. {
  341. SetLastError( (DWORD) MK_E_SYNTAX );
  342. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  343. return FALSE;
  344. }
  345. pParams->dwOutputType = OUTPUTTYPE_DIFF;
  346. }
  347. else if( StringCompareEx( argv[ dw ], L"/os", TRUE, 0 ) == 0 )
  348. {
  349. if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 )
  350. {
  351. SetLastError( (DWORD) MK_E_SYNTAX );
  352. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  353. return FALSE;
  354. }
  355. pParams->dwOutputType = OUTPUTTYPE_SAME;
  356. }
  357. else if( StringCompareEx( argv[ dw ], L"/on", TRUE, 0 ) == 0 )
  358. {
  359. if ( pParams->pwszValueName != NULL || pParams->dwOutputType != 0 )
  360. {
  361. SetLastError( (DWORD) MK_E_SYNTAX );
  362. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  363. return FALSE;
  364. }
  365. pParams->dwOutputType = OUTPUTTYPE_NONE;
  366. }
  367. else if( StringCompareEx( argv[ dw ], L"/s", TRUE, 0 ) == 0 )
  368. {
  369. if ( pParams->pwszValueName != NULL || pParams->bRecurseSubKeys == TRUE )
  370. {
  371. SetLastError( (DWORD) MK_E_SYNTAX );
  372. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  373. return FALSE;
  374. }
  375. pParams->bRecurseSubKeys = TRUE;
  376. }
  377. else
  378. {
  379. SetLastError( (DWORD) MK_E_SYNTAX );
  380. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COMPARE ] );
  381. return FALSE;
  382. }
  383. }
  384. // default output is "DIFF"
  385. if ( pParams->dwOutputType == 0 )
  386. {
  387. pParams->dwOutputType = OUTPUTTYPE_DIFF;
  388. }
  389. return TRUE;
  390. }
  391. BOOL
  392. CopyKeyNameFromLeftToRight( PTREG_PARAMS pParams, PTREG_PARAMS pRightParams )
  393. {
  394. // local variables
  395. DWORD dwLength = 0;
  396. // check the input
  397. if ( pParams == NULL || pRightParams == NULL )
  398. {
  399. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  400. return FALSE;
  401. }
  402. // check if rootkey is remotable for right side
  403. if( pRightParams->bUseRemoteMachine == TRUE &&
  404. pParams->hRootKey != HKEY_USERS && pParams->hRootKey != HKEY_LOCAL_MACHINE )
  405. {
  406. SetLastError( (DWORD) MK_E_SYNTAX );
  407. SetReason2( 1, ERROR_NONREMOTABLEROOT, g_wszOptions[ REG_COMPARE ] );
  408. return FALSE;
  409. }
  410. //
  411. // hive
  412. pRightParams->hRootKey = pParams->hRootKey;
  413. //
  414. // full key
  415. dwLength = StringLength( pParams->pwszFullKey, 0 ) + 1;
  416. pRightParams->pwszFullKey = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
  417. if( pRightParams->pwszFullKey == NULL )
  418. {
  419. SaveErrorMessage( ERROR_OUTOFMEMORY );
  420. return FALSE;
  421. }
  422. // ...
  423. StringCopy( pRightParams->pwszFullKey, pParams->pwszFullKey, dwLength );
  424. //
  425. // sub key
  426. dwLength = StringLength( pParams->pwszSubKey, 0 ) + 1;
  427. pRightParams->pwszSubKey = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
  428. if( pRightParams->pwszSubKey == NULL)
  429. {
  430. SaveErrorMessage( ERROR_OUTOFMEMORY );
  431. return FALSE;
  432. }
  433. // ...
  434. StringCopy( pRightParams->pwszSubKey, pParams->pwszSubKey, dwLength );
  435. // return
  436. return TRUE;
  437. }
  438. //-----------------------------------------------------------------------//
  439. //
  440. // EnumerateKey() - Recursive
  441. //
  442. //-----------------------------------------------------------------------//
  443. LONG
  444. CompareEnumerateKey( HKEY hLeftKey,
  445. LPCWSTR pwszLeftFullKeyName,
  446. HKEY hRightKey,
  447. LPCWSTR pwszRightFullKeyName,
  448. DWORD dwOutputType,
  449. BOOL bRecurseSubKeys,
  450. BOOL* pbHasDifference, DWORD dwDepth )
  451. {
  452. // local variables
  453. DWORD dw = 0;
  454. DWORD dwSize = 0;
  455. LONG lIndex = 0;
  456. LONG lResult = 0;
  457. DWORD dwLeftKeys = 0;
  458. DWORD dwRightKeys = 0;
  459. TARRAY arrLeftKeys = NULL;
  460. TARRAY arrRightKeys = NULL;
  461. HKEY hLeftSubKey = NULL;
  462. HKEY hRightSubKey = NULL;
  463. DWORD dwLengthOfLeftKey = 0;
  464. DWORD dwLengthOfRightKey = 0;
  465. LPWSTR pwszBuffer = NULL;
  466. LPCWSTR pwszKey = NULL;
  467. LPWSTR pwszNewLeftFullKeyName = NULL;
  468. LPWSTR pwszNewRightFullKeyName = NULL;
  469. // check the input
  470. if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL ||
  471. hRightKey == NULL || pwszRightFullKeyName == NULL || pbHasDifference == NULL )
  472. {
  473. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  474. return ERROR_INVALID_PARAMETER;
  475. }
  476. // enumerate all values under current key
  477. lResult = CompareEnumerateValueName( hLeftKey, pwszLeftFullKeyName,
  478. hRightKey, pwszRightFullKeyName, dwOutputType, pbHasDifference );
  479. if( bRecurseSubKeys == FALSE || lResult != ERROR_SUCCESS )
  480. {
  481. SaveErrorMessage( lResult );
  482. return lResult;
  483. }
  484. // optimizing the logic
  485. // if user is not interested in seeing the differences,
  486. // we will check whether the comparision done till now is same or not
  487. // if not, there is no point in proceeding -- this is because, the final output
  488. // of the tool is not going to be by continuing furthur
  489. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  490. {
  491. if ( *pbHasDifference == TRUE )
  492. {
  493. return ERROR_SUCCESS;
  494. }
  495. }
  496. // query left key info
  497. lResult = RegQueryInfoKey( hLeftKey, NULL, NULL, NULL,
  498. &dwLeftKeys, &dwLengthOfLeftKey, NULL, NULL, NULL, NULL, NULL, NULL );
  499. if( lResult != ERROR_SUCCESS )
  500. {
  501. SaveErrorMessage( lResult );
  502. return lResult;
  503. }
  504. //
  505. // SPECIAL CASE:
  506. // -------------
  507. // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
  508. // though there are subkeys underneath this -- to handle this, we are doing a workaround
  509. // by assuming the max registry key length
  510. //
  511. if ( dwLeftKeys != 0 && dwLengthOfLeftKey == 0 )
  512. {
  513. dwLengthOfLeftKey = 256;
  514. }
  515. else if ( dwLengthOfLeftKey < 256 )
  516. {
  517. // always assume 100% more length that what is returned by the API
  518. dwLengthOfLeftKey *= 2;
  519. }
  520. // query right key info
  521. lResult = RegQueryInfoKey( hRightKey, NULL, NULL, NULL,
  522. &dwRightKeys, &dwLengthOfRightKey, NULL, NULL, NULL, NULL, NULL, NULL );
  523. if( lResult != ERROR_SUCCESS )
  524. {
  525. SaveErrorMessage( lResult );
  526. return lResult;
  527. }
  528. //
  529. // SPECIAL CASE:
  530. // -------------
  531. // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
  532. // though there are subkeys underneath this -- to handle this, we are doing a workaround
  533. // by assuming the max registry key length
  534. //
  535. if ( dwRightKeys != 0 && dwLengthOfRightKey == 0 )
  536. {
  537. dwLengthOfRightKey = 256;
  538. }
  539. else if ( dwLengthOfRightKey < 256 )
  540. {
  541. // always assume 100% more length that what is returned by the API
  542. dwLengthOfRightKey *= 2;
  543. }
  544. // furthur more optimizing the logic
  545. // if user is not interested in seeing the differences,
  546. // we will check the count and length information -- if they dont match, simply return
  547. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  548. {
  549. if ( dwLeftKeys != dwRightKeys ||
  550. dwLengthOfLeftKey != dwLengthOfRightKey )
  551. {
  552. *pbHasDifference = TRUE;
  553. return ERROR_SUCCESS;
  554. }
  555. }
  556. // make the length values point to the max. of both
  557. dwLengthOfRightKey++;
  558. dwLengthOfLeftKey++;
  559. if ( dwLengthOfRightKey > dwLengthOfLeftKey )
  560. {
  561. dwLengthOfLeftKey = dwLengthOfRightKey;
  562. }
  563. else
  564. {
  565. dwLengthOfRightKey = dwLengthOfLeftKey;
  566. }
  567. //
  568. // allocate memory
  569. //
  570. // left keys array
  571. arrLeftKeys = CreateDynamicArray();
  572. if ( arrLeftKeys == NULL )
  573. {
  574. SaveErrorMessage( ERROR_OUTOFMEMORY );
  575. return ERROR_OUTOFMEMORY;
  576. }
  577. // right keys array
  578. arrRightKeys = CreateDynamicArray();
  579. if ( arrRightKeys == NULL )
  580. {
  581. DestroyDynamicArray( &arrLeftKeys );
  582. SaveErrorMessage( ERROR_OUTOFMEMORY );
  583. return ERROR_OUTOFMEMORY;
  584. }
  585. // string buffer
  586. pwszBuffer = (LPWSTR) AllocateMemory( dwLengthOfLeftKey * sizeof( WCHAR ) );
  587. if ( pwszBuffer == NULL )
  588. {
  589. DestroyDynamicArray( &arrRightKeys );
  590. DestroyDynamicArray( &arrLeftKeys );
  591. SaveErrorMessage( ERROR_OUTOFMEMORY );
  592. return ERROR_OUTOFMEMORY;
  593. }
  594. //
  595. // enumerate all of the subkeys in left key
  596. //
  597. lResult = ERROR_SUCCESS;
  598. for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; dw++ )
  599. {
  600. dwSize = dwLengthOfLeftKey;
  601. SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) );
  602. lResult = RegEnumKeyEx( hLeftKey, dw,
  603. pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
  604. // add the current value to the list of values in the array
  605. if ( lResult == ERROR_SUCCESS )
  606. {
  607. if ( DynArrayAppendString( arrLeftKeys, pwszBuffer, 0 ) == -1 )
  608. {
  609. lResult = ERROR_OUTOFMEMORY;
  610. }
  611. }
  612. }
  613. //
  614. // enumerate all of the subkeys in right key
  615. //
  616. for( dw = 0; dw < dwRightKeys && lResult == ERROR_SUCCESS; dw++ )
  617. {
  618. dwSize = dwLengthOfRightKey;
  619. SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) );
  620. lResult = RegEnumKeyEx( hRightKey, dw,
  621. pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
  622. // add the current value to the list of values in the array
  623. if ( lResult == ERROR_SUCCESS )
  624. {
  625. if ( DynArrayAppendString( arrRightKeys, pwszBuffer, 0 ) == -1 )
  626. {
  627. lResult = ERROR_OUTOFMEMORY;
  628. }
  629. }
  630. }
  631. // we no longer require this memory -- release it
  632. FreeMemory( &pwszBuffer );
  633. // allocatte new buffers for storing the new left and right full key names
  634. if ( lResult == ERROR_SUCCESS )
  635. {
  636. // determine the lengths
  637. dwLengthOfLeftKey += StringLength( pwszLeftFullKeyName, 0 ) + 5;
  638. dwLengthOfRightKey += StringLength( pwszRightFullKeyName, 0 ) +5;
  639. // now allocate buffers
  640. pwszNewLeftFullKeyName =
  641. (LPWSTR) AllocateMemory( dwLengthOfLeftKey * sizeof( WCHAR ) );
  642. if ( pwszNewLeftFullKeyName == NULL )
  643. {
  644. lResult = ERROR_OUTOFMEMORY;
  645. }
  646. else
  647. {
  648. pwszNewRightFullKeyName =
  649. (LPWSTR) AllocateMemory( dwLengthOfRightKey * sizeof( WCHAR ) );
  650. if ( pwszNewRightFullKeyName == NULL )
  651. {
  652. lResult = ERROR_OUTOFMEMORY;
  653. }
  654. }
  655. }
  656. // compare two subkey name array to find the same subkey
  657. for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; )
  658. {
  659. // get the current value from the left array
  660. pwszKey = DynArrayItemAsString( arrLeftKeys, dw );
  661. // search for this value in the right values array
  662. lIndex = DynArrayFindString( arrRightKeys, pwszKey, TRUE, 0 );
  663. if ( lIndex != -1 )
  664. {
  665. // print the key information
  666. if ( dwOutputType == OUTPUTTYPE_ALL || dwOutputType == OUTPUTTYPE_SAME )
  667. {
  668. PrintKey( pwszLeftFullKeyName, pwszKey, PRINTTYPE_SAME );
  669. }
  670. // prepare the new left subkey
  671. StringCopy( pwszNewLeftFullKeyName, pwszLeftFullKeyName, dwLengthOfLeftKey );
  672. StringConcat( pwszNewLeftFullKeyName, L"\\", dwLengthOfLeftKey );
  673. StringConcat( pwszNewLeftFullKeyName, pwszKey,dwLengthOfLeftKey );
  674. // prepare the new right subkey
  675. StringCopy( pwszNewRightFullKeyName, pwszRightFullKeyName, dwLengthOfRightKey );
  676. StringConcat( pwszNewRightFullKeyName, L"\\", dwLengthOfRightKey );
  677. StringConcat( pwszNewRightFullKeyName, pwszKey, dwLengthOfRightKey );
  678. //
  679. // open new left key
  680. lResult = RegOpenKeyEx( hLeftKey, pwszKey, 0, KEY_READ, &hLeftSubKey );
  681. if( lResult != ERROR_SUCCESS )
  682. {
  683. break;
  684. }
  685. //
  686. // open the new right key
  687. lResult = RegOpenKeyEx( hRightKey, pwszKey, 0, KEY_READ, &hRightSubKey );
  688. if( lResult != ERROR_SUCCESS )
  689. {
  690. break;
  691. }
  692. // recursive to compare subkeys
  693. lResult = CompareEnumerateKey(
  694. hLeftSubKey, pwszNewLeftFullKeyName,
  695. hRightSubKey, pwszNewRightFullKeyName,
  696. dwOutputType, bRecurseSubKeys, pbHasDifference, dwDepth + 1 );
  697. // release the keys
  698. SafeCloseKey( &hLeftSubKey );
  699. SafeCloseKey( &hRightSubKey );
  700. if ( lResult == ERROR_SUCCESS )
  701. {
  702. // comparision is done -- remove the current keys from
  703. // left and right values array
  704. DynArrayRemove( arrLeftKeys, dw );
  705. DynArrayRemove( arrRightKeys, lIndex );
  706. // update the count variables accordingly
  707. dwLeftKeys--;
  708. dwRightKeys--;
  709. }
  710. // check if the differences were found or not
  711. if( *pbHasDifference == TRUE )
  712. {
  713. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  714. {
  715. dw = 0;
  716. dwLeftKeys = 0;
  717. dwRightKeys = 0;
  718. break;
  719. }
  720. }
  721. }
  722. // update the iteration variable
  723. if ( lIndex == -1 )
  724. {
  725. dw++;
  726. }
  727. }
  728. // Output subkey name in left key
  729. for( dw = 0; dw < dwLeftKeys && lResult == ERROR_SUCCESS; dw++ )
  730. {
  731. // get the current value from the left array
  732. pwszKey = DynArrayItemAsString( arrLeftKeys, dw );
  733. if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL )
  734. {
  735. PrintKey( pwszLeftFullKeyName, pwszKey, PRINTTYPE_LEFT );
  736. }
  737. // ...
  738. *pbHasDifference = TRUE;
  739. }
  740. // Output subkey name in right key
  741. for( dw = 0; dw < dwRightKeys && lResult == ERROR_SUCCESS; dw++ )
  742. {
  743. // get the current value from the left array
  744. pwszKey = DynArrayItemAsString( arrRightKeys, dw );
  745. if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL )
  746. {
  747. PrintKey( pwszRightFullKeyName, pwszKey, PRINTTYPE_RIGHT );
  748. }
  749. // ...
  750. *pbHasDifference = TRUE;
  751. }
  752. // release the memory allocated
  753. FreeMemory( &pwszBuffer );
  754. SafeCloseKey( &hLeftSubKey );
  755. SafeCloseKey( &hRightSubKey );
  756. FreeMemory( &pwszNewLeftFullKeyName );
  757. FreeMemory( &pwszNewRightFullKeyName );
  758. DestroyDynamicArray( &arrLeftKeys );
  759. DestroyDynamicArray( &arrRightKeys );
  760. // return
  761. SaveErrorMessage( lResult );
  762. return lResult;
  763. }
  764. LONG
  765. CompareEnumerateValueName( HKEY hLeftKey,
  766. LPCWSTR pwszLeftFullKeyName,
  767. HKEY hRightKey,
  768. LPCWSTR pwszRightFullKeyName,
  769. DWORD dwOutputType, BOOL* pbHasDifference )
  770. {
  771. // local variables
  772. DWORD dw = 0;
  773. LONG lIndex = 0;
  774. LONG lResult = 0;
  775. DWORD dwSize = 0;
  776. DWORD dwLeftValues = 0;
  777. DWORD dwRightValues = 0;
  778. DWORD dwLengthOfLeftValue = 0;
  779. DWORD dwLengthOfRightValue = 0;
  780. TARRAY arrLeftValues = NULL;
  781. TARRAY arrRightValues = NULL;
  782. LPWSTR pwszBuffer = NULL;
  783. LPCWSTR pwszValue = NULL;
  784. // check the input
  785. if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL ||
  786. hRightKey == NULL || pwszRightFullKeyName == NULL || pbHasDifference == NULL )
  787. {
  788. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  789. return ERROR_INVALID_PARAMETER;
  790. }
  791. // optimizing the logic
  792. // if user is not interested in seeing the differences,
  793. // we will check whether the comparision done till now is same or not
  794. // if not, there is no point in proceeding -- this is because, the final output
  795. // of the tool is not going to be by continuing furthur
  796. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  797. {
  798. if ( *pbHasDifference == TRUE )
  799. {
  800. return ERROR_SUCCESS;
  801. }
  802. }
  803. // query left key info
  804. lResult = RegQueryInfoKey(
  805. hLeftKey, NULL, NULL, NULL, NULL, NULL, NULL,
  806. &dwLeftValues, &dwLengthOfLeftValue, NULL, NULL, NULL);
  807. if( lResult != ERROR_SUCCESS )
  808. {
  809. SaveErrorMessage( lResult );
  810. return lResult;
  811. }
  812. // query right key info
  813. lResult = RegQueryInfoKey(
  814. hRightKey, NULL, NULL, NULL, NULL, NULL, NULL,
  815. &dwRightValues, &dwLengthOfRightValue, NULL, NULL, NULL);
  816. if( lResult != ERROR_SUCCESS )
  817. {
  818. SaveErrorMessage( lResult );
  819. return lResult;
  820. }
  821. // furthur more optimizing the logic
  822. // if user is not interested in seeing the differences,
  823. // we will check the count and length information -- if they dont match, simply return
  824. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  825. {
  826. if ( dwLeftValues != dwRightValues ||
  827. dwLengthOfLeftValue != dwLengthOfRightValue )
  828. {
  829. *pbHasDifference = TRUE;
  830. return ERROR_SUCCESS;
  831. }
  832. }
  833. // make the length values point to the max. of both
  834. dwLengthOfRightValue++;
  835. dwLengthOfLeftValue++;
  836. if ( dwLengthOfRightValue > dwLengthOfLeftValue )
  837. {
  838. dwLengthOfLeftValue = dwLengthOfRightValue;
  839. }
  840. else
  841. {
  842. dwLengthOfRightValue = dwLengthOfLeftValue;
  843. }
  844. //
  845. // allocate bufferes
  846. //
  847. // left values array
  848. arrLeftValues = CreateDynamicArray();
  849. if ( arrLeftValues == NULL )
  850. {
  851. SaveErrorMessage( ERROR_OUTOFMEMORY );
  852. return ERROR_OUTOFMEMORY;
  853. }
  854. // right values array
  855. arrRightValues = CreateDynamicArray();
  856. if ( arrRightValues == NULL )
  857. {
  858. DestroyDynamicArray( &arrLeftValues );
  859. SaveErrorMessage( ERROR_OUTOFMEMORY );
  860. return ERROR_OUTOFMEMORY;
  861. }
  862. // string buffer
  863. pwszBuffer = (LPWSTR) AllocateMemory( dwLengthOfLeftValue * sizeof( WCHAR ) );
  864. if ( pwszBuffer == NULL )
  865. {
  866. DestroyDynamicArray( &arrRightValues );
  867. DestroyDynamicArray( &arrLeftValues );
  868. SaveErrorMessage( ERROR_OUTOFMEMORY );
  869. return ERROR_OUTOFMEMORY;
  870. }
  871. //
  872. // enumerate all of the values in left key
  873. //
  874. lResult = ERROR_SUCCESS;
  875. for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; dw++ )
  876. {
  877. dwSize = dwLengthOfLeftValue;
  878. SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) );
  879. lResult = RegEnumValue( hLeftKey, dw,
  880. pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
  881. // add the current value to the list of values in the array
  882. if ( lResult == ERROR_SUCCESS )
  883. {
  884. if ( DynArrayAppendString( arrLeftValues, pwszBuffer, 0 ) == -1 )
  885. {
  886. lResult = ERROR_OUTOFMEMORY;
  887. }
  888. }
  889. }
  890. //
  891. // enumerate all of the values in right key
  892. //
  893. for( dw = 0; dw < dwRightValues && lResult == ERROR_SUCCESS; dw++ )
  894. {
  895. dwSize = dwLengthOfRightValue;
  896. SecureZeroMemory( pwszBuffer, dwSize * sizeof( WCHAR ) );
  897. lResult = RegEnumValue( hRightKey, dw,
  898. pwszBuffer, &dwSize, NULL, NULL, NULL, NULL );
  899. // add the current value to the list of values in the array
  900. if ( lResult == ERROR_SUCCESS )
  901. {
  902. if ( DynArrayAppendString( arrRightValues, pwszBuffer, 0 ) == -1 )
  903. {
  904. lResult = ERROR_OUTOFMEMORY;
  905. }
  906. }
  907. }
  908. // we no longer require this memory -- release it
  909. FreeMemory( &pwszBuffer );
  910. // compare two valuename array to find the same valuename
  911. for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; )
  912. {
  913. // get the current value from the left array
  914. pwszValue = DynArrayItemAsString( arrLeftValues, dw );
  915. // search for this value in the right values array
  916. lIndex = DynArrayFindString( arrRightValues, pwszValue, TRUE, 0 );
  917. if ( lIndex != -1 )
  918. {
  919. lResult = CompareValues( hLeftKey, pwszLeftFullKeyName,
  920. hRightKey, pwszRightFullKeyName, pwszValue, dwOutputType, pbHasDifference );
  921. if ( lResult == ERROR_SUCCESS )
  922. {
  923. // comparision is done -- remove the current keys from
  924. // left and right values array
  925. DynArrayRemove( arrLeftValues, dw );
  926. DynArrayRemove( arrRightValues, lIndex );
  927. // update the count variables accordingly
  928. dwLeftValues--;
  929. dwRightValues--;
  930. }
  931. }
  932. // update the iteration variable
  933. if ( lIndex == -1 )
  934. {
  935. dw++;
  936. }
  937. }
  938. // Output different valuename in left key
  939. for( dw = 0; dw < dwLeftValues && lResult == ERROR_SUCCESS; dw++ )
  940. {
  941. // get the current value from the left array
  942. pwszValue = DynArrayItemAsString( arrLeftValues, dw );
  943. if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL )
  944. {
  945. lResult = OutputValue( hLeftKey,
  946. pwszLeftFullKeyName, pwszValue, PRINTTYPE_LEFT );
  947. }
  948. // ...
  949. *pbHasDifference = TRUE;
  950. }
  951. // Output different valuename in left key
  952. for( dw = 0; dw < dwRightValues && lResult == ERROR_SUCCESS; dw++ )
  953. {
  954. // get the current value from the left array
  955. pwszValue = DynArrayItemAsString( arrRightValues, dw );
  956. if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL )
  957. {
  958. lResult = OutputValue( hRightKey,
  959. pwszRightFullKeyName, pwszValue, PRINTTYPE_RIGHT );
  960. }
  961. // ...
  962. *pbHasDifference = TRUE;
  963. }
  964. // release the memory allocated
  965. DestroyDynamicArray( &arrLeftValues );
  966. DestroyDynamicArray( &arrRightValues );
  967. // return
  968. SaveErrorMessage( lResult );
  969. return lResult;
  970. }
  971. //-----------------------------------------------------------------------//
  972. //
  973. // CompareValues()
  974. //
  975. //-----------------------------------------------------------------------//
  976. LONG
  977. CompareValues( HKEY hLeftKey,
  978. LPCWSTR pwszLeftFullKeyName,
  979. HKEY hRightKey,
  980. LPCWSTR pwszRightFullKeyName,
  981. LPCWSTR pwszValueName,
  982. DWORD dwOutputType, BOOL* pbHasDifference )
  983. {
  984. // local variables
  985. LONG lResult = 0;
  986. DWORD dwTypeLeft = 0;
  987. DWORD dwTypeRight = 0;
  988. DWORD dwSizeLeft = 0;
  989. DWORD dwSizeRight = 0;
  990. BYTE* pLeftData = NULL;
  991. BYTE* pRightData = NULL;
  992. // check the input
  993. if ( hLeftKey == NULL || pwszLeftFullKeyName == NULL ||
  994. hRightKey == NULL || pwszRightFullKeyName == NULL ||
  995. pwszValueName == NULL || pbHasDifference == NULL )
  996. {
  997. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  998. return ERROR_INVALID_PARAMETER;
  999. }
  1000. // optimizing the logic
  1001. // if user is not interested in seeing the differences,
  1002. // we will check whether the comparision done till now is same or not
  1003. // if not, there is no point in proceeding -- this is because, the final output
  1004. // of the tool is not going to be by continuing furthur
  1005. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  1006. {
  1007. if ( *pbHasDifference == TRUE )
  1008. {
  1009. return ERROR_SUCCESS;
  1010. }
  1011. }
  1012. //
  1013. // First find out how much memory to allocate
  1014. //
  1015. lResult = RegQueryValueEx( hLeftKey, pwszValueName, 0, &dwTypeLeft, NULL, &dwSizeLeft );
  1016. if( lResult != ERROR_SUCCESS )
  1017. {
  1018. SaveErrorMessage( lResult );
  1019. return lResult;
  1020. }
  1021. lResult = RegQueryValueEx( hRightKey, pwszValueName, 0, &dwTypeRight, NULL, &dwSizeRight );
  1022. if( lResult != ERROR_SUCCESS )
  1023. {
  1024. SaveErrorMessage( lResult );
  1025. return lResult;
  1026. }
  1027. // furthur more optimizing the logic
  1028. // if user is not interested in seeing the differences,
  1029. // we will check the type and size information -- if they dont match, simply return
  1030. if ( dwOutputType == 0 || dwOutputType == OUTPUTTYPE_NONE )
  1031. {
  1032. if ( dwTypeLeft != dwTypeRight || dwSizeLeft != dwSizeRight )
  1033. {
  1034. *pbHasDifference = TRUE;
  1035. return ERROR_SUCCESS;
  1036. }
  1037. }
  1038. // allocate memory for left data
  1039. // NOTE: always align the data on WCHAR boundary
  1040. dwSizeLeft = ALIGN_UP( dwSizeLeft, WCHAR );
  1041. pLeftData = (BYTE*) AllocateMemory( (dwSizeLeft + 2) * sizeof( BYTE ) );
  1042. if( pLeftData == NULL )
  1043. {
  1044. SaveErrorMessage( ERROR_OUTOFMEMORY );
  1045. return ERROR_OUTOFMEMORY;
  1046. }
  1047. // allocate memory for right data
  1048. // NOTE: always align the data on WCHAR boundary
  1049. dwSizeRight = ALIGN_UP( dwSizeRight, WCHAR );
  1050. pRightData = (BYTE*) AllocateMemory( (dwSizeRight + 2) * sizeof( BYTE ) );
  1051. if( pRightData == NULL )
  1052. {
  1053. FreeMemory( &pLeftData );
  1054. SaveErrorMessage( ERROR_OUTOFMEMORY );
  1055. return ERROR_OUTOFMEMORY;
  1056. }
  1057. //
  1058. // Now get the data
  1059. //
  1060. lResult = RegQueryValueEx( hLeftKey,
  1061. pwszValueName, 0, &dwTypeLeft, pLeftData, &dwSizeLeft );
  1062. if( lResult == ERROR_SUCCESS )
  1063. {
  1064. lResult = RegQueryValueEx( hRightKey,
  1065. pwszValueName, 0, &dwTypeRight, pRightData, &dwSizeRight );
  1066. }
  1067. if( lResult != ERROR_SUCCESS )
  1068. {
  1069. FreeMemory( &pLeftData );
  1070. FreeMemory( &pRightData );
  1071. SaveErrorMessage( lResult );
  1072. return lResult;
  1073. }
  1074. if( dwTypeLeft != dwTypeRight || dwSizeLeft != dwSizeRight ||
  1075. CompareByteData( pLeftData, pRightData, dwSizeLeft ) == TRUE )
  1076. {
  1077. if( dwOutputType == OUTPUTTYPE_DIFF || dwOutputType == OUTPUTTYPE_ALL )
  1078. {
  1079. // print left and right
  1080. PrintValue( pwszLeftFullKeyName, pwszValueName,
  1081. dwTypeLeft, pLeftData, dwSizeLeft, PRINTTYPE_LEFT );
  1082. PrintValue( pwszRightFullKeyName, pwszValueName,
  1083. dwTypeRight, pRightData, dwSizeRight, PRINTTYPE_RIGHT );
  1084. }
  1085. // ...
  1086. *pbHasDifference = TRUE;
  1087. }
  1088. else // they are the same
  1089. {
  1090. if( dwOutputType == OUTPUTTYPE_SAME || dwOutputType == OUTPUTTYPE_ALL )
  1091. {
  1092. PrintValue( pwszLeftFullKeyName, pwszValueName,
  1093. dwTypeLeft, pLeftData, dwSizeLeft, PRINTTYPE_SAME );
  1094. }
  1095. }
  1096. // release memory allocate and return
  1097. FreeMemory( &pLeftData );
  1098. FreeMemory( &pRightData );
  1099. SaveErrorMessage( lResult );
  1100. return lResult;
  1101. }
  1102. BOOL
  1103. PrintKey( LPCWSTR pwszFullKeyName, LPCWSTR pwszSubKeyName, DWORD dwPrintType )
  1104. {
  1105. // check the input
  1106. if ( pwszFullKeyName == NULL || pwszSubKeyName == NULL )
  1107. {
  1108. SetLastError( ERROR_INVALID_PARAMETER );
  1109. return FALSE;
  1110. }
  1111. // print type
  1112. if( dwPrintType == PRINTTYPE_LEFT )
  1113. {
  1114. ShowMessage( stdout, L"< " );
  1115. }
  1116. else if( dwPrintType == PRINTTYPE_RIGHT )
  1117. {
  1118. ShowMessage( stdout, L"> " );
  1119. }
  1120. else if( dwPrintType == PRINTTYPE_SAME )
  1121. {
  1122. ShowMessage( stdout, L"= " );
  1123. }
  1124. // show the key
  1125. ShowMessageEx( stdout, 1, TRUE,
  1126. GetResString2( IDS_KEY_COMPARE, 0 ), pwszFullKeyName, pwszSubKeyName );
  1127. // ...
  1128. ShowMessage( stdout, L"\n" );
  1129. return TRUE;
  1130. }
  1131. LONG
  1132. OutputValue( HKEY hKey,
  1133. LPCWSTR pwszFullKeyName,
  1134. LPCWSTR pwszValueName,
  1135. DWORD dwPrintType )
  1136. {
  1137. // local variables
  1138. LONG lResult = ERROR_SUCCESS;
  1139. DWORD dwType = 0;
  1140. DWORD dwSize = 0;
  1141. BYTE* pByteData = NULL;
  1142. //
  1143. // First find out how much memory to allocate
  1144. //
  1145. lResult = RegQueryValueEx( hKey, pwszValueName, 0, &dwType, NULL, &dwSize );
  1146. if( lResult != ERROR_SUCCESS )
  1147. {
  1148. return lResult;
  1149. }
  1150. // allocate memory
  1151. // NOTE: always align the buffer on the WCHAR border
  1152. dwSize = ALIGN_UP( dwSize, WCHAR );
  1153. pByteData = (BYTE*) AllocateMemory( (dwSize + 2) * sizeof( BYTE ) );
  1154. if( pByteData == NULL )
  1155. {
  1156. return ERROR_NOT_ENOUGH_MEMORY;
  1157. }
  1158. //
  1159. // Now get the data
  1160. //
  1161. lResult = RegQueryValueEx( hKey,
  1162. pwszValueName, 0, &dwType, (LPBYTE) pByteData, &dwSize );
  1163. if( lResult == ERROR_SUCCESS )
  1164. {
  1165. PrintValue( pwszFullKeyName,
  1166. pwszValueName, dwType, pByteData, dwSize, dwPrintType);
  1167. }
  1168. // release memory
  1169. FreeMemory( &pByteData );
  1170. // return
  1171. return lResult;
  1172. }
  1173. BOOL
  1174. PrintValue( LPCWSTR pwszFullKeyName,
  1175. LPCWSTR pwszValueName,
  1176. DWORD dwType, BYTE* pData,
  1177. DWORD dwSize, DWORD dwPrintType )
  1178. {
  1179. // local variables
  1180. TREG_SHOW_INFO showinfo;
  1181. // check the input
  1182. if ( pwszFullKeyName == NULL || pwszValueName == NULL || pData == NULL )
  1183. {
  1184. SetLastError( ERROR_INVALID_PARAMETER );
  1185. return FALSE;
  1186. }
  1187. // print type
  1188. if( dwPrintType == PRINTTYPE_LEFT )
  1189. {
  1190. ShowMessage( stdout, L"< " );
  1191. }
  1192. else if( dwPrintType == PRINTTYPE_RIGHT )
  1193. {
  1194. ShowMessage( stdout, L"> " );
  1195. }
  1196. else if( dwPrintType == PRINTTYPE_SAME )
  1197. {
  1198. ShowMessage( stdout, L"= " );
  1199. }
  1200. // first Print Key
  1201. ShowMessageEx( stdout, 1, TRUE,
  1202. GetResString2( IDS_VALUE_COMPARE, 0 ), pwszFullKeyName );
  1203. // init to ZERO
  1204. SecureZeroMemory( &showinfo, sizeof( TREG_SHOW_INFO ) );
  1205. // set the data
  1206. showinfo.pwszValueName = pwszValueName;
  1207. showinfo.dwType = dwType;
  1208. showinfo.pByteData = pData;
  1209. showinfo.pwszSeparator = NULL;
  1210. showinfo.dwMaxValueNameLength = 0;
  1211. showinfo.dwPadLength = 2;
  1212. showinfo.dwSize = dwSize;
  1213. showinfo.pwszMultiSzSeparator = NULL;
  1214. // show the value and return
  1215. return ShowRegistryValue( &showinfo );
  1216. }
  1217. BOOL
  1218. CompareByteData( BYTE* pLeftData, BYTE* pRightData, DWORD dwSize )
  1219. {
  1220. // local variables
  1221. DWORD dw = 0;
  1222. BOOL bDifferent = FALSE;
  1223. // check the input
  1224. if ( pLeftData == NULL || pRightData == NULL )
  1225. {
  1226. SetLastError( ERROR_INVALID_PARAMETER );
  1227. return FALSE;
  1228. }
  1229. bDifferent = FALSE;
  1230. for( dw = 0; dw < dwSize; dw++ )
  1231. {
  1232. if( pLeftData[ dw ] != pRightData[ dw ] )
  1233. {
  1234. bDifferent = TRUE;
  1235. break;
  1236. }
  1237. }
  1238. return bDifferent;
  1239. }