Source code of Windows XP (NT5)
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.

840 lines
21 KiB

  1. //*************************************************************
  2. //
  3. // Personal Classes Profile management routines
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1995
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "uenv.h"
  11. #include "windows.h"
  12. // Local Data Structures
  13. LPTSTR SpecialSubtrees[] =
  14. {
  15. TEXT("CLSID"),
  16. TEXT("Interface"),
  17. TEXT("TypeLib"),
  18. TEXT("Licenses"),
  19. TEXT("FileType")
  20. };
  21. #define MAX_SPECIAL_SUBTREE (sizeof(SpecialSubtrees)/sizeof(LPTSTR))
  22. //
  23. // Local function proto-types
  24. //
  25. typedef struct _RegKeyInfo {
  26. DWORD SubKeyCount;
  27. DWORD MaxSubKeyLen;
  28. DWORD ValueCount;
  29. DWORD MaxValueNameLen;
  30. DWORD MaxValueLen;
  31. DWORD SDLen;
  32. LPTSTR pSubKeyName;
  33. LPTSTR pValueName;
  34. LPTSTR pValue;
  35. } REGKEYINFO, *PREGKEYINFO;
  36. //*************************************************************
  37. //
  38. // PrepForEnumRegistryTree()
  39. //
  40. // Purpose: prepare to duplicate a source bunch of keys into the destination.
  41. //
  42. // Parameters: hkSourceTree - source registry tree
  43. // pRegKeyInfo - info block for use doing enumeration
  44. //
  45. // Return: TRUE if successful
  46. // FALSE if an error occurs
  47. //
  48. // History: Date Author Comment
  49. // 1/30/96 GregJen Created
  50. //
  51. //*************************************************************
  52. BOOL
  53. PrepForEnumRegistryTree(
  54. HKEY hkSourceTree,
  55. PREGKEYINFO pRegKeyInfo
  56. )
  57. {
  58. LPTSTR pStringsBuffer;
  59. LONG result;
  60. result = RegQueryInfoKey(hkSourceTree,
  61. NULL,
  62. NULL,
  63. 0,
  64. &pRegKeyInfo->SubKeyCount,
  65. &pRegKeyInfo->MaxSubKeyLen,
  66. NULL,
  67. &pRegKeyInfo->ValueCount,
  68. &pRegKeyInfo->MaxValueNameLen,
  69. &pRegKeyInfo->MaxValueLen,
  70. &pRegKeyInfo->SDLen,
  71. NULL);
  72. if ( result != ERROR_SUCCESS )
  73. return FALSE;
  74. // allocate a block of memory to use for enumerating subkeys and values
  75. pStringsBuffer = (LPTSTR) LocalAlloc( LPTR,
  76. (pRegKeyInfo->MaxSubKeyLen +
  77. pRegKeyInfo->MaxValueNameLen +
  78. pRegKeyInfo->MaxValueLen + 3)
  79. * sizeof( TCHAR ) );
  80. if ( !pStringsBuffer )
  81. return FALSE;
  82. pRegKeyInfo->pSubKeyName = pStringsBuffer;
  83. pRegKeyInfo->pValueName = pStringsBuffer + pRegKeyInfo->MaxSubKeyLen + 1;
  84. pRegKeyInfo->pValue = pRegKeyInfo->pValueName +
  85. pRegKeyInfo->MaxValueNameLen + 1;
  86. return TRUE;
  87. }
  88. //*************************************************************
  89. //
  90. // CleanupAfterEnumRegistryTree()
  91. //
  92. // Purpose: duplicate a source bunch of keys into the destination.
  93. //
  94. // Parameters: hkSourceTree - source registry tree
  95. // pRegKeyInfo - info block for use doing enumeration
  96. //
  97. // Return: TRUE if successful
  98. // FALSE if an error occurs
  99. //
  100. // History: Date Author Comment
  101. // 1/30/96 GregJen Created
  102. //
  103. //*************************************************************
  104. void
  105. CleanupAfterEnumRegistryTree(
  106. HKEY hkSourceTree,
  107. PREGKEYINFO pRegKeyInfo)
  108. {
  109. LocalFree( pRegKeyInfo->pSubKeyName );
  110. }
  111. BOOL
  112. DeleteRegistrySubtree (
  113. HKEY hkTree )
  114. {
  115. HKEY hkCurrentSourceKey;
  116. DWORD idx;
  117. DWORD NameLen;
  118. LONG result = ERROR_SUCCESS;
  119. REGKEYINFO RegKeyInfo;
  120. BOOL Success = FALSE;
  121. if ( !PrepForEnumRegistryTree( hkTree, &RegKeyInfo ) )
  122. return FALSE; // nothing to clean up here yet
  123. // enumerate all the source subkeys
  124. // for each: if dest subkey is older than source, delete it
  125. // if dest subkey does not exist (or was deleted) clone the subkey
  126. //
  127. // Clone all the subkeys
  128. //
  129. for ( idx = 0;
  130. (result == ERROR_SUCCESS) &&
  131. ( result != ERROR_MORE_DATA ) &&
  132. ( idx < RegKeyInfo.SubKeyCount );
  133. idx++ ) {
  134. NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
  135. result = RegEnumKeyEx( hkTree,
  136. idx,
  137. RegKeyInfo.pSubKeyName,
  138. &NameLen,
  139. NULL,
  140. NULL,
  141. NULL,
  142. NULL );
  143. if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
  144. goto cleanup;
  145. // TBD: open the subkey in the source tree AS CurrentSourceKey
  146. result = RegOpenKeyEx(hkTree,
  147. RegKeyInfo.pSubKeyName,
  148. 0,
  149. KEY_ALL_ACCESS,
  150. &hkCurrentSourceKey);
  151. DeleteRegistrySubtree( hkCurrentSourceKey );
  152. RegCloseKey( hkCurrentSourceKey );
  153. RegDeleteKey( hkTree, RegKeyInfo.pSubKeyName );
  154. result = ERROR_SUCCESS;
  155. }
  156. cleanup:
  157. CleanupAfterEnumRegistryTree( hkTree, &RegKeyInfo );
  158. return TRUE;
  159. }
  160. //*************************************************************
  161. //
  162. // CloneRegistryValues()
  163. //
  164. // Purpose: copy the values from under the source key to the dest key
  165. //
  166. // Parameters: SourceTree - source registry tree
  167. // DestinationTree - destintation registry tree
  168. // RegKeyInfo - handy information from the RegEnumKeyEx call.
  169. //
  170. // Return: TRUE if successful
  171. // FALSE if an error occurs
  172. //
  173. // History: Date Author Comment
  174. // 1/14/96 GregJen Created
  175. //
  176. //*************************************************************
  177. BOOL
  178. CloneRegistryValues(
  179. HKEY hkSourceTree,
  180. HKEY hkDestinationTree,
  181. REGKEYINFO RegKeyInfo )
  182. {
  183. LONG result = ERROR_SUCCESS;
  184. DWORD idx;
  185. DWORD ValueLen;
  186. DWORD ValueType;
  187. DWORD DataLen;
  188. for ( idx = 0;
  189. (result == ERROR_SUCCESS) &&
  190. ( result != ERROR_MORE_DATA ) &&
  191. ( idx < RegKeyInfo.ValueCount );
  192. idx++ )
  193. {
  194. DataLen = RegKeyInfo.MaxValueLen + sizeof( TCHAR );
  195. ValueLen = RegKeyInfo.MaxValueNameLen + sizeof( TCHAR );
  196. result = RegEnumValue( hkSourceTree,
  197. idx,
  198. RegKeyInfo.pValueName,
  199. &ValueLen,
  200. NULL,
  201. &ValueType,
  202. (BYTE*) RegKeyInfo.pValue,
  203. &DataLen);
  204. // TBD: check errors
  205. // now add the value to the destination key
  206. result = RegSetValueEx( hkDestinationTree,
  207. RegKeyInfo.pValueName,
  208. 0,
  209. ValueType,
  210. (BYTE*) RegKeyInfo.pValue,
  211. DataLen );
  212. // TBD: check errors
  213. }
  214. return TRUE;
  215. }
  216. //*************************************************************
  217. //
  218. // CloneRegistryTree()
  219. //
  220. // Purpose: duplicate a source bunch of keys into the destination.
  221. //
  222. // Parameters: SourceTree - source registry tree
  223. // DestinationTree - destintation registry tree
  224. // lpSubKeyName - if present this is a subkey name that
  225. // corresponds to the SourceTree HKEY.
  226. //
  227. // Return: TRUE if successful
  228. // FALSE if an error occurs
  229. //
  230. // History: Date Author Comment
  231. // 1/14/96 GregJen Created
  232. //
  233. //*************************************************************
  234. BOOL
  235. CloneRegistryTree(
  236. HKEY hkSourceTree,
  237. HKEY hkDestinationTree,
  238. LPTSTR lpDestTreeName )
  239. {
  240. HKEY hkCurrentSourceKey;
  241. DWORD idx;
  242. DWORD NameLen;
  243. LONG result = ERROR_SUCCESS;
  244. REGKEYINFO RegKeyInfo;
  245. BOOL Success = FALSE;
  246. if ( !PrepForEnumRegistryTree( hkSourceTree, &RegKeyInfo ) )
  247. return FALSE; // nothing to clean up here yet
  248. if ( lpDestTreeName ) {
  249. HKEY hkNewKey = NULL;
  250. DWORD dwSDLen = RegKeyInfo.SDLen;
  251. DWORD dwDisp;
  252. SECURITY_INFORMATION SI = DACL_SECURITY_INFORMATION; // for now...
  253. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)
  254. LocalAlloc( LPTR, dwSDLen );
  255. // TBD: check for NULL;
  256. // Get the registry security information from the old key
  257. result = RegGetKeySecurity( hkSourceTree,
  258. SI,
  259. pSD,
  260. &dwSDLen);
  261. // TBD: check for errors, free pSD
  262. // create a key with the given name, and registry info
  263. result = RegCreateKeyEx( hkDestinationTree,
  264. lpDestTreeName,
  265. 0,
  266. NULL,
  267. REG_OPTION_NON_VOLATILE,
  268. KEY_ALL_ACCESS,
  269. pSD,
  270. &hkNewKey,
  271. &dwDisp );
  272. // TBD: check for errors, free pSD
  273. // TBD: and update the hkDestinationTree variable to point to it
  274. hkDestinationTree = hkNewKey;
  275. LocalFree( pSD );
  276. if (ERROR_SUCCESS != result)
  277. {
  278. goto cleanup;
  279. }
  280. }
  281. //
  282. // clone the values
  283. //
  284. if ( ! CloneRegistryValues( hkSourceTree, hkDestinationTree, RegKeyInfo ) )
  285. goto cleanup;
  286. //
  287. // Clone all the subkeys
  288. //
  289. for ( idx = 0;
  290. (result == ERROR_SUCCESS) &&
  291. ( result != ERROR_MORE_DATA ) &&
  292. ( idx < RegKeyInfo.SubKeyCount );
  293. idx++ ) {
  294. NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
  295. result = RegEnumKeyEx( hkSourceTree,
  296. idx,
  297. RegKeyInfo.pSubKeyName,
  298. &NameLen,
  299. NULL,
  300. NULL,
  301. NULL,
  302. NULL );
  303. if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
  304. goto cleanup;
  305. // TBD: open the subkey in the source tree AS CurrentSourceKey
  306. result = RegOpenKeyEx(hkSourceTree,
  307. RegKeyInfo.pSubKeyName,
  308. 0,
  309. KEY_READ,
  310. &hkCurrentSourceKey);
  311. //
  312. // recurse passing the subkey name
  313. //
  314. CloneRegistryTree( hkCurrentSourceKey,
  315. hkDestinationTree,
  316. RegKeyInfo.pSubKeyName );
  317. //
  318. // close our open key
  319. //
  320. RegCloseKey( hkCurrentSourceKey );
  321. }
  322. Success = TRUE;
  323. cleanup:
  324. if ( lpDestTreeName )
  325. {
  326. RegCloseKey( hkDestinationTree );
  327. }
  328. CleanupAfterEnumRegistryTree( hkSourceTree, &RegKeyInfo );
  329. return Success;
  330. }
  331. void SaveChangesToUser( )
  332. {
  333. }
  334. void SaveChangesToCommon( )
  335. {
  336. }
  337. BOOL
  338. AddSharedValuesToSubkeys( HKEY hkShared, LPTSTR pszSubtree )
  339. {
  340. HKEY hkSourceKey;
  341. HKEY hkCurrentSourceKey;
  342. DWORD idx;
  343. DWORD NameLen;
  344. LONG result = ERROR_SUCCESS;
  345. REGKEYINFO RegKeyInfo;
  346. BOOL Success = FALSE;
  347. // for every subkey, set "Shared" value
  348. result = RegOpenKeyEx( hkShared,
  349. pszSubtree,
  350. 0,
  351. KEY_READ,
  352. &hkSourceKey );
  353. // TBD: if no subtree in source, skip ahead to next special subtree
  354. if ( result == ERROR_FILE_NOT_FOUND )
  355. return TRUE;
  356. // If any other errors occurred, return FALSE
  357. if ( result != ERROR_SUCCESS)
  358. return FALSE;
  359. if ( !PrepForEnumRegistryTree( hkSourceKey, &RegKeyInfo ) )
  360. goto cleanup2;
  361. // enumerate all the source subkeys
  362. // for each: if dest subkey is older than source, delete it
  363. // if dest subkey does not exist (or was deleted) clone the subkey
  364. //
  365. // Clone all the subkeys
  366. //
  367. for ( idx = 0;
  368. (result == ERROR_SUCCESS) &&
  369. ( result != ERROR_MORE_DATA ) &&
  370. ( idx < RegKeyInfo.SubKeyCount );
  371. idx++ )
  372. {
  373. NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
  374. result = RegEnumKeyEx( hkSourceKey,
  375. idx,
  376. RegKeyInfo.pSubKeyName,
  377. &NameLen,
  378. NULL,
  379. NULL,
  380. NULL,
  381. NULL );
  382. if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
  383. goto cleanup;
  384. result = RegOpenKeyEx( hkSourceKey,
  385. RegKeyInfo.pSubKeyName,
  386. 0,
  387. KEY_ALL_ACCESS,
  388. &hkCurrentSourceKey );
  389. // Bug 45994
  390. if (result != ERROR_SUCCESS )
  391. goto cleanup;
  392. result = RegSetValueEx( hkCurrentSourceKey,
  393. L"Shared",
  394. 0,
  395. REG_SZ,
  396. (LPBYTE) L"Y",
  397. sizeof( L"Y" ) );
  398. RegCloseKey( hkCurrentSourceKey );
  399. }
  400. Success = TRUE;
  401. cleanup:
  402. CleanupAfterEnumRegistryTree( hkSourceKey, &RegKeyInfo );
  403. cleanup2:
  404. RegCloseKey( hkSourceKey );
  405. return Success;
  406. }
  407. BOOL
  408. AddSharedValues( HKEY hkShared )
  409. {
  410. // for each of the special subtrees, add "Shared" values
  411. int idx;
  412. // now, for each of the special top-level keys, process the level below them
  413. // these keys are: CLSID, Interface, TypeLib, Licenses, FileType
  414. for ( idx = 0; idx < MAX_SPECIAL_SUBTREE; idx++ )
  415. {
  416. AddSharedValuesToSubkeys( hkShared, SpecialSubtrees[idx] );
  417. }
  418. // now do all the top level keys (file extensions and progids)
  419. AddSharedValuesToSubkeys( hkShared, NULL );
  420. return TRUE;
  421. }
  422. //*************************************************************
  423. //
  424. // MergeUserClasses()
  425. //
  426. // Purpose: Merges the user's class information with the
  427. // common class information.
  428. //
  429. // Parameters: UserClassStore - Per-user class information
  430. // CommonClassStore - Machine-wide class information
  431. // MergedClassStore - Destination for merged information.
  432. //
  433. // Return: TRUE if successful
  434. // FALSE if an error occurs
  435. //
  436. // Comments: UserClassStore may be a null HKEY, implying
  437. // just copy the information from the common
  438. // portion into the merged portion
  439. //
  440. // History: Date Author Comment
  441. // 1/14/96 GregJen Created
  442. //
  443. //*************************************************************
  444. BOOL
  445. MergeRegistrySubKeys (
  446. HKEY hkSourceTree,
  447. HKEY hkDestTree )
  448. {
  449. HKEY hkCurrentSourceKey = NULL;
  450. HKEY hkCurrentDestKey = NULL;
  451. DWORD idx;
  452. DWORD NameLen;
  453. LONG result = ERROR_SUCCESS;
  454. REGKEYINFO RegKeyInfo;
  455. BOOL Success = FALSE;
  456. FILETIME SourceFileTime;
  457. FILETIME DestFileTime;
  458. LONG cmp;
  459. if ( !PrepForEnumRegistryTree( hkSourceTree, &RegKeyInfo ) )
  460. return FALSE; // nothing to clean up here yet
  461. // enumerate all the source subkeys
  462. // for each: if dest subkey is older than source, delete it
  463. // if dest subkey does not exist (or was deleted) clone the subkey
  464. //
  465. // Clone all the subkeys
  466. //
  467. for ( idx = 0;
  468. (result == ERROR_SUCCESS) &&
  469. ( result != ERROR_MORE_DATA ) &&
  470. ( idx < RegKeyInfo.SubKeyCount );
  471. idx++ ) {
  472. NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
  473. result = RegEnumKeyEx( hkSourceTree,
  474. idx,
  475. RegKeyInfo.pSubKeyName,
  476. &NameLen,
  477. NULL,
  478. NULL,
  479. NULL,
  480. &SourceFileTime );
  481. if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
  482. goto cleanup;
  483. // TBD: open the subkey in the source tree AS CurrentSourceKey
  484. result = RegOpenKeyEx(hkSourceTree,
  485. RegKeyInfo.pSubKeyName,
  486. 0,
  487. KEY_READ,
  488. &hkCurrentSourceKey);
  489. if (result != ERROR_SUCCESS)
  490. goto cleanup;
  491. result = RegOpenKeyEx(hkDestTree,
  492. RegKeyInfo.pSubKeyName,
  493. 0,
  494. KEY_READ,
  495. &hkCurrentDestKey);
  496. // if current dest key does not exist,
  497. if ( result == ERROR_FILE_NOT_FOUND )
  498. {
  499. //
  500. // recurse passing the subkey name
  501. //
  502. CloneRegistryTree( hkCurrentSourceKey,
  503. hkDestTree,
  504. RegKeyInfo.pSubKeyName );
  505. }
  506. // if current dest key is older than current source key, delete dest
  507. // then recreate new
  508. else if (result == ERROR_SUCCESS)
  509. {
  510. RegQueryInfoKey( hkCurrentDestKey,
  511. NULL,
  512. NULL,
  513. NULL,
  514. NULL,
  515. NULL,
  516. NULL,
  517. NULL,
  518. NULL,
  519. NULL,
  520. NULL,
  521. &DestFileTime );
  522. cmp = CompareFileTime( &SourceFileTime, &DestFileTime );
  523. if ( cmp > 0 )
  524. {
  525. // delete dest
  526. //
  527. DeleteRegistrySubtree( hkCurrentDestKey );
  528. //
  529. // recurse passing the subkey name
  530. //
  531. CloneRegistryTree( hkCurrentSourceKey,
  532. hkDestTree,
  533. RegKeyInfo.pSubKeyName );
  534. }
  535. RegCloseKey(hkCurrentDestKey);
  536. }
  537. //
  538. // close our open key
  539. //
  540. RegCloseKey( hkCurrentSourceKey );
  541. result = ERROR_SUCCESS;
  542. }
  543. cleanup:
  544. CleanupAfterEnumRegistryTree( hkSourceTree, &RegKeyInfo );
  545. return TRUE;
  546. }
  547. //*************************************************************
  548. //
  549. // MergeUserClasses()
  550. //
  551. // Purpose: Merges the user's class information with the
  552. // common class information.
  553. //
  554. // Parameters: UserClassStore - Per-user class information
  555. // CommonClassStore - Machine-wide class information
  556. // MergedClassStore - Destination for merged information.
  557. //
  558. // Return: TRUE if successful
  559. // FALSE if an error occurs
  560. //
  561. // Comments: UserClassStore may be a null HKEY, implying
  562. // just copy the information from the common
  563. // portion into the merged portion
  564. //
  565. // History: Date Author Comment
  566. // 1/14/96 GregJen Created
  567. //
  568. //*************************************************************
  569. BOOL
  570. MergeRegistrySubtree (
  571. HKEY hkSourceParent,
  572. HKEY hkDestParent,
  573. LPTSTR pszSubtree )
  574. {
  575. HKEY hkCurrentSourceKey = NULL;
  576. HKEY hkCurrentDestKey = NULL;
  577. LONG result;
  578. DWORD dummy = 0;
  579. // open the special subtree in the source tree
  580. result = RegOpenKeyEx( hkSourceParent,
  581. pszSubtree,
  582. 0,
  583. KEY_READ,
  584. &hkCurrentSourceKey );
  585. // TBD: if no subtree in source, skip ahead to next special subtree
  586. if ( result == ERROR_FILE_NOT_FOUND )
  587. return TRUE;
  588. // If any other errors occurred, return FALSE
  589. if ( result != ERROR_SUCCESS)
  590. return FALSE;
  591. result = RegOpenKeyEx( hkDestParent,
  592. pszSubtree,
  593. 0,
  594. KEY_ALL_ACCESS,
  595. &hkCurrentDestKey );
  596. // TBD: if no such subtree in dest, do CloneRegistry etc
  597. if ( result == ERROR_FILE_NOT_FOUND )
  598. {
  599. //
  600. // recurse passing the subkey name
  601. //
  602. CloneRegistryTree( hkCurrentSourceKey,
  603. hkDestParent,
  604. pszSubtree );
  605. }
  606. // TBD:if timestamp on source is newer than timestamp on dest,
  607. // delete dest and recreate??
  608. // Bug 45995
  609. if (hkCurrentDestKey)
  610. {
  611. MergeRegistrySubKeys( hkCurrentSourceKey,
  612. hkCurrentDestKey );
  613. // make sure the timestamp on the special trees is updated
  614. result = RegSetValueEx( hkCurrentDestKey,
  615. TEXT("Updated"),
  616. 0,
  617. REG_DWORD,
  618. (BYTE*) &dummy,
  619. sizeof( DWORD ) );
  620. RegCloseKey( hkCurrentDestKey );
  621. }
  622. // close special subtrees
  623. RegCloseKey( hkCurrentSourceKey );
  624. return TRUE;
  625. }
  626. long
  627. CompareRegistryTimes(
  628. HKEY hkLHS,
  629. HKEY hkRHS )
  630. {
  631. FILETIME LHSTime;
  632. FILETIME RHSTime;
  633. RegQueryInfoKey( hkLHS,
  634. NULL,
  635. NULL,
  636. NULL,
  637. NULL,
  638. NULL,
  639. NULL,
  640. NULL,
  641. NULL,
  642. NULL,
  643. NULL,
  644. &LHSTime );
  645. RegQueryInfoKey( hkRHS,
  646. NULL,
  647. NULL,
  648. NULL,
  649. NULL,
  650. NULL,
  651. NULL,
  652. NULL,
  653. NULL,
  654. NULL,
  655. NULL,
  656. &RHSTime );
  657. return CompareFileTime( &LHSTime, &RHSTime );
  658. }
  659. //*************************************************************
  660. //
  661. // MergeUserClasses()
  662. //
  663. // Purpose: Merges the user's class information with the
  664. // common class information.
  665. //
  666. // Parameters: UserClassStore - Per-user class information
  667. // CommonClassStore - Machine-wide class information
  668. // MergedClassStore - Destination for merged information.
  669. //
  670. // Return: TRUE if successful
  671. // FALSE if an error occurs
  672. //
  673. // Comments: UserClassStore may be a null HKEY, implying
  674. // just copy the information from the common
  675. // portion into the merged portion
  676. //
  677. // History: Date Author Comment
  678. // 1/14/96 GregJen Created
  679. //
  680. //*************************************************************
  681. BOOL
  682. MergeUserClasses(
  683. HKEY UserClassStore,
  684. HKEY CommonClassStore,
  685. HKEY MergedClassStore,
  686. BOOL ForceNew )
  687. {
  688. BOOL fNotCorrectUser = FALSE;
  689. HKEY hkOverridingSubtree = CommonClassStore;
  690. HKEY hkMergingSubtree = UserClassStore;
  691. int idx;
  692. //TBD: check time stamps on source and destination
  693. // if same user, and timestamps are in sync, do nothing
  694. // if destination does not belong to the current user, then
  695. // delete everything under it
  696. if ( fNotCorrectUser ) {
  697. DeleteRegistrySubtree( MergedClassStore );
  698. }
  699. if ( !ForceNew &&
  700. ( CompareRegistryTimes( MergedClassStore, CommonClassStore ) > 0 ) &&
  701. ( CompareRegistryTimes( MergedClassStore, UserClassStore ) > 0 ) )
  702. {
  703. return TRUE;
  704. }
  705. // TBD: copy everything from the overriding store into the
  706. // destination store
  707. // At this moment, the common store overrides the user store;
  708. // this will eventually reverse.
  709. CloneRegistryTree( hkOverridingSubtree, MergedClassStore, NULL );
  710. // now, for each of the special top-level keys, process the level below them
  711. // these keys are: CLSID, Interface, TypeLib, Licenses, FileType
  712. for ( idx = 0; idx < MAX_SPECIAL_SUBTREE; idx++ )
  713. {
  714. MergeRegistrySubtree( hkMergingSubtree,
  715. MergedClassStore,
  716. SpecialSubtrees[idx] );
  717. }
  718. // now do all the top level keys (file extensions and progids)
  719. // TBD: MergeRegistrySubtree( UserClassStore, MergedClassStore );
  720. MergeRegistrySubtree( hkMergingSubtree,
  721. MergedClassStore,
  722. NULL );
  723. return TRUE;
  724. }