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.

2054 lines
51 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. hkcr.c
  5. Abstract:
  6. Implements routines that merge various HKCR settings. Macro expansion
  7. list defines a list of merge routines that are called for a particular
  8. key. A context ID and a set of flags allow control over when a merge
  9. routine is called.
  10. The flag set controls the type of enumeration the merge routine wants
  11. to be notified with. It can be any of three values:
  12. MERGE_FLAG_KEY - Called for the root key itself
  13. MERGE_FLAG_VALUE - Called for each value in the root key
  14. MERGE_FLAG_SUBKEY - Called for each subkey in the root key
  15. Recursion of MergeRegistryNode is used to copy parts of the tree.
  16. The context ID is defined in merge.h, and is expandable. It is used
  17. to specify a context when making recursive calls.
  18. The order of processing of the merge routines is specified in the
  19. macro expansion list. The default behavior if no routine chooses to
  20. handle a key is to copy without overwrite.
  21. Author:
  22. Jim Schmidt (jimschm) 24-Mar-1998
  23. Revision History:
  24. jimschm 23-Sep-1998 Updated for new flag bit size
  25. jimschm 27-Apr-1998 Added DefaultIcon preservation
  26. --*/
  27. #include "pch.h"
  28. #include "mergep.h"
  29. extern DWORD g_ProgressBarCounter;
  30. #define MERGE_FLAG_KEY 0x0001
  31. #define MERGE_FLAG_SUBKEY 0x0002
  32. #define MERGE_FLAG_VALUE 0x0004
  33. #define MERGE_ALL_FLAGS 0xFFFFFFFF
  34. #define MERGE_FLAG_SUBKEYS_AND_VALUES (MERGE_FLAG_SUBKEY|MERGE_FLAG_VALUE)
  35. #define MERGE_FLAG_ALL (MERGE_FLAG_KEY|MERGE_FLAG_SUBKEY|MERGE_FLAG_VALUE)
  36. #define MERGE_FLAG_ALL_KEYS (MERGE_FLAG_KEY|MERGE_FLAG_SUBKEY)
  37. #define MULTI_CONTEXT ANY_CONTEXT
  38. /*++
  39. Macro Expansion List Description:
  40. HKCR_FUNCTION_LIST lists functions that are called to process HKCR
  41. registry data. The functions are called in the order specified by
  42. the macro expansion list, and when none of the functions process
  43. the data, the last filter, pLastMergeRoutine, performs a copy-no-
  44. overwrite merge.
  45. Processing occurs in the following stages:
  46. 1. Functions are called for the key itself
  47. 2. Functions are called for each of the key's values
  48. 3. Functions are called for each of the key's subkeys
  49. Line Syntax:
  50. DEFMAC(FilterFn, ContextId, Flags)
  51. Arguments:
  52. FilterFn - Specifies the name of the function. This function is
  53. automatically prototyped as:
  54. MERGE_RESULT
  55. FilterFn (
  56. PMERGE_STATE State
  57. );
  58. The filter function uses the State structure to determine
  59. the context surrounding the registry data (i.e., where is
  60. it, what its parent is, what kind of data, etc.). The
  61. function returns one of the following:
  62. MERGE_LEAVE - Processing of the current key is terminated.
  63. MERGE_BREAK - Processing breaks out of the loop. If the
  64. loop is a value enumeration, then processing
  65. continues with the values. If the loop is
  66. a subkey enumeration, processing ends for
  67. the key.
  68. MERGE_CONTINUE - Processing continues to the next item in
  69. the enumeration.
  70. MERGE_NOP - The function did not process the data
  71. MERGE_ERROR - An error occurred processing the data. The
  72. error stops processing of HKCR.
  73. ContextId - Specifies the context the function is called in. Specify
  74. ANY_CONTEXT or MULTI_CONTEXT to always be called. The
  75. ContextId is specified by the caller of MergeRegistryNode.
  76. NOTE: If MULTI_CONTEXT is used, the function must examine
  77. the ContextId member of State and return MERGE_NOP
  78. if the context is not correct.
  79. Always place ANY_CONTEXT and MULTI_CONTEXT definitions
  80. at the end of the HKCR_FUNCTION_LIST definition.
  81. Flags - Specifies one or more of the following:
  82. MERGE_FLAG_KEY - Called for the key, before enumeration
  83. MERGE_FLAG_SUBKEY - Called for each subkey of the key
  84. MERGE_FLAG_VALUE - Called for each value of the key
  85. or a combined macro:
  86. MERGE_FLAG_SUBKEYS_AND_VALUES - Called for each subkey and each value
  87. MERGE_FLAG_ALL - Called for the key, then each subkey
  88. and each value
  89. Variables Generated From List:
  90. g_MergeRoutines
  91. --*/
  92. #define HKCR_FUNCTION_LIST \
  93. DEFMAC(pDetectRootKeyType, ROOT_BASE, MERGE_FLAG_SUBKEY) \
  94. DEFMAC(pFileExtensionMerge, ROOT_BASE, MERGE_FLAG_SUBKEY) \
  95. DEFMAC(pCopyClassId, CLSID_BASE, MERGE_FLAG_SUBKEY) \
  96. DEFMAC(pCopyClassIdWorker, CLSID_COPY, MERGE_FLAG_ALL_KEYS) \
  97. DEFMAC(pInstanceSpecialCase, CLSID_INSTANCE_COPY, MERGE_FLAG_ALL_KEYS) \
  98. DEFMAC(pCopyTypeLibOrInterface, MULTI_CONTEXT, MERGE_FLAG_SUBKEY) \
  99. DEFMAC(pCopyTypeLibVersion, TYPELIB_VERSION_COPY, MERGE_FLAG_SUBKEY) \
  100. DEFMAC(pDefaultIconExtraction, COPY_DEFAULT_ICON, MERGE_FLAG_ALL) \
  101. DEFMAC(pCopyDefaultValue, COPY_DEFAULT_VALUE, MERGE_FLAG_KEY) \
  102. DEFMAC(pKeyCopyMerge, KEY_COPY, MERGE_FLAG_VALUE) \
  103. \
  104. DEFMAC(pDetectDefaultIconKey, ANY_CONTEXT, MERGE_FLAG_SUBKEY) \
  105. DEFMAC(pEnsureShellDefaultValue, TREE_COPY_NO_OVERWRITE, MERGE_FLAG_SUBKEY) \
  106. DEFMAC(pTreeCopyMerge, MULTI_CONTEXT, MERGE_FLAG_ALL) \
  107. \
  108. DEFMAC(pLastMergeRoutine, MULTI_CONTEXT, MERGE_FLAG_SUBKEY)
  109. //
  110. // Simplification macros
  111. //
  112. #define CopyAllValues(state) MergeValuesOfKey(state,KEY_COPY)
  113. #define CopyAllSubKeyValues(state) MergeValuesOfSubKey(state,KEY_COPY)
  114. #define CopyEntireSubKey(state) MergeSubKeyNode(state,TREE_COPY)
  115. #define CopyEntireSubKeyNoOverwrite(state) MergeSubKeyNode(state,TREE_COPY_NO_OVERWRITE)
  116. //
  117. // Define macro expansion list types
  118. //
  119. typedef struct {
  120. HKEY Key95;
  121. HKEY KeyNt;
  122. HKEY SubKey95;
  123. HKEY SubKeyNt;
  124. BOOL CloseKey95;
  125. BOOL CloseKeyNt;
  126. PCTSTR SubKeyName;
  127. PCTSTR FullKeyName;
  128. PCTSTR FullSubKeyName;
  129. PCTSTR ValueName;
  130. PBYTE ValueData;
  131. DWORD ValueDataSize;
  132. DWORD ValueDataType;
  133. MERGE_CONTEXT Context;
  134. DWORD MergeFlag;
  135. BOOL LockValue;
  136. } MERGE_STATE, *PMERGE_STATE;
  137. typedef enum {
  138. MERGE_LEAVE,
  139. MERGE_BREAK,
  140. MERGE_CONTINUE,
  141. MERGE_NOP,
  142. MERGE_ERROR
  143. } MERGE_RESULT;
  144. typedef MERGE_RESULT (MERGE_ROUTINE_PROTOTYPE) (PMERGE_STATE State);
  145. typedef MERGE_ROUTINE_PROTOTYPE * MERGE_ROUTINE;
  146. typedef struct {
  147. MERGE_ROUTINE fn;
  148. MERGE_CONTEXT Context;
  149. DWORD Flags;
  150. } MERGE_ROUTINE_ATTRIBS, *PMERGE_ROUTINE_ATTRIBS;
  151. //
  152. // Declare function prototypes
  153. //
  154. #define DEFMAC(fn,id,flags) MERGE_ROUTINE_PROTOTYPE fn;
  155. HKCR_FUNCTION_LIST
  156. #undef DEFMAC
  157. //
  158. // Create g_MergeRoutines array
  159. //
  160. #define DEFMAC(fn,id,flags) {fn,id,flags},
  161. MERGE_ROUTINE_ATTRIBS g_MergeRoutines[] = {
  162. HKCR_FUNCTION_LIST /* , */
  163. {NULL, 0, 0}
  164. };
  165. #undef DEFMAC
  166. //
  167. // Local prototypes
  168. //
  169. MERGE_RESULT
  170. pCallMergeRoutines (
  171. IN OUT PMERGE_STATE State,
  172. IN DWORD MergeFlag
  173. );
  174. BOOL
  175. pMakeSureNtKeyExists (
  176. IN PMERGE_STATE State
  177. );
  178. BOOL
  179. pMakeSureNtSubKeyExists (
  180. IN PMERGE_STATE State
  181. );
  182. //
  183. // Globals
  184. //
  185. PBYTE g_MergeBuf;
  186. UINT g_MergeBufUseCount;
  187. //
  188. // Implementation
  189. //
  190. BOOL
  191. MergeRegistryNodeEx (
  192. IN PCTSTR RootKey,
  193. IN HKEY RootKey95, OPTIONAL
  194. IN HKEY RootKeyNt, OPTIONAL
  195. IN MERGE_CONTEXT Context,
  196. IN DWORD RestrictionFlags
  197. )
  198. /*++
  199. Routine Description:
  200. MergeRegistryNode calls functions for the specified RootKey, all of its
  201. values and all of its subkeys. The merge functions can at runtime decide
  202. how to process a key, and typically call this function recursively. All
  203. registry data is passed through the merge data filter, and keys or values
  204. marked as suppressed are not processed.
  205. Arguments:
  206. RootKey - Specifies the root key string, starting with either HKLM or HKR.
  207. RootKey95 - Specifies the 95-side root key; reduces the number of key open
  208. calls
  209. RootKeyNt - Specifies the NT-side root key; reduces the number of key open
  210. calls
  211. Context - Specifies a root ID constant that corresponds to RootKey. This
  212. constant is used by the merge routines to determine the
  213. processing context.
  214. RestrictionFlags - Specifies MERGE_FLAG mask to restrict processing. The
  215. caller can therefore limit the enumerations and processing
  216. to only values, only subkeys, only the key, or a combination
  217. of the three.
  218. Return Value:
  219. TRUE if processing was successful, or FALSE if one of the merge functiosn
  220. returned an error.
  221. --*/
  222. {
  223. REGKEY_ENUM ek;
  224. REGVALUE_ENUM ev;
  225. MERGE_STATE State;
  226. MERGE_RESULT Result = MERGE_NOP;
  227. ZeroMemory (&State, sizeof (MERGE_STATE));
  228. //
  229. // Do not process if key is suppressed
  230. //
  231. if (Is95RegKeyTreeSuppressed (RootKey)) {
  232. return TRUE;
  233. }
  234. //
  235. // Init State
  236. //
  237. ZeroMemory (&State, sizeof (State));
  238. State.Context = Context;
  239. //
  240. // If the NT registry key is suppressed, then we want to do a tree copy, regardless
  241. // of wether there is an NT value or not.
  242. //
  243. if (Context == TREE_COPY_NO_OVERWRITE && IsNtRegKeyTreeSuppressed (RootKey)) {
  244. DEBUGMSG ((DBG_VERBOSE, "The NT Value for %s will be overwritten because it is marked for suppression.", RootKey));
  245. State.Context = TREE_COPY;
  246. }
  247. if (RootKey95) {
  248. State.Key95 = RootKey95;
  249. } else {
  250. State.Key95 = OpenRegKeyStr95 (RootKey);
  251. State.CloseKey95 = (State.Key95 != NULL);
  252. }
  253. if (!State.Key95) {
  254. DEBUGMSG ((DBG_VERBOSE, "Root %s does not exist", RootKey));
  255. return TRUE;
  256. }
  257. //
  258. // Progress bar update
  259. //
  260. g_ProgressBarCounter++;
  261. if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) {
  262. g_ProgressBarCounter = 0;
  263. TickProgressBar();
  264. }
  265. __try {
  266. g_MergeBufUseCount++;
  267. if (g_MergeBufUseCount == MAX_REGISTRY_KEY) {
  268. DEBUGMSG ((DBG_WHOOPS, "Recursive merge depth indicates a loop problem, aborting!"));
  269. __leave;
  270. }
  271. if (RootKeyNt) {
  272. State.KeyNt = RootKeyNt;
  273. } else {
  274. State.KeyNt = OpenRegKeyStr (RootKey);
  275. State.CloseKeyNt = (State.KeyNt != NULL);
  276. }
  277. State.FullKeyName = RootKey;
  278. //
  279. // Key processing
  280. //
  281. if (!Is95RegKeySuppressed (RootKey)) {
  282. //
  283. // Loop through the key functions for the root key
  284. //
  285. if (RestrictionFlags & MERGE_FLAG_KEY) {
  286. Result = pCallMergeRoutines (&State, MERGE_FLAG_KEY);
  287. if (Result == MERGE_ERROR || Result == MERGE_LEAVE) {
  288. __leave;
  289. }
  290. }
  291. //
  292. // Loop through the values, skipping those that are suppressed
  293. //
  294. if ((RestrictionFlags & MERGE_FLAG_VALUE) &&
  295. EnumFirstRegValue95 (&ev, State.Key95)
  296. ) {
  297. do {
  298. if (Is95RegObjectSuppressed (State.FullKeyName, ev.ValueName)) {
  299. continue;
  300. }
  301. State.ValueName = ev.ValueName;
  302. State.ValueDataType = ev.Type;
  303. State.ValueDataSize = ev.DataSize;
  304. //
  305. // Loop through the value functions
  306. //
  307. Result = pCallMergeRoutines (&State, MERGE_FLAG_VALUE);
  308. if (Result == MERGE_ERROR ||
  309. Result == MERGE_LEAVE ||
  310. Result == MERGE_BREAK
  311. ) {
  312. break;
  313. }
  314. } while (EnumNextRegValue95 (&ev));
  315. if (Result == MERGE_ERROR || Result == MERGE_LEAVE) {
  316. __leave;
  317. }
  318. }
  319. State.ValueName = NULL;
  320. State.ValueDataType = 0;
  321. State.ValueDataSize = 0;
  322. }
  323. //
  324. // Subkey processing
  325. //
  326. if ((RestrictionFlags & MERGE_FLAG_SUBKEY) &&
  327. EnumFirstRegKey95 (&ek, State.Key95)
  328. ) {
  329. do {
  330. //
  331. // Prepare State, skip key if it is suppressed
  332. //
  333. State.SubKeyName = ek.SubKeyName;
  334. State.FullSubKeyName = JoinPaths (RootKey, ek.SubKeyName);
  335. if (Is95RegKeyTreeSuppressed (State.FullSubKeyName)) {
  336. FreePathString (State.FullSubKeyName);
  337. continue;
  338. }
  339. State.SubKey95 = OpenRegKey95 (ek.KeyHandle, ek.SubKeyName);
  340. if (State.KeyNt) {
  341. State.SubKeyNt = OpenRegKey (State.KeyNt, ek.SubKeyName);
  342. } else {
  343. State.SubKeyNt = NULL;
  344. }
  345. //
  346. // Loop through the subkey functions
  347. //
  348. Result = pCallMergeRoutines (&State, MERGE_FLAG_SUBKEY);
  349. //
  350. // Clean up
  351. //
  352. FreePathString (State.FullSubKeyName);
  353. if (State.SubKeyNt) {
  354. CloseRegKey (State.SubKeyNt);
  355. }
  356. if (State.SubKey95) {
  357. CloseRegKey95 (State.SubKey95);
  358. }
  359. if (Result == MERGE_ERROR ||
  360. Result == MERGE_LEAVE ||
  361. Result == MERGE_BREAK
  362. ) {
  363. break;
  364. }
  365. } while (EnumNextRegKey95 (&ek));
  366. if (Result == MERGE_ERROR || Result == MERGE_LEAVE) {
  367. __leave;
  368. }
  369. }
  370. }
  371. __finally {
  372. PushError();
  373. g_MergeBufUseCount--;
  374. if (!g_MergeBufUseCount && g_MergeBuf) {
  375. ReuseFree (g_hHeap, g_MergeBuf);
  376. g_MergeBuf = NULL;
  377. }
  378. if (State.CloseKey95) {
  379. CloseRegKey95 (State.Key95);
  380. }
  381. if (State.CloseKeyNt) {
  382. CloseRegKey (State.KeyNt);
  383. }
  384. PopError();
  385. }
  386. return Result != MERGE_ERROR;
  387. }
  388. BOOL
  389. MergeRegistryNode (
  390. IN PCTSTR RootKey,
  391. IN MERGE_CONTEXT Context
  392. )
  393. {
  394. return MergeRegistryNodeEx (RootKey, NULL, NULL, Context, MERGE_ALL_FLAGS);
  395. }
  396. BOOL
  397. MergeKeyNode (
  398. IN PMERGE_STATE State,
  399. IN MERGE_CONTEXT Context
  400. )
  401. {
  402. return MergeRegistryNodeEx (
  403. State->FullKeyName,
  404. State->Key95,
  405. State->KeyNt,
  406. Context,
  407. MERGE_ALL_FLAGS
  408. );
  409. }
  410. BOOL
  411. MergeSubKeyNode (
  412. IN PMERGE_STATE State,
  413. IN MERGE_CONTEXT Context
  414. )
  415. {
  416. return MergeRegistryNodeEx (
  417. State->FullSubKeyName,
  418. State->SubKey95,
  419. State->SubKeyNt,
  420. Context,
  421. MERGE_ALL_FLAGS
  422. );
  423. }
  424. BOOL
  425. MergeValuesOfKey (
  426. IN PMERGE_STATE State,
  427. IN MERGE_CONTEXT Context
  428. )
  429. {
  430. if (!pMakeSureNtKeyExists (State)) {
  431. DEBUGMSG ((DBG_ERROR, "Can't create %s to merge values", State->FullKeyName));
  432. return TRUE; // eat error
  433. }
  434. return MergeRegistryNodeEx (
  435. State->FullKeyName,
  436. State->Key95,
  437. State->KeyNt,
  438. Context,
  439. MERGE_FLAG_VALUE
  440. );
  441. }
  442. BOOL
  443. MergeValuesOfSubKey (
  444. IN PMERGE_STATE State,
  445. IN MERGE_CONTEXT Context
  446. )
  447. {
  448. if (!pMakeSureNtSubKeyExists (State)) {
  449. DEBUGMSG ((DBG_ERROR, "Can't create %s to merge values", State->FullSubKeyName));
  450. return TRUE; // eat error
  451. }
  452. return MergeRegistryNodeEx (
  453. State->FullSubKeyName,
  454. State->SubKey95,
  455. State->SubKeyNt,
  456. Context,
  457. MERGE_FLAG_VALUE
  458. );
  459. }
  460. MERGE_RESULT
  461. pCallMergeRoutines (
  462. IN OUT PMERGE_STATE State,
  463. IN DWORD MergeFlag
  464. )
  465. {
  466. INT i;
  467. MERGE_RESULT Result = MERGE_NOP;
  468. State->MergeFlag = MergeFlag;
  469. for (i = 0 ; g_MergeRoutines[i].fn ; i++) {
  470. if (g_MergeRoutines[i].Context != State->Context &&
  471. g_MergeRoutines[i].Context != ANY_CONTEXT
  472. ) {
  473. continue;
  474. }
  475. if (g_MergeRoutines[i].Flags & MergeFlag) {
  476. Result = g_MergeRoutines[i].fn (State);
  477. if (Result != MERGE_NOP) {
  478. break;
  479. }
  480. }
  481. }
  482. return Result;
  483. }
  484. BOOL
  485. pFillStateWithValue (
  486. IN OUT PMERGE_STATE State
  487. )
  488. /*++
  489. Routine Description:
  490. pFillStateWithValue queries the Win95 registry for the value specified in
  491. the inbound State struct. Upon return, the ValueData member of State is
  492. set to the global buffer g_MergeBuf. The value is passed through the merge
  493. data filter in datafilt.c.
  494. The caller must make a copy of the data if two or more values are to be
  495. processed at the same time.
  496. Arguments:
  497. State - Specifies the registry key name and value, along with a key handle.
  498. Receives the value data.
  499. Return Value:
  500. TRUE if the value was read, or FALSE if an error occurred.
  501. --*/
  502. {
  503. LONG rc;
  504. DWORD Size;
  505. if (!State->ValueName) {
  506. DEBUGMSG ((DBG_WHOOPS, "pFillStateWithValue: No value name"));
  507. return FALSE;
  508. }
  509. if (State->LockValue) {
  510. return TRUE;
  511. }
  512. //
  513. // Do not process if value is suppressed
  514. //
  515. if (Is95RegObjectSuppressed (State->FullKeyName, State->ValueName)) {
  516. return TRUE;
  517. }
  518. //
  519. // Get data from registry
  520. //
  521. rc = Win95RegQueryValueEx (
  522. State->Key95,
  523. State->ValueName,
  524. NULL,
  525. &State->ValueDataType,
  526. NULL,
  527. &State->ValueDataSize
  528. );
  529. if (rc != ERROR_SUCCESS) {
  530. SetLastError (rc);
  531. LOG ((
  532. LOG_ERROR,
  533. "Win95Reg query size of %s [%s] failed",
  534. State->FullKeyName,
  535. State->ValueName
  536. ));
  537. return FALSE;
  538. }
  539. Size = State->ValueDataSize;
  540. g_MergeBuf = (PBYTE) ReuseAlloc (g_hHeap, g_MergeBuf, Size);
  541. if (!g_MergeBuf) {
  542. DEBUGMSG ((DBG_ERROR, "pFillStateWithValue: ReuseAlloc returned NULL"));
  543. return FALSE;
  544. }
  545. rc = Win95RegQueryValueEx (
  546. State->Key95,
  547. State->ValueName,
  548. NULL,
  549. NULL,
  550. g_MergeBuf,
  551. &Size
  552. );
  553. if (rc != ERROR_SUCCESS) {
  554. SetLastError (rc);
  555. LOG ((
  556. LOG_ERROR,
  557. "Win95Reg query for %s [%s] failed",
  558. State->FullKeyName,
  559. State->ValueName
  560. ));
  561. return FALSE;
  562. }
  563. //
  564. // Convert data if necessary; g_MergeBuf is a ReUse buffer, so it's
  565. // address may change upon return.
  566. //
  567. State->ValueData = FilterRegValue (
  568. g_MergeBuf,
  569. Size,
  570. State->ValueDataType,
  571. State->FullKeyName,
  572. &State->ValueDataSize
  573. );
  574. if (State->ValueData) {
  575. if (g_MergeBuf != State->ValueData) {
  576. g_MergeBuf = State->ValueData;
  577. }
  578. }
  579. return State->ValueData != NULL;
  580. }
  581. BOOL
  582. pMakeSureNtKeyExists (
  583. IN PMERGE_STATE State
  584. )
  585. {
  586. if (!State->KeyNt) {
  587. State->KeyNt = CreateRegKeyStr (State->FullKeyName);
  588. State->CloseKeyNt = (State->KeyNt != NULL);
  589. }
  590. return State->KeyNt != NULL;
  591. }
  592. BOOL
  593. pMakeSureNtSubKeyExists (
  594. IN PMERGE_STATE State
  595. )
  596. {
  597. if (!State->SubKeyNt) {
  598. State->SubKeyNt = CreateRegKeyStr (State->FullSubKeyName);
  599. }
  600. return State->SubKeyNt != NULL;
  601. }
  602. BOOL
  603. pCopy95ValueToNt (
  604. IN OUT PMERGE_STATE State
  605. )
  606. {
  607. LONG rc = ERROR_SUCCESS;
  608. if (pFillStateWithValue (State)) {
  609. pMakeSureNtKeyExists (State);
  610. rc = RegSetValueEx (
  611. State->KeyNt,
  612. State->ValueName,
  613. 0,
  614. State->ValueDataType,
  615. State->ValueData,
  616. State->ValueDataSize
  617. );
  618. if (rc != ERROR_SUCCESS) {
  619. SetLastError (rc);
  620. LOG ((
  621. LOG_ERROR,
  622. "Copy Win9x Value To Nt failed to set %s [%s]",
  623. State->FullKeyName,
  624. State->ValueName
  625. ));
  626. }
  627. }
  628. return rc = ERROR_SUCCESS;
  629. }
  630. MERGE_RESULT
  631. pFileExtensionMerge (
  632. IN PMERGE_STATE State
  633. )
  634. {
  635. BOOL CloseNTKey = FALSE;
  636. BOOL Close95Key = FALSE;
  637. PCTSTR Value9x, ValueNt;
  638. TCHAR key [MEMDB_MAX];
  639. DWORD value;
  640. MYASSERT (State->FullKeyName);
  641. MYASSERT (State->FullSubKeyName);
  642. MYASSERT (State->SubKeyName);
  643. MYASSERT (State->SubKey95);
  644. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  645. MYASSERT (State->Context == ROOT_BASE);
  646. //
  647. // Sub key name must have a dot
  648. //
  649. if (_tcsnextc (State->SubKeyName) != TEXT('.')) {
  650. return MERGE_NOP;
  651. }
  652. //
  653. // We look now to see if NT comes with this file extension.
  654. // If it does and the progID referenced by 9x file extension has
  655. // a loss of default command functionality, we let NT overwrite
  656. // the ProgId reference. We do this by suppressing the default
  657. // value of this file extension.
  658. //
  659. if (!State->SubKey95) {
  660. State->SubKey95 = OpenRegKeyStr95 (State->FullSubKeyName);
  661. Close95Key = (State->SubKey95 != NULL);
  662. }
  663. if (!State->SubKeyNt) {
  664. State->SubKeyNt = OpenRegKeyStr (State->FullSubKeyName);
  665. CloseNTKey = (State->SubKeyNt != NULL);
  666. }
  667. if (State->SubKey95 && State->SubKeyNt) {
  668. //
  669. // Let's see if we the NT default value is different than 9x one.
  670. //
  671. Value9x = GetRegValueString95 (State->SubKey95, TEXT(""));
  672. ValueNt = GetRegValueString (State->SubKeyNt, TEXT(""));
  673. if ((ValueNt && !Value9x) ||
  674. (!ValueNt && Value9x) ||
  675. (ValueNt && Value9x && (!StringIMatch (Value9x, ValueNt)))
  676. ) {
  677. MemDbBuildKey (key, MEMDB_CATEGORY_PROGIDS, Value9x?Value9x:State->SubKeyName, NULL, NULL);
  678. if (MemDbGetValue (key, &value) &&
  679. (value == PROGID_LOSTDEFAULT)
  680. ) {
  681. //
  682. // Now it's the time to suppress the default value for this file extension
  683. //
  684. MemDbBuildKey (key, MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), State->SubKeyName, NULL);
  685. if (!Suppress95RegSetting(key, TEXT(""))) {
  686. DEBUGMSG((DBG_WARNING,"Could not suppress %s\\[] registry setting.", key));
  687. }
  688. }
  689. }
  690. if (Value9x) {
  691. MemFree (g_hHeap, 0, Value9x);
  692. Value9x = NULL;
  693. }
  694. if (ValueNt) {
  695. MemFree (g_hHeap, 0, ValueNt);
  696. ValueNt = NULL;
  697. }
  698. }
  699. if (Close95Key) {
  700. CloseRegKey95 (State->SubKey95);
  701. State->SubKey95 = NULL;
  702. }
  703. if (CloseNTKey) {
  704. CloseRegKey (State->SubKeyNt);
  705. State->SubKeyNt = NULL;
  706. }
  707. //
  708. // We copy all the extensions blindly
  709. //
  710. if (!CopyEntireSubKey (State)) {
  711. return MERGE_ERROR;
  712. }
  713. //
  714. // Return MERGE_CONTINUE so processing continues to next subkey
  715. //
  716. return MERGE_CONTINUE;
  717. }
  718. MERGE_RESULT
  719. pDetectDefaultIconKey (
  720. IN PMERGE_STATE State
  721. )
  722. {
  723. MYASSERT (State->FullKeyName);
  724. MYASSERT (State->FullSubKeyName);
  725. MYASSERT (State->SubKeyName);
  726. MYASSERT (State->SubKey95);
  727. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  728. if (StringIMatch (State->SubKeyName, TEXT("DefaultIcon"))) {
  729. if (!MergeSubKeyNode (State, COPY_DEFAULT_ICON)) {
  730. return MERGE_ERROR;
  731. }
  732. return MERGE_CONTINUE;
  733. }
  734. return MERGE_NOP;
  735. }
  736. MERGE_RESULT
  737. pEnsureShellDefaultValue (
  738. IN PMERGE_STATE State
  739. )
  740. {
  741. PTSTR dataNt = NULL;
  742. PTSTR data9x = NULL;
  743. PTSTR p = NULL;
  744. MYASSERT (State->FullKeyName);
  745. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  746. if (StringIMatch (State->SubKeyName, TEXT("Shell"))) {
  747. //
  748. // Get default values for both sides. We'll need this
  749. // to determine wether to do the merge or not.
  750. //
  751. pMakeSureNtSubKeyExists (State);
  752. data9x = (PTSTR) GetRegValueData95 (State->SubKey95, S_EMPTY);
  753. dataNt = (PTSTR) GetRegValueData (State->SubKeyNt, S_EMPTY);
  754. __try {
  755. if (data9x && *data9x && (!dataNt || !*dataNt)) {
  756. //
  757. // If we get here, we know there is some value set
  758. // in the win9x registry and no value set in the
  759. // nt registry.
  760. //
  761. p = JoinPaths (State->FullSubKeyName, data9x);
  762. if (!Is95RegKeyTreeSuppressed (p)) {
  763. if (!MergeSubKeyNode (State, COPY_DEFAULT_VALUE)) {
  764. return MERGE_ERROR;
  765. }
  766. }
  767. }
  768. } __finally {
  769. if (p) {
  770. FreePathString (p);
  771. }
  772. if (dataNt) {
  773. MemFree (g_hHeap, 0, dataNt);
  774. }
  775. if (data9x) {
  776. MemFree (g_hHeap, 0, data9x);
  777. }
  778. }
  779. }
  780. return MERGE_NOP;
  781. }
  782. MERGE_RESULT
  783. pDefaultIconExtraction (
  784. IN PMERGE_STATE State
  785. )
  786. {
  787. PCTSTR Data;
  788. TCHAR iconCmdLine[MAX_CMDLINE];
  789. PCTSTR LongPath = NULL;
  790. PCTSTR p;
  791. INT IconIndex;
  792. TCHAR IconIndexStr[32];
  793. TCHAR Node[MEMDB_MAX];
  794. DWORD Offset;
  795. DWORD Seq;
  796. LONG rc;
  797. BOOL Copied = FALSE;
  798. PCTSTR updatedPath;
  799. INT newSeq;
  800. MYASSERT (State->Context == COPY_DEFAULT_ICON);
  801. if (State->MergeFlag == MERGE_FLAG_KEY) {
  802. return MERGE_BREAK;
  803. }
  804. if (State->MergeFlag == MERGE_FLAG_SUBKEY) {
  805. //
  806. // Copy subkey (which is garbage)
  807. //
  808. if (!CopyEntireSubKey (State)) {
  809. return MERGE_ERROR;
  810. }
  811. return MERGE_CONTINUE;
  812. }
  813. //
  814. // Get the default command line
  815. //
  816. if (State->ValueDataSize > MAX_CMDLINE - sizeof (TCHAR)) {
  817. LOG ((LOG_ERROR, "Data too large in %s [%s]", State->FullKeyName, State->ValueName));
  818. return MERGE_CONTINUE;
  819. }
  820. Data = (PCTSTR) GetRegValueString95 (State->Key95, State->ValueName);
  821. if (Data) {
  822. //
  823. // Determine if command line has saved icon
  824. //
  825. ExtractArgZeroEx (Data, iconCmdLine, TEXT(","), TRUE);
  826. p = (PCTSTR) ((PBYTE) Data + ByteCount (iconCmdLine));
  827. while (*p == TEXT(' ')) {
  828. p++;
  829. }
  830. if (*p == TEXT(',')) {
  831. IconIndex = _ttoi (_tcsinc (p));
  832. LongPath = GetSourceFileLongName (iconCmdLine);
  833. wsprintf (IconIndexStr, TEXT("%i"), IconIndex);
  834. //
  835. // Test for a moved icon. If there is a moved icon, use it,
  836. // otherwise test for an extracted icon. If there is an
  837. // extracted icon, use it. Otherwise, leave DefaultIcon alone.
  838. //
  839. iconCmdLine[0] = 0;
  840. MemDbBuildKey (Node, MEMDB_CATEGORY_ICONS_MOVED, LongPath, IconIndexStr, NULL);
  841. if (MemDbGetValueAndFlags (Node, &Offset, &Seq)) {
  842. //
  843. // icon moved to a new binary
  844. //
  845. if (IconIndex < 0) {
  846. newSeq = -((INT) Seq);
  847. } else {
  848. newSeq = (INT) Seq;
  849. }
  850. MemDbBuildKeyFromOffset (Offset, Node, 1, NULL);
  851. updatedPath = GetPathStringOnNt (Node);
  852. wsprintf (iconCmdLine, TEXT("%s,%i"), updatedPath, newSeq);
  853. FreePathString (updatedPath);
  854. } else {
  855. Offset = INVALID_OFFSET;
  856. MemDbBuildKey (Node, MEMDB_CATEGORY_ICONS, LongPath, IconIndexStr, NULL);
  857. if (MemDbGetValueAndFlags (Node, NULL, &Seq)) {
  858. //
  859. // icon was extracted
  860. //
  861. wsprintf (iconCmdLine, TEXT("%s,%i"), g_IconBin, Seq);
  862. }
  863. }
  864. if (iconCmdLine[0]) {
  865. //
  866. // DefaultIcon has changed; write change now (full REG_SZ
  867. // value is in iconCmdLine)
  868. //
  869. if (!pMakeSureNtKeyExists (State)) {
  870. LOG ((
  871. LOG_ERROR,
  872. "Unable to open %s",
  873. State->FullKeyName
  874. ));
  875. } else {
  876. rc = RegSetValueEx (
  877. State->KeyNt,
  878. State->ValueName,
  879. 0,
  880. REG_SZ,
  881. (PBYTE) iconCmdLine,
  882. SizeOfString (iconCmdLine)
  883. );
  884. if (rc != ERROR_SUCCESS) {
  885. SetLastError (rc);
  886. LOG ((
  887. LOG_ERROR,
  888. "Default Icon Extraction failed to set path for %s",
  889. State->FullKeyName
  890. ));
  891. } else {
  892. Copied = TRUE;
  893. DEBUGMSG_IF ((
  894. Offset == INVALID_OFFSET,
  895. DBG_VERBOSE,
  896. "DefaultIcon preserved for %s [%s]",
  897. State->FullKeyName,
  898. State->ValueName
  899. ));
  900. DEBUGMSG_IF ((
  901. Offset != INVALID_OFFSET,
  902. DBG_VERBOSE,
  903. "DefaultIcon moved to new OS icon for %s [%s]",
  904. State->FullKeyName,
  905. State->ValueName
  906. ));
  907. }
  908. }
  909. }
  910. FreePathString (LongPath);
  911. }
  912. MemFree (g_hHeap, 0, Data);
  913. }
  914. if (!Copied) {
  915. pCopy95ValueToNt (State);
  916. }
  917. return MERGE_CONTINUE;
  918. }
  919. MERGE_RESULT
  920. pTreeCopyMerge (
  921. IN PMERGE_STATE State
  922. )
  923. {
  924. REGVALUE_ENUM ev;
  925. if (State->Context != TREE_COPY && State->Context != TREE_COPY_NO_OVERWRITE) {
  926. return MERGE_NOP;
  927. }
  928. switch (State->MergeFlag) {
  929. case MERGE_FLAG_KEY:
  930. if (State->Context == TREE_COPY) {
  931. if (!pMakeSureNtKeyExists (State)) {
  932. LOG ((
  933. LOG_ERROR,
  934. "Unable to create %s",
  935. State->FullKeyName
  936. ));
  937. }
  938. } else {
  939. //
  940. // If no values in Win9x key, then it is OK to create the
  941. // value-less key now. Otherwise, wait until MERGE_FLAG_VALUE
  942. // processing.
  943. //
  944. if (!EnumFirstRegValue95 (&ev, State->Key95)) {
  945. if (!pMakeSureNtKeyExists (State)) {
  946. LOG ((
  947. LOG_ERROR,
  948. "Unable to create %s",
  949. State->FullKeyName
  950. ));
  951. }
  952. }
  953. }
  954. break;
  955. case MERGE_FLAG_VALUE:
  956. //
  957. // Copy values unconditionally, unless no overwrite is specified and
  958. // NT key exists.
  959. //
  960. if (State->Context == TREE_COPY_NO_OVERWRITE && State->KeyNt) {
  961. return MERGE_BREAK;
  962. }
  963. if (!MergeKeyNode (State, KEY_COPY)) {
  964. return MERGE_ERROR;
  965. }
  966. return MERGE_BREAK; // MERGE_BREAK breaks out of value enumeration and enters
  967. // subkey enumeration
  968. case MERGE_FLAG_SUBKEY:
  969. //
  970. // Continue copy recursively
  971. //
  972. if (!MergeSubKeyNode (State, State->Context)) {
  973. return MERGE_ERROR;
  974. }
  975. break;
  976. }
  977. return MERGE_CONTINUE;
  978. }
  979. MERGE_RESULT
  980. pKeyCopyMerge (
  981. IN OUT PMERGE_STATE State
  982. )
  983. {
  984. MYASSERT (State->FullKeyName);
  985. MYASSERT (!State->FullSubKeyName);
  986. MYASSERT (!State->SubKeyName);
  987. MYASSERT (!State->SubKey95);
  988. MYASSERT (State->ValueName);
  989. MYASSERT (State->MergeFlag == MERGE_FLAG_VALUE);
  990. MYASSERT (State->Context == KEY_COPY);
  991. pCopy95ValueToNt (State);
  992. return MERGE_CONTINUE;
  993. }
  994. MERGE_RESULT
  995. pCopyDefaultValue (
  996. IN PMERGE_STATE State
  997. )
  998. {
  999. PCSTR value1;
  1000. PCSTR value2;
  1001. PCWSTR value3;
  1002. MYASSERT (State->FullKeyName);
  1003. MYASSERT (!State->FullSubKeyName);
  1004. MYASSERT (!State->SubKeyName);
  1005. MYASSERT (!State->SubKey95);
  1006. MYASSERT (!State->ValueName);
  1007. MYASSERT (State->MergeFlag == MERGE_FLAG_KEY);
  1008. MYASSERT (State->Context == COPY_DEFAULT_VALUE);
  1009. State->ValueName = S_EMPTY;
  1010. #ifdef DEBUG
  1011. //
  1012. // Obtain NT value, if it exists, then compare against Win9x value. If
  1013. // different, dump debug output.
  1014. //
  1015. {
  1016. PBYTE Data95, DataNt;
  1017. Data95 = GetRegValueData95 (State->Key95, S_EMPTY);
  1018. DataNt = GetRegValueData (State->KeyNt, S_EMPTY);
  1019. if (Data95 && DataNt) {
  1020. __try {
  1021. if (memcmp (Data95, DataNt, ByteCount ((PTSTR) Data95))) {
  1022. DEBUGMSG ((
  1023. DBG_VERBOSE,
  1024. "Default value of %s changed from %s to %s",
  1025. State->FullKeyName,
  1026. DataNt,
  1027. Data95
  1028. ));
  1029. }
  1030. }
  1031. __except (1) {
  1032. }
  1033. }
  1034. if (Data95) {
  1035. MemFree (g_hHeap, 0, Data95);
  1036. }
  1037. if (DataNt) {
  1038. MemFree (g_hHeap, 0, DataNt);
  1039. }
  1040. }
  1041. #endif
  1042. //
  1043. // now let's get the value and convert it if necessary
  1044. //
  1045. if (pFillStateWithValue (State)) {
  1046. if ((OurGetACP() == 932) &&
  1047. ((State->ValueDataType == REG_SZ) ||
  1048. (State->ValueDataType == REG_EXPAND_SZ)
  1049. )) {
  1050. //
  1051. // apply the Katakana filter
  1052. //
  1053. value1 = ConvertWtoA ((PCWSTR) State->ValueData);
  1054. value2 = ConvertSBtoDB (NULL, value1, NULL);
  1055. value3 = ConvertAtoW (value2);
  1056. g_MergeBuf = (PBYTE) ReuseAlloc (g_hHeap, g_MergeBuf, SizeOfStringW (value3));
  1057. StringCopyW ((PWSTR)g_MergeBuf, value3);
  1058. State->ValueData = g_MergeBuf;
  1059. FreeConvertedStr (value3);
  1060. FreePathStringA (value2);
  1061. FreeConvertedStr (value1);
  1062. }
  1063. State->LockValue = TRUE;
  1064. pCopy95ValueToNt (State);
  1065. State->LockValue = FALSE;
  1066. }
  1067. State->ValueName = NULL;
  1068. return MERGE_LEAVE;
  1069. }
  1070. MERGE_RESULT
  1071. pDetectRootKeyType (
  1072. IN PMERGE_STATE State
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. pDetectRootKeyType identifies CLSID in the root of HKCR, and when found, the CLSID
  1077. subkey is processed with the CLSID_BASE context.
  1078. Arguments:
  1079. State - Specifies the enumeration state.
  1080. Return Value:
  1081. MERGE_ERROR - An error occurred
  1082. MERGE_CONTINUE - The subkey was processed
  1083. MERGE_NOP - The subkey was not processed
  1084. --*/
  1085. {
  1086. MYASSERT (State->FullKeyName);
  1087. MYASSERT (State->FullSubKeyName);
  1088. MYASSERT (State->SubKeyName);
  1089. MYASSERT (State->SubKey95);
  1090. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  1091. MYASSERT (State->Context == ROOT_BASE);
  1092. if (StringIMatch (State->SubKeyName, TEXT("CLSID"))) {
  1093. //
  1094. // This is the CLSID key; copy with CLSID_BASE
  1095. //
  1096. if (!MergeSubKeyNode (State, CLSID_BASE)) {
  1097. return MERGE_ERROR;
  1098. }
  1099. //
  1100. // Copy the values (usually there are none)
  1101. //
  1102. if (!MergeRegistryNodeEx (
  1103. State->FullKeyName,
  1104. State->Key95,
  1105. State->KeyNt,
  1106. KEY_COPY,
  1107. MERGE_FLAG_VALUE
  1108. )) {
  1109. return MERGE_ERROR;
  1110. }
  1111. return MERGE_CONTINUE;
  1112. } else if (StringIMatch (State->SubKeyName, TEXT("TYPELIB"))) {
  1113. //
  1114. // Copy the TypeLib subkey (its values and all of its subkeys)
  1115. //
  1116. if (!MergeSubKeyNode (State, TYPELIB_BASE) ||
  1117. !CopyAllSubKeyValues (State)
  1118. ) {
  1119. return MERGE_ERROR;
  1120. }
  1121. return MERGE_CONTINUE;
  1122. } else if (StringIMatch (State->SubKeyName, TEXT("Interface"))) {
  1123. //
  1124. // Copy the Interface, then copy the values (usually none)
  1125. //
  1126. if (!MergeSubKeyNode (State, INTERFACE_BASE)) {
  1127. return MERGE_ERROR;
  1128. }
  1129. if (!CopyAllSubKeyValues (State)) {
  1130. return MERGE_ERROR;
  1131. }
  1132. return MERGE_CONTINUE;
  1133. }
  1134. return MERGE_NOP;
  1135. }
  1136. BOOL
  1137. pIsNtClsIdOverwritable (
  1138. IN HKEY Key
  1139. )
  1140. {
  1141. REGKEY_ENUM e;
  1142. BOOL Overwritable = TRUE;
  1143. HKEY InstanceSubKey;
  1144. //
  1145. // Enumerate the subkeys. If there is a subkey that has a binary
  1146. // implementation, then do not overwrite the key.
  1147. //
  1148. if (!Key) {
  1149. return TRUE;
  1150. }
  1151. if (EnumFirstRegKey (&e, Key)) {
  1152. do {
  1153. if (StringIMatchCharCount (e.SubKeyName, TEXT("Inproc"), 6) ||
  1154. StringIMatch (e.SubKeyName, TEXT("LocalServer")) ||
  1155. StringIMatch (e.SubKeyName, TEXT("LocalServer32")) ||
  1156. StringIMatch (e.SubKeyName, TEXT("ProxyStubClsid32"))
  1157. ) {
  1158. Overwritable = FALSE;
  1159. break;
  1160. }
  1161. if (StringIMatch (e.SubKeyName, TEXT("Instance"))) {
  1162. break;
  1163. }
  1164. } while (EnumNextRegKey (&e));
  1165. }
  1166. if (!Overwritable) {
  1167. //
  1168. // if we think a key is not overwritable, we have
  1169. // to test for a subkey Instance. If it exists, then we
  1170. // consider the key overwritable. This is for ActiveMovie,
  1171. // and unfortunately it has the potential of breaking anyone
  1172. // in NT who puts an Instance key in their CLSID. Since
  1173. // ActiveMovie plug-ins use this key, we're stuck.
  1174. //
  1175. // Fortunately, nobody in NT does this currently.
  1176. //
  1177. InstanceSubKey = OpenRegKey (Key, TEXT("Instance"));
  1178. if (InstanceSubKey) {
  1179. CloseRegKey (InstanceSubKey);
  1180. Overwritable = TRUE;
  1181. }
  1182. return Overwritable;
  1183. }
  1184. return TRUE;
  1185. }
  1186. MERGE_RESULT
  1187. pCopyClassId (
  1188. IN PMERGE_STATE State
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. pCopyClassId performs a copy of an HKCR\CLSID\* key. It copies the entire
  1193. key to NT if NT does not provide an equivalent setting. In all cases, the
  1194. friendly name is copied to NT, because it may have been modified on Win9x.
  1195. However, we don't copy the default value when we are talking about a suppressed
  1196. GUID and NT does not install this GUID.
  1197. This function is called for all subkeys of CLSID. The subkey name is either
  1198. a GUID or garbage.
  1199. Arguments:
  1200. State - Specifies the enumeration state, which is always a subkey of
  1201. HKCR\CLSID in this case.
  1202. Return Value:
  1203. MERGE_CONTINUE - Key was processed
  1204. MERGE_ERROR - An error occurred
  1205. --*/
  1206. {
  1207. TCHAR Node[MEMDB_MAX];
  1208. TCHAR DefaultIconKey[MAX_REGISTRY_KEY];
  1209. HKEY DefaultIcon95;
  1210. BOOL Copied = FALSE;
  1211. PTSTR defaultValue = NULL;
  1212. MYASSERT (State->FullKeyName);
  1213. MYASSERT (State->FullSubKeyName);
  1214. MYASSERT (State->SubKeyName);
  1215. MYASSERT (State->SubKey95);
  1216. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  1217. MYASSERT (State->Context == CLSID_BASE);
  1218. //
  1219. // Skip if the GUID is suppressed
  1220. //
  1221. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, State->SubKeyName, NULL, NULL);
  1222. if (!MemDbGetValue (Node, NULL)) {
  1223. //
  1224. // Copy entire Win9x setting if GUID does not exist on NT.
  1225. // If GUID exists on NT, do not touch it.
  1226. //
  1227. if (pIsNtClsIdOverwritable (State->SubKeyNt)) {
  1228. Copied = TRUE;
  1229. if (!pMakeSureNtSubKeyExists (State)) {
  1230. LOG ((LOG_ERROR, "Can't create %s", State->FullSubKeyName));
  1231. } else {
  1232. //
  1233. // Copy the specific CLSID key from 95 to NT
  1234. //
  1235. if (!MergeSubKeyNode (State, CLSID_COPY)) {
  1236. return MERGE_ERROR;
  1237. }
  1238. }
  1239. }
  1240. ELSE_DEBUGMSG ((DBG_VERBOSE, "CLSID %s is not overwritable", State->SubKeyName));
  1241. }
  1242. if (!Copied) {
  1243. if (State->SubKeyNt) {
  1244. defaultValue = (PTSTR) GetRegValueData95 (State->SubKey95, S_EMPTY);
  1245. if (defaultValue && *defaultValue) {
  1246. //
  1247. // If ClsId is suppressed but NT installs the GUID, we want to copy
  1248. // the default value and the default icon for GUID.
  1249. //
  1250. // (This is the class friendly name.)
  1251. //
  1252. if (!MergeRegistryNodeEx (
  1253. State->FullSubKeyName,
  1254. State->SubKey95,
  1255. State->SubKeyNt,
  1256. COPY_DEFAULT_VALUE,
  1257. MERGE_FLAG_KEY
  1258. )) {
  1259. return MERGE_ERROR;
  1260. }
  1261. }
  1262. if (defaultValue) {
  1263. MemFree (g_hHeap, 0, defaultValue);
  1264. }
  1265. StringCopy (DefaultIconKey, State->FullSubKeyName);
  1266. StringCopy (AppendWack (DefaultIconKey), TEXT("DefaultIcon"));
  1267. DefaultIcon95 = OpenRegKeyStr95 (DefaultIconKey);
  1268. if (DefaultIcon95) {
  1269. CloseRegKey95 (DefaultIcon95);
  1270. if (!MergeRegistryNode (DefaultIconKey, COPY_DEFAULT_ICON)) {
  1271. return MERGE_ERROR;
  1272. }
  1273. }
  1274. }
  1275. }
  1276. return MERGE_CONTINUE;
  1277. }
  1278. MERGE_RESULT
  1279. pCopyClassIdWorker (
  1280. IN PMERGE_STATE State
  1281. )
  1282. /*++
  1283. Routine Description:
  1284. pCopyClassIdWorker handles one CLSID entry. It processses all the values
  1285. of the entry, and all subkeys. This routine looks for the special cases of
  1286. CLSID. If none are found, the entire key is copied (unless NT provides the
  1287. key). If a special case is found, the root is changed for the special
  1288. case.
  1289. The key is HKCR\CLSID\<guid>.
  1290. The subkey is HKCR\CLSID\<guid>\<subkey>
  1291. We have already determined that <guid> is not suppressed.
  1292. Arguments:
  1293. State - Specifies the enumeration state, which is the subkey of HKCR\CLSID,
  1294. or the subkey of HKCR\CLSID\<guid>.
  1295. Return Value:
  1296. MERGE_CONTINUE - Key was processed
  1297. MERGE_ERROR - An error occurred
  1298. --*/
  1299. {
  1300. MYASSERT (State->FullKeyName);
  1301. MYASSERT (State->FullSubKeyName || State->MergeFlag == MERGE_FLAG_KEY);
  1302. MYASSERT (State->SubKeyName || State->MergeFlag == MERGE_FLAG_KEY);
  1303. MYASSERT (State->SubKey95 || State->MergeFlag == MERGE_FLAG_KEY);
  1304. MYASSERT (State->Context == CLSID_COPY);
  1305. switch (State->MergeFlag) {
  1306. case MERGE_FLAG_KEY:
  1307. //
  1308. // For MERGE_FLAG_KEY, copy all the values
  1309. //
  1310. CopyAllValues (State);
  1311. break;
  1312. case MERGE_FLAG_SUBKEY:
  1313. //
  1314. // For MERGE_FLAG_SUBKEY, copy unless it needs a special-case merge
  1315. //
  1316. if (StringIMatch (State->SubKeyName, TEXT("Instance"))) {
  1317. //
  1318. // The subkey is Instance, perform a special-case merge
  1319. //
  1320. if (!MergeSubKeyNode (State, CLSID_INSTANCE_COPY)) {
  1321. return MERGE_ERROR;
  1322. }
  1323. } else {
  1324. //
  1325. // Copy the key unconditionally
  1326. //
  1327. if (!CopyEntireSubKey (State)) {
  1328. return MERGE_ERROR;
  1329. }
  1330. }
  1331. break;
  1332. default:
  1333. DEBUGMSG ((DBG_WHOOPS, "Wasteful call to pCopyClassIdWorker"));
  1334. break;
  1335. }
  1336. return MERGE_CONTINUE;
  1337. }
  1338. MERGE_RESULT
  1339. pInstanceSpecialCase (
  1340. IN PMERGE_STATE State
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. pInstanceSpecialCase handles the Instance subkey of arbitrary GUIDs. This
  1345. is used by ActiveMovie to track third-party plug-ins. This routine
  1346. examines the format of Instance (specific to ActiveMove), and copies only
  1347. parts of the key that are compatible with NT and not
  1348. replaced.
  1349. The Key refers to HKCR\CLSID\<guid>\Instance.
  1350. The SubKey refers to HKCR\CLSID\<guid>\Instance\<sequencer>
  1351. We have already determined that <guid> is not suppressed.
  1352. Arguments:
  1353. State - Specifies the HKCR state.
  1354. Return Value:
  1355. MERGE_CONTINUE - Key was processed
  1356. MERGE_ERROR - An error occurred
  1357. --*/
  1358. {
  1359. TCHAR Guid[MAX_GUID];
  1360. TCHAR Node[MEMDB_MAX];
  1361. LONG rc;
  1362. DWORD Size;
  1363. MYASSERT (State->FullKeyName);
  1364. MYASSERT (State->FullSubKeyName || State->MergeFlag == MERGE_FLAG_KEY);
  1365. MYASSERT (State->SubKeyName || State->MergeFlag == MERGE_FLAG_KEY);
  1366. MYASSERT (State->SubKey95 || State->MergeFlag == MERGE_FLAG_KEY);
  1367. MYASSERT (State->Context == CLSID_INSTANCE_COPY);
  1368. switch (State->MergeFlag) {
  1369. case MERGE_FLAG_KEY:
  1370. //
  1371. // Copy all values (normally there are none)
  1372. //
  1373. CopyAllValues (State);
  1374. break;
  1375. case MERGE_FLAG_SUBKEY:
  1376. //
  1377. // The subkey is a random enumerator (usually a GUID -- but it is not defined
  1378. // to be so). Look at the CLSID value of the subkey, then check the GUID
  1379. // (the value data) against the suppress list.
  1380. //
  1381. //
  1382. // Was that random enumerator installed by NT? If so, ignore the Win9x
  1383. // setting.
  1384. //
  1385. if (State->SubKeyNt) {
  1386. break;
  1387. }
  1388. //
  1389. // Get GUID and see if it is suppressed
  1390. //
  1391. Size = sizeof (Guid);
  1392. rc = Win95RegQueryValueEx (
  1393. State->SubKey95,
  1394. TEXT("CLSID"),
  1395. NULL,
  1396. NULL,
  1397. (PBYTE) Guid,
  1398. &Size
  1399. );
  1400. if (rc != ERROR_SUCCESS) {
  1401. //
  1402. // No CLSID value; copy entire subkey unaltered
  1403. //
  1404. if (!CopyEntireSubKey (State)) {
  1405. return MERGE_ERROR;
  1406. }
  1407. }
  1408. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, Guid, NULL, NULL);
  1409. if (!MemDbGetValue (Node, NULL)) {
  1410. //
  1411. // GUID is not suppressed; copy entire subkey unaltered
  1412. //
  1413. if (!CopyEntireSubKey (State)) {
  1414. return MERGE_ERROR;
  1415. }
  1416. }
  1417. ELSE_DEBUGMSG ((DBG_VERBOSE, "Suppressing ActiveMovie Instance GUID: %s", Guid));
  1418. break;
  1419. default:
  1420. DEBUGMSG ((DBG_WHOOPS, "Wasteful call to pInstanceSpecialCase"));
  1421. break;
  1422. }
  1423. return MERGE_CONTINUE;
  1424. }
  1425. MERGE_RESULT
  1426. pCopyTypeLibOrInterface (
  1427. IN PMERGE_STATE State
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. pCopyTypeLibOrInterface copies the COM type registration and COM interfaces.
  1432. Arguments:
  1433. State - Specifies the enumeration state, which is always a subkey of
  1434. HKCR\TypeLib in this case.
  1435. Return Value:
  1436. MERGE_CONTINUE - Key was processed
  1437. MERGE_ERROR - An error occurred
  1438. --*/
  1439. {
  1440. TCHAR Node[MEMDB_MAX];
  1441. MYASSERT (State->FullKeyName);
  1442. MYASSERT (State->FullSubKeyName);
  1443. MYASSERT (State->SubKeyName);
  1444. MYASSERT (State->SubKey95);
  1445. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  1446. if (State->Context != TYPELIB_BASE &&
  1447. State->Context != INTERFACE_BASE
  1448. ) {
  1449. return MERGE_NOP;
  1450. }
  1451. //
  1452. // Skip if the GUID is suppressed
  1453. //
  1454. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, State->SubKeyName, NULL, NULL);
  1455. if (!MemDbGetValue (Node, NULL)) {
  1456. if (State->Context == TYPELIB_BASE) {
  1457. //
  1458. // If this is a typelib entry, use additional typelib logic
  1459. //
  1460. if (!MergeSubKeyNode (State, TYPELIB_VERSION_COPY) ||
  1461. !CopyAllSubKeyValues (State)
  1462. ) {
  1463. return MERGE_ERROR;
  1464. }
  1465. } else {
  1466. //
  1467. // For the Interface entries, copy entire Win9x setting if
  1468. // GUID does not exist on NT. If GUID exists on NT, do not
  1469. // touch it.
  1470. //
  1471. if (!State->SubKeyNt) {
  1472. if (!CopyEntireSubKey (State)) {
  1473. return MERGE_ERROR;
  1474. }
  1475. }
  1476. }
  1477. }
  1478. return MERGE_CONTINUE;
  1479. }
  1480. MERGE_RESULT
  1481. pCopyTypeLibVersion (
  1482. IN PMERGE_STATE State
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. pCopyTypeLibVersion copies the type registration for a specific
  1487. interface version. It only copies if the particular version
  1488. is not installed by NT.
  1489. This function is called only for subkeys within a TypeLib\{GUID}
  1490. key.
  1491. Arguments:
  1492. State - Specifies the enumeration state, which is always a subkey of
  1493. HKCR\TypeLib in this case.
  1494. Return Value:
  1495. MERGE_CONTINUE - Key was processed
  1496. MERGE_ERROR - An error occurred
  1497. --*/
  1498. {
  1499. MYASSERT (State->FullKeyName);
  1500. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  1501. MYASSERT (State->Context == TYPELIB_VERSION_COPY);
  1502. MYASSERT (State->FullSubKeyName);
  1503. MYASSERT (State->SubKeyName);
  1504. MYASSERT (State->SubKey95);
  1505. //
  1506. // Skip if the sub key exists in NT, copy the entire thing otherwise
  1507. //
  1508. if (!State->SubKeyNt) {
  1509. if (!CopyEntireSubKey (State)) {
  1510. return MERGE_ERROR;
  1511. }
  1512. }
  1513. return MERGE_CONTINUE;
  1514. }
  1515. MERGE_RESULT
  1516. pLastMergeRoutine (
  1517. IN PMERGE_STATE State
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. pLastMergeRoutine performs a default copy with no overwrite for all keys
  1522. left unhandled. This routine first verifies the context is a base context
  1523. (such as ROOT_BASE or CLSID_BASE), and if so, MergeRegistryNode is called
  1524. recursively to perform the merge.
  1525. Arguments:
  1526. State - Specifies the enumeration state
  1527. Return Value:
  1528. MERGE_NOP - The subkey was not processed
  1529. MERGE_ERROR - An error occurred
  1530. MERGE_CONTINUE - The key was merged
  1531. --*/
  1532. {
  1533. TCHAR DefaultIconKey[MAX_REGISTRY_KEY];
  1534. HKEY DefaultIcon95;
  1535. MYASSERT (State->FullKeyName);
  1536. MYASSERT (State->FullSubKeyName);
  1537. MYASSERT (State->SubKeyName);
  1538. MYASSERT (State->SubKey95);
  1539. MYASSERT (State->MergeFlag == MERGE_FLAG_SUBKEY);
  1540. //
  1541. // Process only base contexts
  1542. //
  1543. if (State->Context != ROOT_BASE &&
  1544. State->Context != CLSID_BASE
  1545. ) {
  1546. return MERGE_NOP;
  1547. }
  1548. //
  1549. // If we got here, nobody wants to handle the current key,
  1550. // so let's copy it without overwriting NT keys.
  1551. //
  1552. if (!CopyEntireSubKeyNoOverwrite (State)) {
  1553. return MERGE_ERROR;
  1554. }
  1555. //
  1556. // Special case: If ROOT_BASE, and subkey has a DefaultIcon subkey,
  1557. // run the DefaultIcon processing.
  1558. //
  1559. if (State->Context == ROOT_BASE) {
  1560. StringCopy (DefaultIconKey, State->FullSubKeyName);
  1561. StringCopy (AppendWack (DefaultIconKey), TEXT("DefaultIcon"));
  1562. DefaultIcon95 = OpenRegKeyStr95 (DefaultIconKey);
  1563. if (DefaultIcon95) {
  1564. CloseRegKey95 (DefaultIcon95);
  1565. if (!MergeRegistryNode (DefaultIconKey, COPY_DEFAULT_ICON)) {
  1566. return MERGE_ERROR;
  1567. }
  1568. }
  1569. }
  1570. return MERGE_CONTINUE;
  1571. }