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.

2803 lines
72 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. rulehlpr.c
  5. Abstract:
  6. Migration rule helper DLL
  7. This source file implements helper functions needed to migrate the
  8. system applications. Inside usermig.inf are rules that call this
  9. DLL to do various data conversions. Two examples of these are
  10. conversion of the accessibility cpl and desktop scheme conversions.
  11. Author:
  12. Jim Schmidt (jimschm) 06-Aug-1996
  13. Revision History:
  14. jimschm 17-Feb-1999 Now calling ismig.dll
  15. ovidiut 02-Feb-1999 Added ConvertCDPlayerSettings
  16. jimschm 20-Jan-1999 pAddRemoveProgramsFilter
  17. jimschm 23-Sep-1998 Changed for new fileop code
  18. jimschm 27-Jul-1998 Added ValFn_AntiAlias
  19. calinn 19-May-1998 Added MigrateFreeCell
  20. jimschm 30-Apr-1998 Added ShellIcons support
  21. jimschm 25-Mar-1998 Added MergeClasses support
  22. jimschm 24-Feb-1998 Added ValFn_Fonts
  23. jimschm 20-Feb-1998 Added ValFn_ModuleUsage
  24. calinn 19-Jan-1998 Modified ValidateRunKey
  25. jimschm 25-Nov-1997 Added RuleHlpr_ConvertAppPaths
  26. --*/
  27. #include "pch.h"
  28. #include "ismig.h"
  29. //
  30. // Types
  31. //
  32. typedef struct {
  33. REGVALFN RegValFn;
  34. BOOL Tree;
  35. } MERGEFILTERARG, *PMERGEFILTERARG;
  36. typedef struct {
  37. PCTSTR Old;
  38. PCTSTR New;
  39. } STRINGREPLACEARGS, *PSTRINGREPLACEARGS;
  40. typedef struct {
  41. PCTSTR FunctionName;
  42. PROCESSINGFN ProcessingFn;
  43. PVOID Arg;
  44. } HELPER_FUNCTION, *PHELPER_FUNCTION;
  45. HANDLE g_ISMigDll;
  46. PISUGETALLSTRINGS ISUGetAllStrings;
  47. PISUMIGRATE ISUMigrate;
  48. //
  49. // Processing functions get the chance to do any
  50. // kind of translation necessary, including ones
  51. // that involve other keys, values or value data.
  52. //
  53. #define PROCESSING_FUNCITON_LIST \
  54. DECLARE_PROCESSING_FN(ConvertFilterKeys) \
  55. DECLARE_PROCESSING_FN(ConvertOldDisabled) \
  56. DECLARE_PROCESSING_FN(CreateNetMappings) \
  57. DECLARE_PROCESSING_FN(ConvertRecentMappings) \
  58. DECLARE_PROCESSING_FN(ConvertMouseKeys) \
  59. DECLARE_PROCESSING_FN(ConvertStickyKeys) \
  60. DECLARE_PROCESSING_FN(ConvertSoundSentry) \
  61. DECLARE_PROCESSING_FN(ConvertTimeOut) \
  62. DECLARE_PROCESSING_FN(ConvertToggleKeys) \
  63. DECLARE_PROCESSING_FN(ConvertHighContrast) \
  64. DECLARE_PROCESSING_FN(ConvertAppPaths) \
  65. DECLARE_PROCESSING_FN(ConvertKeysToValues) \
  66. DECLARE_PROCESSING_FN(MergeClasses) \
  67. DECLARE_PROCESSING_FN(ShellIcons) \
  68. DECLARE_PROCESSING_FN(MigrateFreeCell) \
  69. DECLARE_PROCESSING_FN(MigrateAddRemovePrograms) \
  70. DECLARE_PROCESSING_FN(MigrateKeyboardLayouts) \
  71. DECLARE_PROCESSING_FN(MigrateKeyboardPreloads) \
  72. DECLARE_PROCESSING_FN(MigrateKeyboardSubstitutes) \
  73. DECLARE_PROCESSING_FN(ValidateRunKey) \
  74. //
  75. // To simplify things, you can write a reg val function when you only need
  76. // to translate registry value settings. Depending on the pattern stored
  77. // in usermig.inf or wkstamig.inf, your reg val function will be called for
  78. // a single value, all values of a key, or all values of all keys and
  79. // subkeys. You will *not* be called for the key or subkey itself.
  80. //
  81. // The text comment describes which values are expected by the reg val
  82. // function.
  83. //
  84. // Name INF Syntax Description
  85. //
  86. // "key values" HKR\Foo\Bar Routine processes the values of a single key
  87. // "key tree values" HKR\Foo\Bar\* Routine processes all values including subkeys
  88. // "value" HKR\Foo\[Bar] Routine processes one value
  89. // "any value" (any syntax) Routine doesn't care about keys
  90. //
  91. #define VAL_FN_LIST \
  92. DECLARE_REGVAL(ConvertRunMRU, "key values") \
  93. DECLARE_REGVAL(ConvertRecentDocsMRU, "key values") \
  94. DECLARE_REGVAL(ConvertLogFont, "key tree values") \
  95. DECLARE_REGVAL(ConvertAppearanceScheme, "key tree values") \
  96. DECLARE_REGVAL(ConvertToDword, "any value") \
  97. DECLARE_REGVAL(ConvertToString, "any value") \
  98. DECLARE_REGVAL(VerifyLastLoggedOnUser, "value") \
  99. DECLARE_REGVAL(AddSharedDlls, "key values") \
  100. DECLARE_REGVAL(ConvertIndeoSettings, "key tree values") \
  101. DECLARE_REGVAL(ModuleUsage, "key tree values") \
  102. DECLARE_REGVAL(Fonts, "key values") \
  103. DECLARE_REGVAL(AntiAlias, "any value") \
  104. DECLARE_REGVAL(ConvertDarwinPaths, "key tree value") \
  105. DECLARE_REGVAL(FixActiveDesktop, "any value") \
  106. DECLARE_REGVAL(ConvertCDPlayerSettings, "value") \
  107. //
  108. // Make the necessary declarations
  109. //
  110. #define DECLARE PROCESSING_FUNCITON_LIST VAL_FN_LIST
  111. PROCESSINGFN_PROTOTYPE RuleHlpr_ConvertReg;
  112. PROCESSINGFN_PROTOTYPE RuleHlpr_ConvertRegVal;
  113. PROCESSINGFN_PROTOTYPE RuleHlpr_ConvertRegKey;
  114. PROCESSINGFN_PROTOTYPE RuleHlpr_ConvertRegTree;
  115. #define DECLARE_PROCESSING_FN(fn) PROCESSINGFN_PROTOTYPE RuleHlpr_##fn;
  116. #define DECLARE_REGVAL(fn,type) REGVALFN_PROTOTYPE ValFn_##fn;
  117. DECLARE
  118. #undef DECLARE_PROCESSING_FN
  119. #undef DECLARE_REGVAL
  120. #define DECLARE_PROCESSING_FN(fn) TEXT(#fn), RuleHlpr_##fn, NULL,
  121. #define DECLARE_REGVAL(fn,type) TEXT(#fn), RuleHlpr_ConvertReg, ValFn_##fn,
  122. HELPER_FUNCTION g_HelperFunctions[] = {
  123. DECLARE /* , */
  124. NULL, NULL, NULL
  125. };
  126. #undef DECLARE_PROCESSING_FN
  127. #undef DECLARE_REGVAL
  128. #undef DECLARE
  129. //
  130. // Prototypes
  131. //
  132. FILTERRETURN
  133. AppPathsKeyFilter (
  134. IN CPDATAOBJECT SrcObjectPtr,
  135. IN CPDATAOBJECT DestObjectPtr,
  136. IN FILTERTYPE FilterType,
  137. IN PVOID FilterArg
  138. );
  139. FILTERRETURN
  140. pConvertKeysToValuesFilter (
  141. IN CPDATAOBJECT SrcObject,
  142. IN CPDATAOBJECT DstObject,
  143. IN FILTERTYPE Type,
  144. IN PVOID Arg
  145. );
  146. FILTERRETURN
  147. Standard9xSuppressFilter (
  148. IN CPDATAOBJECT SrcObject,
  149. IN CPDATAOBJECT DstObject,
  150. IN FILTERTYPE FilterType,
  151. IN PVOID Arg
  152. );
  153. FILTERRETURN
  154. pNtPreferredSuppressFilter (
  155. IN CPDATAOBJECT SrcObject,
  156. IN CPDATAOBJECT DstObject,
  157. IN FILTERTYPE FilterType,
  158. IN PVOID Arg
  159. );
  160. //
  161. // Globals
  162. //
  163. PVOID g_NtFontFiles;
  164. #define S_FONTS_KEY TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts")
  165. //
  166. // Implementation
  167. //
  168. BOOL
  169. WINAPI
  170. RuleHlpr_Entry (
  171. IN HINSTANCE hinstDLL,
  172. IN DWORD dwReason,
  173. IN PVOID lpv
  174. )
  175. /*++
  176. Routine Description:
  177. DllMain is called after the C runtime is initialized, and its purpose
  178. is to initialize the globals for this process. For this DLL, DllMain
  179. is provided as a stub.
  180. Arguments:
  181. hinstDLL - (OS-supplied) Instance handle for the DLL
  182. dwReason - (OS-supplied) Type of initialization or termination
  183. lpv - (OS-supplied) Unused
  184. Return Value:
  185. TRUE because DLL always initializes properly.
  186. --*/
  187. {
  188. HKEY Key;
  189. REGVALUE_ENUM e;
  190. PCTSTR Data;
  191. switch (dwReason)
  192. {
  193. case DLL_PROCESS_ATTACH:
  194. if(!pSetupInitializeUtils()) {
  195. return FALSE;
  196. }
  197. g_NtFontFiles = pSetupStringTableInitialize();
  198. if (!g_NtFontFiles) {
  199. return FALSE;
  200. }
  201. Key = OpenRegKeyStr (S_FONTS_KEY);
  202. if (!Key) {
  203. DEBUGMSG ((DBG_WHOOPS, "Can't open %s", S_FONTS_KEY));
  204. } else {
  205. if (EnumFirstRegValue (&e, Key)) {
  206. do {
  207. Data = GetRegValueString (Key, e.ValueName);
  208. if (Data) {
  209. pSetupStringTableAddString (
  210. g_NtFontFiles,
  211. (PTSTR) Data,
  212. STRTAB_CASE_INSENSITIVE
  213. );
  214. MemFree (g_hHeap, 0, Data);
  215. }
  216. } while (EnumNextRegValue (&e));
  217. }
  218. CloseRegKey (Key);
  219. }
  220. break;
  221. case DLL_PROCESS_DETACH:
  222. if (g_NtFontFiles) {
  223. pSetupStringTableDestroy (g_NtFontFiles);
  224. g_NtFontFiles = NULL;
  225. }
  226. if (g_ISMigDll) {
  227. FreeLibrary (g_ISMigDll);
  228. g_ISMigDll = NULL;
  229. }
  230. pSetupUninitializeUtils();
  231. break;
  232. }
  233. return TRUE;
  234. }
  235. PROCESSINGFN
  236. RuleHlpr_GetFunctionAddr (
  237. PCTSTR Function,
  238. PVOID *ArgPtrToPtr
  239. )
  240. {
  241. PHELPER_FUNCTION p;
  242. p = g_HelperFunctions;
  243. while (p->FunctionName) {
  244. if (StringIMatch (p->FunctionName, Function)) {
  245. *ArgPtrToPtr = p->Arg;
  246. return p->ProcessingFn;
  247. }
  248. p++;
  249. }
  250. SetLastError (ERROR_PROC_NOT_FOUND);
  251. return NULL;
  252. }
  253. BOOL
  254. RuleHlpr_ConvertReg (
  255. IN PCTSTR SrcObjectStr,
  256. IN PCTSTR DestObjectStr,
  257. IN PCTSTR User,
  258. IN PVOID Data
  259. )
  260. {
  261. DATAOBJECT Ob;
  262. BOOL b;
  263. if (!CreateObjectStruct (SrcObjectStr, &Ob, WIN95OBJECT)) {
  264. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertReg: %s is invalid", SrcObjectStr));
  265. return FALSE;
  266. }
  267. if (IsObjectRegistryKeyOnly (&Ob)) {
  268. if (Ob.ObjectType & OT_TREE) {
  269. b = RuleHlpr_ConvertRegTree (SrcObjectStr, DestObjectStr, User, Data);
  270. } else {
  271. b = RuleHlpr_ConvertRegKey (SrcObjectStr, DestObjectStr, User, Data);
  272. }
  273. } else if (IsObjectRegistryKeyAndVal (&Ob)) {
  274. b = RuleHlpr_ConvertRegVal (SrcObjectStr, DestObjectStr, User, Data);
  275. } else {
  276. DEBUGMSG ((DBG_WHOOPS, "RuleHlpr_ConvertReg: %s is not a supported object type", SrcObjectStr));
  277. b = FALSE;
  278. }
  279. FreeObjectStruct (&Ob);
  280. return b;
  281. }
  282. BOOL
  283. RuleHlpr_ConvertRegVal (
  284. IN PCTSTR SrcObjectStr,
  285. IN PCTSTR DestObjectStr,
  286. IN PCTSTR User,
  287. IN PVOID Data
  288. )
  289. /*++
  290. Routine Description:
  291. RuleHlpr_ConvertRegVal calls a value function for just one value. It makes
  292. sure the value is supposed to be processed, then it calls the value
  293. function and writes the value to the destination.
  294. Arguments:
  295. SrcObjectStr - Specifies the source object string, as specified by the INF
  296. DestObjectStr - Specifies the destination object string. In most cases,
  297. this string is the same as SrcObjectStr. Registry key
  298. mapping can influence the destination.
  299. User - Specifies the user name (for the value function's use)
  300. Data - Specifies data for the value function's use
  301. Return Value:
  302. TRUE if the value was processed, FALSE if an error occurred.
  303. --*/
  304. {
  305. DATAOBJECT SrcObject;
  306. DATAOBJECT DstObject;
  307. BOOL b = FALSE;
  308. REGVALFN RegValFn;
  309. FILTERRETURN StdRc;
  310. DWORD Err;
  311. RegValFn = (REGVALFN) Data;
  312. //
  313. // If this value is Force NT value, and the NT value exists
  314. // already, then don't call the value function.
  315. //
  316. if (!CreateObjectStruct (SrcObjectStr, &SrcObject, WIN95OBJECT)) {
  317. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegVal: %s is not a valid source", SrcObjectStr));
  318. return FALSE;
  319. }
  320. if (!CreateObjectStruct (DestObjectStr, &DstObject, WINNTOBJECT)) {
  321. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegVal: %s is not a valid source", SrcObjectStr));
  322. goto c0;
  323. }
  324. StdRc = Standard9xSuppressFilter (
  325. &SrcObject,
  326. &DstObject,
  327. FILTER_VALUENAME_ENUM,
  328. NULL
  329. );
  330. if (StdRc != FILTER_RETURN_CONTINUE) {
  331. DEBUGMSG ((
  332. DBG_NAUSEA,
  333. "A value-based rule helper was skipped for %s",
  334. SrcObjectStr
  335. ));
  336. b = TRUE;
  337. goto c1;
  338. }
  339. StdRc = pNtPreferredSuppressFilter (
  340. &SrcObject,
  341. &DstObject,
  342. FILTER_VALUENAME_ENUM,
  343. NULL
  344. );
  345. if (StdRc != FILTER_RETURN_CONTINUE) {
  346. DEBUGMSG ((
  347. DBG_NAUSEA,
  348. "A value-based rule helper was skipped for %s because the NT value exists already",
  349. SrcObjectStr
  350. ));
  351. b = TRUE;
  352. goto c1;
  353. }
  354. //
  355. // Read registry value
  356. //
  357. if (!ReadObject (&SrcObject)) {
  358. Err = GetLastError();
  359. if (Err == ERROR_SUCCESS || Err == ERROR_FILE_NOT_FOUND) {
  360. b = TRUE;
  361. DEBUGMSG ((DBG_VERBOSE, "RuleHlpr_ConvertRegVal failed because %s does not exist", SrcObjectStr));
  362. } else {
  363. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegVal failed because ReadObject failed"));
  364. }
  365. goto c1;
  366. }
  367. //
  368. // Call conversion function
  369. //
  370. if (!RegValFn (&SrcObject)) {
  371. if (GetLastError() == ERROR_SUCCESS) {
  372. b = TRUE;
  373. }
  374. goto c1;
  375. }
  376. //
  377. // Write changed value to destination (which takes into account renaming)
  378. //
  379. if (!WriteWinNTObjectString (DestObjectStr, &SrcObject)) {
  380. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegVal failed because WriteWinNTObjectString failed"));
  381. goto c1;
  382. }
  383. b = TRUE;
  384. c1:
  385. FreeObjectStruct (&DstObject);
  386. c0:
  387. FreeObjectStruct (&SrcObject);
  388. return b;
  389. }
  390. FILTERRETURN
  391. RegKeyMergeFilter (
  392. IN CPDATAOBJECT InObPtr,
  393. IN CPDATAOBJECT OutObPtr,
  394. IN FILTERTYPE Type,
  395. IN PVOID Arg
  396. )
  397. /*++
  398. Routine Description:
  399. RegKeyMergeFilter is the filter that calls value functions.
  400. Arguments:
  401. InObPtr - Specifies the source object.
  402. OutObPtr - Specifies the destination object.
  403. Type - Specifies the filter type. See Standard9xSuppressFilter for
  404. a good description.
  405. Arg - Specifies the value function to run. See the VAL_FN_LIST macro
  406. expansion list.
  407. Return Value:
  408. A FILTERRETURN value that specifies how to proceed with the enumeration.
  409. --*/
  410. {
  411. PMERGEFILTERARG ArgPtr;
  412. FILTERRETURN StdRc;
  413. ArgPtr = (PMERGEFILTERARG) Arg;
  414. if (Type != FILTER_CREATE_KEY) {
  415. StdRc = Standard9xSuppressFilter (InObPtr, OutObPtr, Type, Arg);
  416. if (StdRc != FILTER_RETURN_CONTINUE) {
  417. DEBUGMSG ((
  418. DBG_NAUSEA,
  419. "A value-based rule helper was skipped for %s",
  420. DEBUGENCODER (InObPtr)
  421. ));
  422. return StdRc;
  423. }
  424. }
  425. StdRc = pNtPreferredSuppressFilter (InObPtr, OutObPtr, Type, NULL);
  426. if (StdRc != FILTER_RETURN_CONTINUE) {
  427. DEBUGMSG ((
  428. DBG_NAUSEA,
  429. "A value-based rule helper was skipped for %s because NT value exists",
  430. DEBUGENCODER (InObPtr)
  431. ));
  432. return StdRc;
  433. }
  434. if (Type == FILTER_CREATE_KEY) {
  435. return FILTER_RETURN_HANDLED;
  436. }
  437. if (Type == FILTER_KEY_ENUM) {
  438. return ArgPtr->Tree ? FILTER_RETURN_CONTINUE : FILTER_RETURN_HANDLED;
  439. }
  440. if (Type == FILTER_VALUE_COPY) {
  441. DATAOBJECT SrcOb, DestOb;
  442. BOOL b = FALSE;
  443. if (!DuplicateObjectStruct (&SrcOb, InObPtr)) {
  444. return FILTER_RETURN_FAIL;
  445. }
  446. // This guy has a value
  447. MYASSERT (SrcOb.ObjectType & OT_VALUE);
  448. //
  449. // Process data
  450. //
  451. if (!ArgPtr->RegValFn (&SrcOb)) {
  452. if (GetLastError() == ERROR_SUCCESS) {
  453. b = TRUE;
  454. } else {
  455. DEBUGMSG ((DBG_VERBOSE, "RegKeyMergeFilter: RegValFn failed with gle=%u", GetLastError()));
  456. }
  457. } else {
  458. //
  459. // Write results
  460. //
  461. if (DuplicateObjectStruct (&DestOb, OutObPtr)) {
  462. if (ReplaceValue (&DestOb, SrcOb.Value.Buffer, SrcOb.Value.Size)) {
  463. if (SrcOb.ObjectType & OT_REGISTRY_TYPE) {
  464. DestOb.ObjectType |= OT_REGISTRY_TYPE;
  465. DestOb.Type = SrcOb.Type;
  466. }
  467. if (WriteObject (&DestOb)) {
  468. b = TRUE;
  469. }
  470. }
  471. FreeObjectStruct (&DestOb);
  472. }
  473. }
  474. FreeObjectStruct (&SrcOb);
  475. return b ? FILTER_RETURN_HANDLED : FILTER_RETURN_FAIL;
  476. }
  477. return FILTER_RETURN_CONTINUE;
  478. }
  479. BOOL
  480. RuleHlpr_ConvertRegKey (
  481. IN PCTSTR SrcObjectStr,
  482. IN PCTSTR DestObjectStr,
  483. IN PCTSTR User,
  484. IN PVOID Data
  485. )
  486. {
  487. DATAOBJECT Ob, DestOb;
  488. BOOL b = FALSE;
  489. MERGEFILTERARG FilterArg;
  490. FILTERRETURN fr;
  491. //
  492. // Create object structs
  493. //
  494. if (!CreateObjectStruct (SrcObjectStr, &Ob, WIN95OBJECT)) {
  495. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: %s is not a valid source", SrcObjectStr));
  496. goto c0;
  497. }
  498. Ob.ObjectType &= ~OT_TREE;
  499. if (!CreateObjectStruct (DestObjectStr, &DestOb, WINNTOBJECT)) {
  500. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: %s is not a valid dest", DestObjectStr));
  501. goto c1;
  502. }
  503. if (DestOb.ObjectType & OT_TREE || DestOb.ValueName) {
  504. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: dest %s is not a key only", DestObjectStr));
  505. goto c2;
  506. }
  507. //
  508. // Call RegValFn for all values in the key
  509. //
  510. FilterArg.Tree = FALSE;
  511. FilterArg.RegValFn = (REGVALFN) Data;
  512. fr = CopyObject (&Ob, &DestOb, RegKeyMergeFilter, &FilterArg);
  513. if (fr == FILTER_RETURN_FAIL) {
  514. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: CopyObject failed"));
  515. goto c2;
  516. }
  517. b = TRUE;
  518. c2:
  519. FreeObjectStruct (&DestOb);
  520. c1:
  521. FreeObjectStruct (&Ob);
  522. c0:
  523. return b;
  524. }
  525. BOOL
  526. RuleHlpr_ConvertRegTree (
  527. IN PCTSTR SrcObjectStr,
  528. IN PCTSTR DestObjectStr,
  529. IN PCTSTR User,
  530. IN PVOID Data
  531. )
  532. {
  533. DATAOBJECT Ob, DestOb;
  534. BOOL b = FALSE;
  535. MERGEFILTERARG FilterArg;
  536. FILTERRETURN fr;
  537. //
  538. // Create object structs
  539. //
  540. if (!CreateObjectStruct (SrcObjectStr, &Ob, WIN95OBJECT)) {
  541. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: %s is not a valid source", SrcObjectStr));
  542. goto c0;
  543. }
  544. Ob.ObjectType |= OT_TREE;
  545. if (!CreateObjectStruct (DestObjectStr, &DestOb, WINNTOBJECT)) {
  546. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: %s is not a valid dest", DestObjectStr));
  547. goto c1;
  548. }
  549. //
  550. // Call RegValFn for all subkeys and values in the key
  551. //
  552. FilterArg.Tree = TRUE;
  553. FilterArg.RegValFn = (REGVALFN) Data;
  554. fr = CopyObject (&Ob, &DestOb, RegKeyMergeFilter, &FilterArg);
  555. if (fr == FILTER_RETURN_FAIL) {
  556. DEBUGMSG ((DBG_WARNING, "RuleHlpr_ConvertRegKey: CopyObject failed"));
  557. goto c2;
  558. }
  559. b = TRUE;
  560. c2:
  561. FreeObjectStruct (&DestOb);
  562. c1:
  563. FreeObjectStruct (&Ob);
  564. c0:
  565. return b;
  566. }
  567. BOOL
  568. ValFn_ConvertToDword (
  569. PDATAOBJECT ObPtr
  570. )
  571. {
  572. DWORD d;
  573. if (!GetDwordFromObject (ObPtr, &d)) {
  574. SetLastError(ERROR_SUCCESS);
  575. return FALSE;
  576. }
  577. if (ReplaceValue (ObPtr, (PBYTE) &d, sizeof (d))) {
  578. ObPtr->ObjectType |= OT_REGISTRY_TYPE;
  579. ObPtr->Type = REG_DWORD;
  580. return TRUE;
  581. }
  582. return FALSE;
  583. }
  584. BOOL
  585. ValFn_ConvertToString (
  586. PDATAOBJECT ObPtr
  587. )
  588. {
  589. PCTSTR result;
  590. result = GetStringFromObject (ObPtr);
  591. if (!result) {
  592. SetLastError(ERROR_SUCCESS);
  593. return FALSE;
  594. }
  595. if (ReplaceValueWithString (ObPtr, result)) {
  596. ObPtr->ObjectType |= OT_REGISTRY_TYPE;
  597. ObPtr->Type = REG_SZ;
  598. FreePathString (result);
  599. return TRUE;
  600. }
  601. FreePathString (result);
  602. return FALSE;
  603. }
  604. BOOL
  605. ValFn_AddSharedDlls (
  606. IN OUT PDATAOBJECT ObPtr
  607. )
  608. {
  609. DWORD d, d2;
  610. DATAOBJECT NtOb;
  611. PTSTR TempValueName;
  612. CONVERTPATH_RC C_Result;
  613. BOOL Result = TRUE;
  614. if (!GetDwordFromObject (ObPtr, &d)) {
  615. SetLastError(ERROR_SUCCESS);
  616. return FALSE;
  617. }
  618. if (!DuplicateObjectStruct (&NtOb, ObPtr)) {
  619. return FALSE;
  620. }
  621. SetPlatformType (&NtOb, WINNTOBJECT);
  622. if (GetDwordFromObject (&NtOb, &d2)) {
  623. d += d2;
  624. }
  625. FreeObjectStruct (&NtOb);
  626. ObPtr->Type = REG_DWORD;
  627. TempValueName = MemAlloc (g_hHeap, 0, MAX_TCHAR_PATH * sizeof (TCHAR));
  628. __try {
  629. StringCopy (TempValueName, (PTSTR) ObPtr->ValueName);
  630. C_Result = ConvertWin9xPath ((PTSTR) TempValueName);
  631. switch (C_Result) {
  632. case CONVERTPATH_DELETED:
  633. //
  634. // nothing to do
  635. //
  636. SetLastError (ERROR_SUCCESS);
  637. break;
  638. case CONVERTPATH_NOT_REMAPPED:
  639. //
  640. // just changing the value
  641. //
  642. d -= 1;
  643. Result = ReplaceValue (ObPtr, (PBYTE) &d, sizeof (d));
  644. break;
  645. default:
  646. //
  647. // we have to change value name and we'll have to do it by ourselves
  648. // actually value name has been already changed by calling ConvertWin9xPath
  649. // so just changing the value and writting the object
  650. //
  651. Result = Result && SetPlatformType (ObPtr, WINNTOBJECT);
  652. Result = Result && SetRegistryValueName (ObPtr, TempValueName);
  653. Result = Result && ReplaceValue (ObPtr, (PBYTE) &d, sizeof (d));
  654. Result = Result && WriteObject(ObPtr);
  655. if (!Result) {
  656. // we had an error somewhere so sending this to the log.
  657. LOG ((LOG_ERROR, "The SharedDll reference count cannot be updated"));
  658. }
  659. SetLastError (ERROR_SUCCESS);
  660. break;
  661. }
  662. }
  663. __finally {
  664. MemFree (g_hHeap, 0, TempValueName);
  665. }
  666. return Result;
  667. }
  668. #define S_INDEO_KEYDES TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\drivers.desc")
  669. #define S_INDEO_KEYDRV TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32")
  670. #define S_INDEO_DESCR TEXT("description")
  671. #define S_INDEO_DRIVER TEXT("driver")
  672. BOOL
  673. ValFn_ConvertIndeoSettings (
  674. PDATAOBJECT ObPtr
  675. )
  676. {
  677. PCTSTR KeyName;
  678. DATAOBJECT TmpObj;
  679. BOOL Result = TRUE;
  680. //
  681. // we are interested only in "drivers" and "description" value names.
  682. // Everything else is suppressed. So, we are going to return false
  683. // setting Error_Success in order to be sure that no value is migrated.
  684. // For those particular value names ("drivers" and "description") we
  685. // are going to migrate them directly by writing a NT Object.
  686. //
  687. if (StringIMatch (ObPtr->ValueName, S_INDEO_DRIVER)) {
  688. // extracting the last part of the key path
  689. KeyName = _tcsrchr (ObPtr->KeyPtr->KeyString, TEXT('\\'));
  690. if (!KeyName) {
  691. KeyName = ObPtr->KeyPtr->KeyString;
  692. }
  693. else {
  694. KeyName++;
  695. }
  696. // converting to WinNtObject, modifying and writing the registry key.
  697. Result = Result && SetPlatformType (ObPtr, WINNTOBJECT);
  698. Result = Result && SetRegistryValueName (ObPtr, KeyName);
  699. Result = Result && SetRegistryKey (ObPtr, S_INDEO_KEYDRV);
  700. Result = Result && WriteObject(ObPtr);
  701. }
  702. else
  703. if (StringIMatch (ObPtr->ValueName, S_INDEO_DESCR)) {
  704. // searching for a particular value name in Win95 key
  705. Result = Result && DuplicateObjectStruct (&TmpObj, ObPtr);
  706. if (Result) {
  707. FreeObjectVal (&TmpObj);
  708. Result = Result && SetRegistryValueName (&TmpObj, S_INDEO_DRIVER);
  709. if (ReadObject (&TmpObj)) {
  710. // converting to WinNtObject, modifying and writing the registry key.
  711. Result = Result && SetPlatformType (ObPtr, WINNTOBJECT);
  712. Result = Result && SetRegistryValueName (ObPtr, (PCTSTR)TmpObj.Value.Buffer);
  713. Result = Result && SetRegistryKey (ObPtr, S_INDEO_KEYDES);
  714. Result = Result && WriteObject(ObPtr);
  715. }
  716. FreeObjectStruct (&TmpObj);
  717. }
  718. }
  719. if (!Result) {
  720. // we had an error somewhere so sending this to the log.
  721. LOG ((LOG_ERROR, "Intel Indeo settings could not be migrated"));
  722. }
  723. SetLastError (ERROR_SUCCESS);
  724. return FALSE;
  725. }
  726. BOOL
  727. RuleHlpr_ConvertKeysToValues (
  728. IN PCTSTR SrcObjectStr,
  729. IN PCTSTR DestObjectStr,
  730. IN PCTSTR User,
  731. IN PVOID Data
  732. )
  733. {
  734. BOOL rSuccess = TRUE;
  735. FILTERRETURN fr;
  736. DATAOBJECT srcObject;
  737. DATAOBJECT dstObject;
  738. KEYTOVALUEARG args;
  739. //
  740. // We need to enumerate all keys in SrcObjectStr. For each key,
  741. // we will change the subkey to a value.
  742. //
  743. __try {
  744. ZeroMemory (&srcObject, sizeof (DATAOBJECT));
  745. ZeroMemory (&dstObject, sizeof (DATAOBJECT));
  746. if (!CreateObjectStruct (SrcObjectStr, &srcObject, WIN95OBJECT)) {
  747. DEBUGMSG ((DBG_WARNING, "ConvertKeysToValues: %s is invalid", SrcObjectStr));
  748. return FALSE;
  749. }
  750. if (!(srcObject.ObjectType & OT_TREE)) {
  751. DEBUGMSG ((DBG_WARNING, "ConvertKeysToValues: %s does not specify subkeys -- skipping rule", SrcObjectStr));
  752. return TRUE;
  753. }
  754. DuplicateObjectStruct (&dstObject, &srcObject);
  755. SetPlatformType (&dstObject, WINNTOBJECT);
  756. ZeroMemory(&args,sizeof(KEYTOVALUEARG));
  757. DuplicateObjectStruct(&(args.Object),&dstObject);
  758. fr = CopyObject (&srcObject, &dstObject, pConvertKeysToValuesFilter,&args);
  759. FreeObjectStruct(&(args.Object));
  760. DEBUGMSG_IF((fr == FILTER_RETURN_FAIL,DBG_WHOOPS,"ConvertKeysToValues: CopyObject returned false."));
  761. }
  762. __finally {
  763. FreeObjectStruct (&dstObject);
  764. FreeObjectStruct (&srcObject);
  765. }
  766. SetLastError(ERROR_SUCCESS);
  767. return rSuccess;
  768. }
  769. FILTERRETURN
  770. pRunKeyFilter (
  771. IN CPDATAOBJECT SrcObjectPtr,
  772. IN CPDATAOBJECT DestObjectPtr,
  773. IN FILTERTYPE FilterType,
  774. IN PVOID FilterArg
  775. )
  776. {
  777. TCHAR key [MEMDB_MAX];
  778. DATAOBJECT destOb;
  779. BOOL b = FALSE;
  780. PTSTR path = NULL;
  781. UINT len;
  782. DWORD status;
  783. BOOL knownGood = FALSE;
  784. BOOL knownBad = FALSE;
  785. FILTERRETURN fr;
  786. fr = Standard9xSuppressFilter (SrcObjectPtr, DestObjectPtr, FilterType, FilterArg);
  787. if (fr != FILTER_RETURN_CONTINUE) {
  788. DEBUGMSG ((
  789. DBG_NAUSEA,
  790. "The following Run key was suppressed: %s",
  791. DEBUGENCODER (SrcObjectPtr)
  792. ));
  793. return fr;
  794. }
  795. switch (FilterType) {
  796. case FILTER_CREATE_KEY:
  797. case FILTER_KEY_ENUM:
  798. case FILTER_PROCESS_VALUES:
  799. case FILTER_VALUENAME_ENUM:
  800. break;
  801. case FILTER_VALUE_COPY:
  802. __try {
  803. //
  804. // Is expected value data?
  805. //
  806. if (SrcObjectPtr->Type != REG_SZ) {
  807. DEBUGMSG ((
  808. DBG_NAUSEA,
  809. "The following Run key is not REG_SZ: %s",
  810. DEBUGENCODER (SrcObjectPtr)
  811. ));
  812. __leave;
  813. }
  814. //
  815. // Is this Run key known good?
  816. //
  817. MemDbBuildKey (
  818. key,
  819. MEMDB_CATEGORY_COMPATIBLE_RUNKEY_NT,
  820. SrcObjectPtr->ValueName,
  821. NULL,
  822. NULL
  823. );
  824. knownGood = MemDbGetValue (key, NULL);
  825. //
  826. // Is value name known bad?
  827. //
  828. MemDbBuildKey (
  829. key,
  830. MEMDB_CATEGORY_INCOMPATIBLE_RUNKEY_NT,
  831. SrcObjectPtr->ValueName,
  832. NULL,
  833. NULL
  834. );
  835. knownBad = MemDbGetValue (key, NULL);
  836. //
  837. // Is target known bad? We need to check the string, which is a command line.
  838. // If it points to anything deleted, then it is bad.
  839. //
  840. // NOTE: Data in DestObjectPtr is already converted to NT
  841. //
  842. if (!knownBad) {
  843. len = SrcObjectPtr->Value.Size / sizeof (TCHAR);
  844. len = min (len, MAX_CMDLINE);
  845. path = AllocPathString (len + 1);
  846. CopyMemory (path, SrcObjectPtr->Value.Buffer, len * sizeof (TCHAR));
  847. path[len] = 0;
  848. ConvertWin9xCmdLine (path, NULL, &knownBad);
  849. }
  850. //
  851. // If it is known good, write it to the same location as it was on Win9x.
  852. // If it is known bad, skip it.
  853. // If it is unknown, leave it, relying in INF to move it.
  854. //
  855. if (!knownGood && knownBad) {
  856. DEBUGMSG ((
  857. DBG_NAUSEA,
  858. "The following Run key is known bad: %s",
  859. DEBUGENCODER (SrcObjectPtr)
  860. ));
  861. } else {
  862. //
  863. // Create a destination object. The inbound dest object
  864. // (DestObjectPtr) does not yet have a value. It does
  865. // have other information, such as a destination
  866. // registry key.
  867. //
  868. // The source object has a value, and it was filtered already
  869. // (it has NT paths).
  870. //
  871. if (!DuplicateObjectStruct (&destOb, DestObjectPtr)) {
  872. fr = FILTER_RETURN_FAIL;
  873. }
  874. SetPlatformType (&destOb, WINNTOBJECT);
  875. if (ReplaceValue (&destOb, SrcObjectPtr->Value.Buffer, SrcObjectPtr->Value.Size)) {
  876. destOb.ObjectType |= OT_REGISTRY_TYPE;
  877. destOb.Type = SrcObjectPtr->Type;
  878. }
  879. //
  880. // Now output the object. Either write it to the expected
  881. // destination (known good case) or redirect it to the setup
  882. // key (unknown case).
  883. //
  884. if (knownGood) {
  885. DEBUGMSG ((
  886. DBG_NAUSEA,
  887. "The following Run key is known good: %s",
  888. DEBUGENCODER (SrcObjectPtr)
  889. ));
  890. } else {
  891. DEBUGMSG ((
  892. DBG_NAUSEA,
  893. "The following Run key is unknown: %s",
  894. DEBUGENCODER (SrcObjectPtr)
  895. ));
  896. //
  897. // Redirect to Windows\CurrentVersion\Setup\DisabledRunKeys
  898. //
  899. SetRegistryKey (
  900. &destOb,
  901. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\DisabledRunKeys")
  902. );
  903. }
  904. b = WriteObject (&destOb);
  905. FreeObjectStruct (&destOb);
  906. if (!b) {
  907. return FILTER_RETURN_FAIL;
  908. }
  909. }
  910. fr = FILTER_RETURN_HANDLED;
  911. }
  912. __finally {
  913. FreePathString (path);
  914. }
  915. return fr;
  916. }
  917. return FILTER_RETURN_CONTINUE;
  918. }
  919. BOOL
  920. RuleHlpr_ValidateRunKey (
  921. IN PCTSTR SrcObjectStr,
  922. IN PCTSTR DestObjectStr,
  923. IN PCTSTR User,
  924. IN PVOID Data
  925. )
  926. {
  927. DATAOBJECT runKeyOb;
  928. DATAOBJECT destOb;
  929. BOOL b = FALSE;
  930. //
  931. // We need to enumerate all values in SrcObjectStr. For each key,
  932. // we examine the default Win9x value, which may cause us to change
  933. // the default value, or skip the key altogether.
  934. //
  935. __try {
  936. ZeroMemory (&runKeyOb, sizeof (DATAOBJECT));
  937. ZeroMemory (&destOb, sizeof (DATAOBJECT));
  938. DEBUGMSG ((DBG_VERBOSE, "ValidateRunKey: Processing %s", SrcObjectStr));
  939. if (!CreateObjectStruct (SrcObjectStr, &runKeyOb, WIN95OBJECT)) {
  940. DEBUGMSG ((DBG_WARNING, "ValidateRunKey: %s is invalid", SrcObjectStr));
  941. __leave;
  942. }
  943. if (runKeyOb.ObjectType & OT_TREE) {
  944. DEBUGMSG ((DBG_WARNING, "ValidateRunKey: %s specifies subkeys -- skipping rule", SrcObjectStr));
  945. b = TRUE;
  946. __leave;
  947. }
  948. DuplicateObjectStruct (&destOb, &runKeyOb);
  949. SetPlatformType (&destOb, WINNTOBJECT);
  950. b = CopyObject (&runKeyOb, &destOb, pRunKeyFilter, NULL);
  951. // If there were no entries, return success
  952. if (!b) {
  953. if (GetLastError() == ERROR_FILE_NOT_FOUND ||
  954. GetLastError() == ERROR_NO_MORE_ITEMS
  955. ) {
  956. b = TRUE;
  957. }
  958. }
  959. }
  960. __finally {
  961. FreeObjectStruct (&destOb);
  962. FreeObjectStruct (&runKeyOb);
  963. }
  964. return b;
  965. }
  966. BOOL
  967. RuleHlpr_ConvertAppPaths (
  968. IN PCTSTR SrcObjectStr,
  969. IN PCTSTR DestObjectStr,
  970. IN PCTSTR User,
  971. IN PVOID Data
  972. )
  973. /*++
  974. Routine Description:
  975. RuleHlpr_ConvertAppPaths determines if a specific EXE referenced by an App
  976. Paths entry (in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion) has been
  977. moved or deleted.
  978. If the EXE has been moved, the default value is updated to point to the
  979. potentially new directory.
  980. If the EXE has been deleted, the subkey is suppressed from being copied.
  981. This function gets called by the usermig.inf/wkstamig.inf parser, not by
  982. CopyObject. It gets called only once, and it is responsible for transferring
  983. the entire key specified by SrcObjectStr to the key specified by DestObjectStr.
  984. Arguments:
  985. SrcObjectStr - Specifies Win9x registry key being enumerated (copy source)
  986. DestObjectStr - Specifies WinNT registry key (copy destination)
  987. User - Specifies the current user name (or NULL for default)
  988. Data - Specifies caller-supplied data (see table in rulehlpr.c)
  989. Return Value:
  990. Tri-state:
  991. TRUE to continue procesing
  992. FALSE and last error == ERROR_SUCCESS to continue on to the next rule
  993. FALSE and last error != ERROR_SUCCESS if a fatal error occurred
  994. --*/
  995. {
  996. DATAOBJECT AppPathsOb;
  997. DATAOBJECT DestOb;
  998. BOOL b = FALSE;
  999. // If not local machine, don't process
  1000. if (User) {
  1001. SetLastError (ERROR_SUCCESS);
  1002. return FALSE;
  1003. }
  1004. //
  1005. // We need to enumerate all keys in SrcObjectStr. For each key,
  1006. // we examine the default Win9x value, which may cause us to change
  1007. // the default value, or skip the key altogether.
  1008. //
  1009. __try {
  1010. ZeroMemory (&AppPathsOb, sizeof (DATAOBJECT));
  1011. ZeroMemory (&DestOb, sizeof (DATAOBJECT));
  1012. if (!CreateObjectStruct (SrcObjectStr, &AppPathsOb, WIN95OBJECT)) {
  1013. DEBUGMSG ((DBG_WARNING, "ConvertAppPaths: %s is invalid", SrcObjectStr));
  1014. __leave;
  1015. }
  1016. if (!(AppPathsOb.ObjectType & OT_TREE)) {
  1017. DEBUGMSG ((DBG_WARNING, "ConvertAppPaths: %s does not specify subkeys -- skipping rule", SrcObjectStr));
  1018. b = TRUE;
  1019. __leave;
  1020. }
  1021. DuplicateObjectStruct (&DestOb, &AppPathsOb);
  1022. SetPlatformType (&DestOb, WINNTOBJECT);
  1023. b = CopyObject (&AppPathsOb, &DestOb, AppPathsKeyFilter, NULL);
  1024. // If there were no mappings, return success
  1025. if (!b) {
  1026. if (GetLastError() == ERROR_FILE_NOT_FOUND ||
  1027. GetLastError() == ERROR_NO_MORE_ITEMS
  1028. ) {
  1029. b = TRUE;
  1030. }
  1031. }
  1032. }
  1033. __finally {
  1034. FreeObjectStruct (&DestOb);
  1035. FreeObjectStruct (&AppPathsOb);
  1036. }
  1037. return b;
  1038. }
  1039. FILTERRETURN
  1040. pConvertKeysToValuesFilter (
  1041. IN CPDATAOBJECT SrcObject,
  1042. IN CPDATAOBJECT DstObject,
  1043. IN FILTERTYPE Type,
  1044. IN PVOID Arg
  1045. )
  1046. {
  1047. DATAOBJECT newObject;
  1048. PKEYTOVALUEARG keyToValueArgs = (PKEYTOVALUEARG) Arg;
  1049. //
  1050. // We want to create the initial key, but not any of the subkeys.
  1051. //
  1052. if (Type == FILTER_CREATE_KEY) {
  1053. if (keyToValueArgs -> EnumeratingSubKeys) {
  1054. return FILTER_RETURN_HANDLED;
  1055. }
  1056. else {
  1057. return FILTER_RETURN_CONTINUE;
  1058. }
  1059. } else if (Type == FILTER_KEY_ENUM) {
  1060. if (!keyToValueArgs -> EnumeratingSubKeys) {
  1061. keyToValueArgs -> EnumeratingSubKeys = TRUE;
  1062. }
  1063. return FILTER_RETURN_CONTINUE;
  1064. } else if (Type == FILTER_VALUENAME_ENUM && keyToValueArgs -> EnumeratingSubKeys) {
  1065. if (!*SrcObject -> ValueName) {
  1066. return FILTER_RETURN_CONTINUE;
  1067. }
  1068. ELSE_DEBUGMSG((DBG_WHOOPS,"ConvertKeysToValues: Unexpected value names."));
  1069. return FILTER_RETURN_HANDLED;
  1070. }
  1071. else if (Type == FILTER_VALUE_COPY && keyToValueArgs -> EnumeratingSubKeys) {
  1072. //
  1073. // If this is the default value, we have the information we need to create the value for this.
  1074. //
  1075. if (!*SrcObject -> ValueName) {
  1076. DuplicateObjectStruct(&newObject,&(keyToValueArgs -> Object));
  1077. SetRegistryValueName(&newObject,_tcsrchr(SrcObject -> KeyPtr -> KeyString,TEXT('\\')) + 1);
  1078. ReplaceValueWithString(&newObject,(PTSTR)SrcObject -> Value.Buffer);
  1079. SetRegistryType(&newObject,REG_SZ);
  1080. WriteObject (&newObject);
  1081. FreeObjectStruct (&newObject);
  1082. }
  1083. ELSE_DEBUGMSG((DBG_WHOOPS,"ConvertKeysToValues: Unexpected value names.."));
  1084. return FILTER_RETURN_HANDLED;
  1085. }
  1086. return FILTER_RETURN_CONTINUE;
  1087. }
  1088. FILTERRETURN
  1089. StringReplaceFilter (
  1090. IN CPDATAOBJECT SrcObjectPtr,
  1091. IN CPDATAOBJECT DestObjectPtr,
  1092. IN FILTERTYPE FilterType,
  1093. IN PVOID FilterArg
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. StringReplaceFilter processes all values that pass through it, searching
  1098. and replacing based on the filter arg (a STRINGREPLACEARGS struct).
  1099. Arguments:
  1100. SrcObjectPtr - Specifies Win9x registry key being enumerated (copy source)
  1101. DestObjectPtr - Specifies WinNT registry key (copy destination)
  1102. FilterType - Specifies the reason the filter is being called
  1103. FilterArg - Sepcifies a STIRNGREPLACEARGS struct.
  1104. Return Value:
  1105. FILTER_RETURN_FAIL for failures
  1106. FILTER_RETURN_CONTINUE otherwise.
  1107. --*/
  1108. {
  1109. PSTRINGREPLACEARGS Args;
  1110. PCTSTR NewString;
  1111. DATAOBJECT NewDestOb;
  1112. FILTERRETURN fr = FILTER_RETURN_CONTINUE;
  1113. Args = (PSTRINGREPLACEARGS) FilterArg;
  1114. if (FilterType == FILTER_VALUE_COPY) {
  1115. if (SrcObjectPtr->Type == REG_SZ) {
  1116. //
  1117. // Get a new string
  1118. //
  1119. NewString = StringSearchAndReplace (
  1120. (PCTSTR) SrcObjectPtr->Value.Buffer,
  1121. Args->Old,
  1122. Args->New
  1123. );
  1124. if (NewString && !StringMatch (NewString, (PCTSTR) SrcObjectPtr->Value.Buffer)) {
  1125. //
  1126. // Here's the offical way to change the value of an object, and
  1127. // then save the changes:
  1128. //
  1129. DuplicateObjectStruct (&NewDestOb, DestObjectPtr);
  1130. ReplaceValueWithString (&NewDestOb, NewString);
  1131. WriteObject (&NewDestOb);
  1132. FreeObjectStruct (&NewDestOb);
  1133. //
  1134. // In the case above, I could have optimized by replacing
  1135. // the value of the SrcObjectPtr, but the SrcObjectPtr is
  1136. // typed as const because it is unsafe to replace other
  1137. // parts of it, such as the value name, key handle, and
  1138. // so on.
  1139. //
  1140. // We end up paying a little extra for the DuplicateObjectStruct
  1141. // call, but it's not very expensive.
  1142. //
  1143. // Do not carry out the copy -- we just did it ourselves
  1144. fr = FILTER_RETURN_HANDLED;
  1145. }
  1146. FreePathString (NewString);
  1147. }
  1148. }
  1149. return fr;
  1150. }
  1151. FILTERRETURN
  1152. AppPathsKeyFilter (
  1153. IN CPDATAOBJECT SrcObjectPtr,
  1154. IN CPDATAOBJECT DestObjectPtr,
  1155. IN FILTERTYPE FilterType,
  1156. IN PVOID FilterArg
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. AppPathsKeyFilter is called for every subkey under
  1161. HKLM\Software\Microsoft\Windows\CurrentVersion\AppPaths
  1162. We determine if the key needs to be copied by examining the default value
  1163. of the key. If the value points to a deleted EXE, AppPathsKeyFilter
  1164. returns FILTER_RETURN_HANDLED. If the value points to a moved EXE, the
  1165. values are updated to use the new path.
  1166. If this routine is called for anything other than FILTER_KEY_ENUM, we
  1167. return FILTER_RETURN_HANDLED, so garbage values and subkeys don't get
  1168. processed.
  1169. Arguments:
  1170. SrcObjectPtr - Specifies Win9x registry key being enumerated (copy source)
  1171. DestObjectPtr - Specifies WinNT registry key (copy destination)
  1172. FilterType - Specifies the reason the filter is being called
  1173. FilterArg - Caller's arg passed in to CopyObject
  1174. Return Value:
  1175. FILTER_RETURN_FAIL for failures
  1176. FILTER_RETURN_HANDLED to skip all sub keys, values, etc.
  1177. --*/
  1178. {
  1179. DATAOBJECT LocalObject;
  1180. PCTSTR DefaultValue;
  1181. DWORD Status;
  1182. TCHAR NewPath[MEMDB_MAX];
  1183. FILTERRETURN fr;
  1184. PCTSTR p, q;
  1185. PCTSTR Start;
  1186. UINT SysDirTchars;
  1187. GROWBUFFER Buf = GROWBUF_INIT;
  1188. WCHAR c;
  1189. fr = Standard9xSuppressFilter (SrcObjectPtr, DestObjectPtr, FilterType, FilterArg);
  1190. if (fr != FILTER_RETURN_CONTINUE) {
  1191. DEBUGMSG ((
  1192. DBG_NAUSEA,
  1193. "The following AppPaths key was suppressed: %s",
  1194. DEBUGENCODER (SrcObjectPtr)
  1195. ));
  1196. return fr;
  1197. }
  1198. //
  1199. // Do not create an empty key -- we might want to suppress it
  1200. //
  1201. if (FilterType == FILTER_CREATE_KEY) {
  1202. return FILTER_RETURN_HANDLED;
  1203. }
  1204. //
  1205. // Determine how to handle App Path subkey before processing the values
  1206. //
  1207. else if (FilterType == FILTER_PROCESS_VALUES) {
  1208. //
  1209. // Create object that points to default value
  1210. //
  1211. if (!DuplicateObjectStruct (&LocalObject, SrcObjectPtr)) {
  1212. return FILTER_RETURN_FAIL;
  1213. }
  1214. __try {
  1215. FreeObjectVal (&LocalObject);
  1216. SetRegistryValueName (&LocalObject, S_EMPTY);
  1217. if (!ReadObject (&LocalObject) || LocalObject.Type != REG_SZ) {
  1218. //
  1219. // Maybe this key is garbage and has no default value
  1220. // or the default value is not a string.
  1221. //
  1222. return FILTER_RETURN_CONTINUE;
  1223. }
  1224. DefaultValue = (PCTSTR) LocalObject.Value.Buffer;
  1225. //
  1226. // Skip empty values or big values
  1227. //
  1228. if (*DefaultValue == 0 || (TcharCount (DefaultValue) >= MAX_PATH)) {
  1229. return FILTER_RETURN_CONTINUE;
  1230. }
  1231. Status = GetFileInfoOnNt (DefaultValue, NewPath, MEMDB_MAX);
  1232. //
  1233. // Was the file deleted or moved? If so, abandon the key.
  1234. //
  1235. if (Status & (FILESTATUS_NTINSTALLED|FILESTATUS_DELETED)) {
  1236. return FILTER_RETURN_HANDLED;
  1237. }
  1238. }
  1239. __finally {
  1240. FreeObjectStruct (&LocalObject);
  1241. }
  1242. } else if (FilterType == FILTER_VALUE_COPY) {
  1243. //
  1244. // If we have %windir%\system in the value. If so, change
  1245. // it to %windir%\system32.
  1246. //
  1247. if (!(*SrcObjectPtr->ValueName)) {
  1248. return FILTER_RETURN_CONTINUE;
  1249. }
  1250. if (SrcObjectPtr->Type != REG_SZ && SrcObjectPtr->Type != REG_EXPAND_SZ) {
  1251. return FILTER_RETURN_CONTINUE;
  1252. }
  1253. MYASSERT (DoesObjectHaveValue (SrcObjectPtr));
  1254. Start = (PCTSTR) SrcObjectPtr->Value.Buffer;
  1255. p = _tcsistr (Start, g_SystemDir);
  1256. if (p) {
  1257. SysDirTchars = TcharCount (g_SystemDir);
  1258. do {
  1259. q = p + SysDirTchars;
  1260. //
  1261. // Ignore if text comes after system, and that text
  1262. // is not a semicolon, and is not a wack followed
  1263. // by a semicolon or nul.
  1264. //
  1265. if (*q) {
  1266. c = (WCHAR)_tcsnextc (q);
  1267. if (c == TEXT('\\')) {
  1268. c = (WCHAR)_tcsnextc (q + 1);
  1269. }
  1270. } else {
  1271. c = 0;
  1272. }
  1273. if (!c || c == TEXT(';')) {
  1274. //
  1275. // Replace with system32
  1276. //
  1277. if (Start < p) {
  1278. GrowBufAppendStringAB (&Buf, Start, p);
  1279. }
  1280. GrowBufAppendString (&Buf, g_System32Dir);
  1281. //
  1282. // Continue loop
  1283. //
  1284. Start = q;
  1285. }
  1286. p = _tcsistr (q, g_SystemDir);
  1287. } while (p);
  1288. }
  1289. if (*Start && Buf.End) {
  1290. GrowBufAppendString (&Buf, Start);
  1291. }
  1292. if (Buf.End) {
  1293. //
  1294. // At least one instance of %windir%\system was changed.
  1295. //
  1296. DuplicateObjectStruct (&LocalObject, DestObjectPtr);
  1297. SetRegistryType (&LocalObject, REG_SZ);
  1298. ReplaceValue (&LocalObject, Buf.Buf, Buf.End);
  1299. WriteObject (&LocalObject);
  1300. FreeObjectStruct (&LocalObject);
  1301. fr = FILTER_RETURN_HANDLED;
  1302. } else {
  1303. fr = FILTER_RETURN_CONTINUE;
  1304. }
  1305. FreeGrowBuffer (&Buf);
  1306. return fr;
  1307. }
  1308. return FILTER_RETURN_CONTINUE;
  1309. }
  1310. BOOL
  1311. RuleHlpr_MergeClasses (
  1312. IN PCTSTR SrcObjectStr,
  1313. IN PCTSTR DestObjectStr,
  1314. IN PCTSTR User,
  1315. IN PVOID Data
  1316. )
  1317. {
  1318. DATAOBJECT SrcOb;
  1319. BOOL b;
  1320. TCHAR RegKeyStr[MAX_REGISTRY_KEY];
  1321. if (!CreateObjectStruct (SrcObjectStr, &SrcOb, WIN95OBJECT)) {
  1322. DEBUGMSG ((DBG_WARNING, "MergeClasses: %s is invalid", SrcObjectStr));
  1323. return FALSE;
  1324. }
  1325. if (SrcOb.RootItem) {
  1326. StringCopy (RegKeyStr, GetRootStringFromOffset (SrcOb.RootItem));
  1327. } else {
  1328. RegKeyStr[0] = 0;
  1329. }
  1330. StringCopy (AppendWack (RegKeyStr), SrcOb.KeyPtr->KeyString);
  1331. b = MergeRegistryNode (RegKeyStr, ROOT_BASE);
  1332. if (!b) {
  1333. LOG ((LOG_ERROR, "The merge of HKCR failed; random application problems are likely"));
  1334. }
  1335. return TRUE;
  1336. }
  1337. BOOL
  1338. RuleHlpr_ShellIcons (
  1339. IN PCTSTR SrcObjectStr,
  1340. IN PCTSTR DestObjectStr,
  1341. IN PCTSTR User,
  1342. IN PVOID Data
  1343. )
  1344. {
  1345. DATAOBJECT SrcOb;
  1346. BOOL b;
  1347. TCHAR RegKeyStr[MAX_REGISTRY_KEY];
  1348. if (!CreateObjectStruct (SrcObjectStr, &SrcOb, WIN95OBJECT)) {
  1349. DEBUGMSG ((DBG_WARNING, "ShellIcons: %s is invalid", SrcObjectStr));
  1350. return FALSE;
  1351. }
  1352. if (SrcOb.RootItem) {
  1353. StringCopy (RegKeyStr, GetRootStringFromOffset (SrcOb.RootItem));
  1354. } else {
  1355. RegKeyStr[0] = 0;
  1356. }
  1357. StringCopy (AppendWack (RegKeyStr), SrcOb.KeyPtr->KeyString);
  1358. b = MergeRegistryNode (RegKeyStr, COPY_DEFAULT_ICON);
  1359. if (!b) {
  1360. LOG ((LOG_ERROR, "The migration of some shell icons failed"));
  1361. }
  1362. return TRUE;
  1363. }
  1364. BOOL
  1365. RuleHlpr_MigrateFreeCell (
  1366. IN LPCTSTR SrcObjectStr,
  1367. IN LPCTSTR DestObjectStr,
  1368. IN LPCTSTR User,
  1369. IN LPVOID Data
  1370. )
  1371. {
  1372. DATAOBJECT SrcOb;
  1373. DATAOBJECT DestOb;
  1374. BYTE data[4] = {1,0,0,0};
  1375. ZeroMemory (&SrcOb, sizeof (DATAOBJECT));
  1376. ZeroMemory (&DestOb, sizeof (DATAOBJECT));
  1377. if (!CreateObjectStruct (SrcObjectStr, &SrcOb, WIN95OBJECT)) {
  1378. DEBUGMSG ((DBG_WARNING, "MigrateFreeCell: %s is invalid", SrcObjectStr));
  1379. return TRUE;
  1380. }
  1381. if (!CreateObjectStruct (DestObjectStr, &DestOb, WINNTOBJECT)) {
  1382. DEBUGMSG ((DBG_WARNING, "MigrateFreeCell: %s is invalid", DestObjectStr));
  1383. FreeObjectStruct (&SrcOb);
  1384. return TRUE;
  1385. }
  1386. CopyObject (&SrcOb, &DestOb, NULL, NULL);
  1387. SetRegistryValueName (&DestOb, S_FREECELL_PLAYED);
  1388. SetRegistryType (&DestOb, REG_BINARY);
  1389. ReplaceValue (&DestOb, data, 4);
  1390. WriteObject (&DestOb);
  1391. FreeObjectStruct (&DestOb);
  1392. FreeObjectStruct (&SrcOb);
  1393. return TRUE;
  1394. }
  1395. BOOL
  1396. ValFn_ConvertDarwinPaths (
  1397. PDATAOBJECT ObPtr
  1398. )
  1399. {
  1400. BOOL rSuccess = TRUE;
  1401. PTSTR newPath = NULL;
  1402. DWORD size = 0;
  1403. BOOL flaggedPath = FALSE;
  1404. //
  1405. // Because they do some odd encoding in there
  1406. // paths, we have to ensure that darwin paths are
  1407. // properly updated.
  1408. //
  1409. size = SizeOfString ((PTSTR) ObPtr->Value.Buffer);
  1410. newPath = (PTSTR) ReuseAlloc (g_hHeap, NULL, size);
  1411. if (newPath && size > 1) {
  1412. StringCopy (newPath, (PTSTR) ObPtr->Value.Buffer);
  1413. if (newPath[1] == TEXT('?')) {
  1414. newPath[1] = TEXT(':');
  1415. flaggedPath = TRUE;
  1416. }
  1417. newPath = (PTSTR) FilterRegValue (
  1418. (PBYTE) newPath,
  1419. size,
  1420. REG_SZ,
  1421. TEXT("Darwin"),
  1422. &size
  1423. );
  1424. if (flaggedPath) {
  1425. newPath[1] = TEXT('?');
  1426. }
  1427. ReplaceValueWithString (ObPtr, newPath);
  1428. ReuseFree (g_hHeap, newPath);
  1429. }
  1430. return rSuccess;
  1431. }
  1432. VOID
  1433. pProcessInstallShieldLog (
  1434. IN PCTSTR CmdLine,
  1435. IN PCMDLINE Table
  1436. )
  1437. {
  1438. UINT u;
  1439. PCTSTR LogFileArg;
  1440. TCHAR LogFilePath[MAX_TCHAR_PATH];
  1441. PCSTR AnsiLogFilePath = NULL;
  1442. PCSTR AnsiTempDir = NULL;
  1443. PTSTR p;
  1444. HGLOBAL IsuStringMultiSz = NULL;
  1445. PCSTR MultiSz;
  1446. GROWBUFFER SearchMultiSz = GROWBUF_INIT;
  1447. GROWBUFFER ReplaceMultiSz = GROWBUF_INIT;
  1448. MULTISZ_ENUMA e;
  1449. DWORD Status;
  1450. INT Result;
  1451. PCSTR NtPath;
  1452. PCTSTR Arg;
  1453. BOOL InIsuFn = FALSE;
  1454. //
  1455. // Search for the -f arg
  1456. //
  1457. LogFileArg = NULL;
  1458. for (u = 1 ; u < Table->ArgCount ; u++) {
  1459. Arg = Table->Args[u].CleanedUpArg;
  1460. if (Arg[0] == TEXT('-') || Arg[0] == TEXT('/')) {
  1461. if (_totlower (Arg[1]) == TEXT('f')) {
  1462. if (Arg[2]) {
  1463. LogFileArg = &Arg[2];
  1464. break;
  1465. }
  1466. }
  1467. }
  1468. }
  1469. if (!LogFileArg) {
  1470. DEBUGMSG ((
  1471. DBG_WARNING,
  1472. "InstallShield command line %s does not have -f arg",
  1473. CmdLine
  1474. ));
  1475. return;
  1476. }
  1477. //
  1478. // Fix up the arg
  1479. //
  1480. if (_tcsnextc (LogFileArg) == TEXT('\"')) {
  1481. _tcssafecpy (LogFilePath, LogFileArg + 1, MAX_TCHAR_PATH);
  1482. p = _tcsrchr (LogFilePath, TEXT('\"'));
  1483. if (p && p[1] == 0) {
  1484. *p = 0;
  1485. }
  1486. } else {
  1487. _tcssafecpy (LogFilePath, LogFileArg, MAX_TCHAR_PATH);
  1488. }
  1489. if (!DoesFileExist (LogFilePath)) {
  1490. DEBUGMSG ((
  1491. DBG_WARNING,
  1492. "InstallShield log file %s does not exist. CmdLine=%s",
  1493. LogFilePath,
  1494. CmdLine
  1495. ));
  1496. return;
  1497. }
  1498. //
  1499. // Get the list of strings
  1500. //
  1501. if (!ISUGetAllStrings || !ISUMigrate) {
  1502. DEBUGMSG ((DBG_WARNING, "Can't process %s because ismig.dll was not loaded", LogFilePath));
  1503. return;
  1504. }
  1505. __try {
  1506. __try {
  1507. AnsiLogFilePath = CreateDbcs (LogFilePath);
  1508. InIsuFn = TRUE;
  1509. IsuStringMultiSz = ISUGetAllStrings (AnsiLogFilePath);
  1510. InIsuFn = FALSE;
  1511. if (!IsuStringMultiSz) {
  1512. DEBUGMSG ((
  1513. DBG_WARNING,
  1514. "No strings or error reading %s, rc=%u",
  1515. LogFilePath,
  1516. GetLastError()
  1517. ));
  1518. __leave;
  1519. }
  1520. //
  1521. // Build a list of changed paths
  1522. //
  1523. MultiSz = GlobalLock (IsuStringMultiSz);
  1524. #ifdef DEBUG
  1525. {
  1526. INT Count = 0;
  1527. if (EnumFirstMultiSzA (&e, MultiSz)) {
  1528. do {
  1529. Count++;
  1530. } while (EnumNextMultiSzA (&e));
  1531. }
  1532. DEBUGMSG ((
  1533. DBG_NAUSEA,
  1534. "ISUGetAllStrings returned %i strings for %s",
  1535. Count,
  1536. LogFilePath
  1537. ));
  1538. }
  1539. #endif
  1540. if (EnumFirstMultiSzA (&e, MultiSz)) {
  1541. do {
  1542. Status = GetFileStatusOnNtA (e.CurrentString);
  1543. if (Status & FILESTATUS_MOVED) {
  1544. NtPath = GetPathStringOnNtA (e.CurrentString);
  1545. DEBUGMSGA ((
  1546. DBG_NAUSEA,
  1547. "ISLOG: %s -> %s",
  1548. e.CurrentString,
  1549. NtPath
  1550. ));
  1551. MultiSzAppendA (&SearchMultiSz, e.CurrentString);
  1552. MultiSzAppendA (&ReplaceMultiSz, NtPath);
  1553. FreePathStringA (NtPath);
  1554. }
  1555. } while (EnumNextMultiSzA (&e));
  1556. }
  1557. GlobalUnlock (IsuStringMultiSz);
  1558. //
  1559. // If there was a change, update the log file
  1560. //
  1561. if (SearchMultiSz.End) {
  1562. AnsiTempDir = CreateDbcs (g_TempDir);
  1563. InIsuFn = TRUE;
  1564. Result = ISUMigrate (
  1565. AnsiLogFilePath,
  1566. (PCSTR) SearchMultiSz.Buf,
  1567. (PCSTR) ReplaceMultiSz.Buf,
  1568. AnsiTempDir
  1569. );
  1570. InIsuFn = FALSE;
  1571. DestroyDbcs (AnsiTempDir);
  1572. AnsiTempDir = NULL;
  1573. if (Result != ERROR_SUCCESS) {
  1574. SetLastError (Result);
  1575. DEBUGMSG ((
  1576. DBG_ERROR,
  1577. "Could not update paths in IS log file %s",
  1578. LogFilePath
  1579. ));
  1580. }
  1581. }
  1582. }
  1583. __except (TRUE) {
  1584. DEBUGMSG_IF ((
  1585. InIsuFn,
  1586. DBG_ERROR,
  1587. "An InstallShield function threw an unhandled exception"
  1588. ));
  1589. DEBUGMSG_IF ((
  1590. !InIsuFn,
  1591. DBG_WHOOPS,
  1592. "An unhandled exception was hit processing data returned by InstallShield"
  1593. ));
  1594. if (AnsiTempDir) {
  1595. DestroyDbcs (AnsiTempDir);
  1596. }
  1597. }
  1598. }
  1599. __finally {
  1600. //
  1601. // Clean up
  1602. //
  1603. if (IsuStringMultiSz) {
  1604. GlobalFree (IsuStringMultiSz);
  1605. }
  1606. FreeGrowBuffer (&SearchMultiSz);
  1607. FreeGrowBuffer (&ReplaceMultiSz);
  1608. DestroyDbcs (AnsiLogFilePath);
  1609. }
  1610. return;
  1611. }
  1612. FILTERRETURN
  1613. Standard9xSuppressFilter (
  1614. IN CPDATAOBJECT SrcObject,
  1615. IN CPDATAOBJECT DstObject,
  1616. IN FILTERTYPE FilterType,
  1617. IN PVOID Arg
  1618. )
  1619. {
  1620. TCHAR RegKey[MAX_REGISTRY_KEY];
  1621. switch (FilterType) {
  1622. case FILTER_CREATE_KEY:
  1623. //
  1624. // Before enumerating subkeys and processing values,
  1625. // we first have to create the destination key. This
  1626. // gives us a good opportunity to suppress the
  1627. // entire key if necessary.
  1628. //
  1629. // If the source object tree is suppressed, then
  1630. // don't create the key.
  1631. //
  1632. if (GetRegistryKeyStrFromObject (SrcObject, RegKey)) {
  1633. if (Is95RegKeyTreeSuppressed (RegKey)) {
  1634. //
  1635. // Is this key NT priority? If so, don't suppress.
  1636. //
  1637. if (!IsRegObjectMarkedForOperation (
  1638. RegKey,
  1639. NULL,
  1640. KEY_TREE,
  1641. REGMERGE_NT_PRIORITY_NT
  1642. )) {
  1643. //
  1644. // It's official -- this key tree is suppressed
  1645. //
  1646. return FILTER_RETURN_DONE;
  1647. }
  1648. }
  1649. }
  1650. break;
  1651. case FILTER_KEY_ENUM:
  1652. //
  1653. // This is the case where a subkey was just
  1654. // enumerated. We don't care to test the subkeys,
  1655. // because the FILTER_CREATE_KEY will take care
  1656. // of this next, and we don't want to duplicate the
  1657. // test when the value is not suppressed.
  1658. //
  1659. break;
  1660. case FILTER_PROCESS_VALUES:
  1661. //
  1662. // After a subkey has been enumerated and created,
  1663. // we get a chance to intercept the processing of
  1664. // key values.
  1665. //
  1666. // If the source object is suppressed, and not the
  1667. // entire tree, then don't process its values.
  1668. // However, continue to process the subkeys.
  1669. //
  1670. if (GetRegistryKeyStrFromObject (SrcObject, RegKey)) {
  1671. if (Is95RegKeySuppressed (RegKey)) {
  1672. //
  1673. // Is this key NT priority? If so, don't suppress.
  1674. //
  1675. if (!IsRegObjectMarkedForOperation (
  1676. RegKey,
  1677. NULL,
  1678. KEY_ONLY,
  1679. REGMERGE_NT_PRIORITY_NT
  1680. )) {
  1681. //
  1682. // This key is suppressed
  1683. //
  1684. return FILTER_RETURN_HANDLED;
  1685. }
  1686. }
  1687. }
  1688. break;
  1689. case FILTER_VALUENAME_ENUM:
  1690. //
  1691. // Now we have a specific value name that is ready to
  1692. // be copied to the destination.
  1693. //
  1694. // If the specific source object is suppressed, then
  1695. // don't create the key.
  1696. //
  1697. if (GetRegistryKeyStrFromObject (SrcObject, RegKey)) {
  1698. if (Is95RegObjectSuppressed (RegKey, SrcObject->ValueName)) {
  1699. //
  1700. // Is this key NT priority? If so, don't suppress.
  1701. //
  1702. if (!IsRegObjectMarkedForOperation (
  1703. RegKey,
  1704. SrcObject->ValueName,
  1705. TREE_OPTIONAL,
  1706. REGMERGE_NT_PRIORITY_NT
  1707. )) {
  1708. //
  1709. // This key is suppressed
  1710. //
  1711. return FILTER_RETURN_HANDLED;
  1712. }
  1713. //
  1714. // Yes, this key is NT priority. If the NT value
  1715. // exists, then don't overwrite it.
  1716. //
  1717. if (CheckIfNtKeyExists (DstObject)) {
  1718. return FILTER_RETURN_HANDLED;
  1719. }
  1720. }
  1721. }
  1722. break;
  1723. case FILTER_VALUE_COPY:
  1724. //
  1725. // This is the case where the value is in the process of
  1726. // being copied. We've already handled the suppression,
  1727. // so there is no work here.
  1728. //
  1729. break;
  1730. }
  1731. return FILTER_RETURN_CONTINUE;
  1732. }
  1733. FILTERRETURN
  1734. pNtPreferredSuppressFilter (
  1735. IN CPDATAOBJECT SrcObject,
  1736. IN CPDATAOBJECT DstObject,
  1737. IN FILTERTYPE FilterType,
  1738. IN PVOID Arg
  1739. )
  1740. {
  1741. TCHAR RegKey[MAX_REGISTRY_KEY];
  1742. switch (FilterType) {
  1743. case FILTER_CREATE_KEY:
  1744. //
  1745. // The key is just about to be processed. Since we care
  1746. // only about values, there is no work here.
  1747. //
  1748. break;
  1749. case FILTER_KEY_ENUM:
  1750. //
  1751. // Subkeys are going to be enumerated. We don't care about
  1752. // subkeys.
  1753. //
  1754. break;
  1755. case FILTER_PROCESS_VALUES:
  1756. //
  1757. // We are just about ready to process values within the key.
  1758. // Since we don't have a specific value yet, we don't care.
  1759. //
  1760. break;
  1761. case FILTER_VALUENAME_ENUM:
  1762. //
  1763. // Now we have a specific value name that is ready to be
  1764. // processed. If the value is set for Force NT, and it exists
  1765. // already, then don't process the value.
  1766. //
  1767. if (GetRegistryKeyStrFromObject (SrcObject, RegKey)) {
  1768. if (IsRegObjectMarkedForOperation (
  1769. RegKey,
  1770. SrcObject->ValueName,
  1771. KEY_ONLY,
  1772. REGMERGE_NT_PRIORITY_NT
  1773. )) {
  1774. //
  1775. // If NT destination exists, then don't overwrite it
  1776. //
  1777. if (CheckIfNtKeyExists (SrcObject)) {
  1778. return FILTER_RETURN_HANDLED;
  1779. }
  1780. }
  1781. }
  1782. break;
  1783. case FILTER_VALUE_COPY:
  1784. //
  1785. // This is the case where the value is in the process of
  1786. // being copied. We've already handled the suppression,
  1787. // so there is no work here.
  1788. //
  1789. break;
  1790. }
  1791. return FILTER_RETURN_CONTINUE;
  1792. }
  1793. FILTERRETURN
  1794. pAddRemoveProgramsFilter (
  1795. IN CPDATAOBJECT SrcObject,
  1796. IN CPDATAOBJECT DstObject,
  1797. IN FILTERTYPE FilterType,
  1798. IN PVOID Arg
  1799. )
  1800. {
  1801. DATAOBJECT UninstallStringOb;
  1802. PCTSTR UninstallString;
  1803. FILTERRETURN rc = FILTER_RETURN_CONTINUE;
  1804. GROWBUFFER CmdLineArgs = GROWBUF_INIT;
  1805. PCMDLINE Table;
  1806. BOOL Suppress = TRUE;
  1807. DWORD Status;
  1808. BOOL FreeOb = FALSE;
  1809. UINT u;
  1810. PCTSTR p;
  1811. VERSION_STRUCT Version;
  1812. BOOL InstallShield = FALSE;
  1813. PCTSTR CompanyName;
  1814. FILTERRETURN StdRc;
  1815. __try {
  1816. //
  1817. // Chain to the suppress filter
  1818. //
  1819. StdRc = Standard9xSuppressFilter (SrcObject, DstObject, FilterType, Arg);
  1820. if (StdRc != FILTER_RETURN_CONTINUE) {
  1821. DEBUGMSG ((
  1822. DBG_NAUSEA,
  1823. "The following ARP key was suppressed: %s",
  1824. DEBUGENCODER (SrcObject)
  1825. ));
  1826. rc = StdRc;
  1827. __leave;
  1828. }
  1829. //
  1830. // Do not create an empty key -- we might want to suppress it
  1831. //
  1832. if (FilterType == FILTER_CREATE_KEY) {
  1833. rc = FILTER_RETURN_HANDLED;
  1834. __leave;
  1835. }
  1836. //
  1837. // Determine if Add/Remove Programs is still valid before copying
  1838. //
  1839. if (FilterType == FILTER_PROCESS_VALUES) {
  1840. //
  1841. // Create object that points to UninstallString value
  1842. //
  1843. if (!DuplicateObjectStruct (&UninstallStringOb, SrcObject)) {
  1844. rc = FILTER_RETURN_FAIL;
  1845. __leave;
  1846. }
  1847. FreeOb = TRUE;
  1848. FreeObjectVal (&UninstallStringOb);
  1849. SetRegistryValueName (&UninstallStringOb, TEXT("UninstallString"));
  1850. if (!ReadObject (&UninstallStringOb) || (UninstallStringOb.Type != REG_SZ && UninstallStringOb.Type != REG_EXPAND_SZ)) {
  1851. //
  1852. // Maybe this key is garbage and has no default value
  1853. // or the default value is not a string.
  1854. //
  1855. DEBUGMSG ((
  1856. DBG_WARNING,
  1857. "Uninstall key has no UninstallString: %s",
  1858. DEBUGENCODER (SrcObject)
  1859. ));
  1860. __leave;
  1861. }
  1862. UninstallString = (PCTSTR) UninstallStringOb.Value.Buffer;
  1863. Table = ParseCmdLine (UninstallString, &CmdLineArgs);
  1864. //
  1865. // Check for InstallShield, and if found, convert paths in the
  1866. // log file (provided by the -f arg)
  1867. //
  1868. if (Table->ArgCount > 0) {
  1869. p = GetFileNameFromPath (Table->Args[0].CleanedUpArg);
  1870. if (CreateVersionStruct (&Version, p)) {
  1871. //
  1872. // Check CompanyName for InstallShield
  1873. //
  1874. CompanyName = EnumFirstVersionValue (&Version, TEXT("CompanyName"));
  1875. while (CompanyName) {
  1876. DEBUGMSG ((DBG_NAUSEA, "%s has CompanyName: %s", p, CompanyName));
  1877. if (_tcsistr (CompanyName, TEXT("InstallShield"))) {
  1878. InstallShield = TRUE;
  1879. break;
  1880. }
  1881. CompanyName = EnumNextVersionValue (&Version);
  1882. }
  1883. DestroyVersionStruct (&Version);
  1884. }
  1885. if (InstallShield) {
  1886. pProcessInstallShieldLog (UninstallString, Table);
  1887. }
  1888. }
  1889. //
  1890. // Examine each command line arg for validity
  1891. //
  1892. for (u = 0 ; u < Table->ArgCount ; u++) {
  1893. if (Table->Args[u].Attributes != INVALID_ATTRIBUTES) {
  1894. Suppress = FALSE;
  1895. Status = GetFileStatusOnNt (Table->Args[u].CleanedUpArg);
  1896. if (Status == FILESTATUS_UNCHANGED) {
  1897. p = _tcschr (Table->Args[u].CleanedUpArg, TEXT(':'));
  1898. while (p) {
  1899. p = _tcsdec (Table->Args[u].CleanedUpArg, p);
  1900. Status = GetFileStatusOnNt (Table->Args[u].CleanedUpArg);
  1901. if (Status != FILESTATUS_UNCHANGED) {
  1902. break;
  1903. }
  1904. p = _tcschr (p + 2, TEXT(':'));
  1905. }
  1906. }
  1907. if ((Status & FILESTATUS_DELETED) ||
  1908. ((Status & FILESTATUS_NTINSTALLED) && u)
  1909. ) {
  1910. DEBUGMSG ((
  1911. DBG_VERBOSE,
  1912. "Add/Remove Programs entry %s suppressed because of arg %s",
  1913. DEBUGENCODER (SrcObject),
  1914. Table->Args[u].CleanedUpArg
  1915. ));
  1916. Suppress = TRUE;
  1917. break;
  1918. }
  1919. }
  1920. }
  1921. //
  1922. // If we are to suppress this key, then return handled
  1923. //
  1924. if (Suppress) {
  1925. rc = FILTER_RETURN_HANDLED;
  1926. }
  1927. }
  1928. }
  1929. __finally {
  1930. if (FreeOb) {
  1931. FreeObjectStruct (&UninstallStringOb);
  1932. }
  1933. FreeGrowBuffer (&CmdLineArgs);
  1934. }
  1935. return rc;
  1936. }
  1937. BOOL
  1938. RuleHlpr_MigrateAddRemovePrograms (
  1939. IN PCTSTR SrcObjectStr,
  1940. IN PCTSTR DestObjectStr,
  1941. IN PCTSTR User,
  1942. IN PVOID Data
  1943. )
  1944. {
  1945. DATAOBJECT SrcOb;
  1946. DATAOBJECT DestOb;
  1947. BOOL b = FALSE;
  1948. PCTSTR Path;
  1949. // If not local machine, don't process
  1950. if (User) {
  1951. SetLastError (ERROR_SUCCESS);
  1952. return FALSE;
  1953. }
  1954. //
  1955. // We need to enumerate all keys in SrcObjectStr. For each key,
  1956. // we examine the default Win9x value, which may cause us to change
  1957. // the default value, or skip the key altogether.
  1958. //
  1959. __try {
  1960. ZeroMemory (&SrcOb, sizeof (DATAOBJECT));
  1961. ZeroMemory (&DestOb, sizeof (DATAOBJECT));
  1962. if (!CreateObjectStruct (SrcObjectStr, &SrcOb, WIN95OBJECT)) {
  1963. DEBUGMSG ((DBG_WARNING, "MigrateAddRemovePrograms: %s is invalid", SrcObjectStr));
  1964. __leave;
  1965. }
  1966. if (!(SrcOb.ObjectType & OT_TREE)) {
  1967. DEBUGMSG ((DBG_WARNING, "MigrateAddRemovePrograms %s does not specify subkeys -- skipping rule", SrcObjectStr));
  1968. b = TRUE;
  1969. __leave;
  1970. }
  1971. DuplicateObjectStruct (&DestOb, &SrcOb);
  1972. SetPlatformType (&DestOb, WINNTOBJECT);
  1973. if (!g_ISMigDll) {
  1974. Path = JoinPaths (g_TempDir, TEXT("ismig.dll"));
  1975. g_ISMigDll = LoadLibrary (Path);
  1976. if (g_ISMigDll) {
  1977. ISUMigrate = (PISUMIGRATE) GetProcAddress (g_ISMigDll, "ISUMigrate");
  1978. ISUGetAllStrings = (PISUGETALLSTRINGS) GetProcAddress (g_ISMigDll, "ISUGetAllStrings");
  1979. }
  1980. ELSE_DEBUGMSG ((DBG_ERROR, "Could not load %s", Path));
  1981. }
  1982. FreePathString (Path);
  1983. b = CopyObject (&SrcOb, &DestOb, pAddRemoveProgramsFilter, NULL);
  1984. // If there were no entries, return success
  1985. if (!b) {
  1986. if (GetLastError() == ERROR_FILE_NOT_FOUND ||
  1987. GetLastError() == ERROR_NO_MORE_ITEMS
  1988. ) {
  1989. b = TRUE;
  1990. }
  1991. }
  1992. }
  1993. __finally {
  1994. FreeObjectStruct (&DestOb);
  1995. FreeObjectStruct (&SrcOb);
  1996. if (g_ISMigDll) {
  1997. FreeLibrary (g_ISMigDll);
  1998. g_ISMigDll = NULL;
  1999. }
  2000. }
  2001. return b;
  2002. }
  2003. BOOL
  2004. ValFn_FixActiveDesktop (
  2005. IN OUT PDATAOBJECT ObPtr
  2006. )
  2007. /*++
  2008. Routine Description:
  2009. This routine uses the RuleHlpr_ConvertRegVal simplification routine. See
  2010. rulehlpr.c for details. The simplification routine does almost all the work
  2011. for us; all we need to do is update the value.
  2012. ValFn_AntiAlias checks if ShellState has bogus data. This usually happens when you have
  2013. fresh installed Win98 and you never switched ActiveDesktop on and off. If bogus data is
  2014. found, we writes some valid data so that the state of Active Desktop is preserved during
  2015. migration
  2016. Return Value:
  2017. Tri-state:
  2018. TRUE to allow merge code to continue processing (it writes the value)
  2019. FALSE and last error == ERROR_SUCCESS to continue, but skip the write
  2020. FALSE and last error != ERROR_SUCCESS if an error occurred
  2021. --*/
  2022. {
  2023. #define BadBufferSize 16
  2024. #define GoodBufferSize 28
  2025. BYTE BadBuffer[BadBufferSize] =
  2026. {0x10, 0x00, 0x00, 0x00,
  2027. 0x01, 0x00, 0x00, 0x00,
  2028. 0x00, 0x00, 0x00, 0x00,
  2029. 0x00, 0x00, 0x00, 0x00};
  2030. BYTE GoodBuffer[GoodBufferSize] =
  2031. {0x1C, 0x00, 0x00, 0x00,
  2032. 0x20, 0x08, 0x00, 0x00,
  2033. 0x00, 0x00, 0x00, 0x00,
  2034. 0x00, 0x00, 0x00, 0x00,
  2035. 0x00, 0x00, 0x00, 0x00,
  2036. 0x00, 0x00, 0x00, 0x00,
  2037. 0x0A, 0x00, 0x00, 0x00};
  2038. INT i;
  2039. BOOL shouldChange = TRUE;
  2040. //
  2041. // Require 16 bytes REG_BINARY data like in BadBuffer
  2042. //
  2043. if (!IsObjectRegistryKeyAndVal (ObPtr) ||
  2044. !IsRegistryTypeSpecified (ObPtr) ||
  2045. !ObPtr->Value.Size ||
  2046. (ObPtr->Value.Size != 16) ||
  2047. ObPtr->Type != REG_BINARY
  2048. ) {
  2049. DEBUGMSG ((DBG_WARNING, "ValFn_FixActiveDesktop: Data is not valid"));
  2050. } else {
  2051. for (i = 0; i<BadBufferSize; i++) {
  2052. if (ObPtr->Value.Buffer[i] != BadBuffer [i]) {
  2053. shouldChange = FALSE;
  2054. }
  2055. }
  2056. if (shouldChange) {
  2057. ReplaceValue (ObPtr, GoodBuffer, GoodBufferSize);
  2058. }
  2059. }
  2060. return TRUE;
  2061. }
  2062. //
  2063. // magic values for CD Player Deluxe
  2064. //
  2065. #define PM_BASE 0x8CA0
  2066. #define PM_STANDARD 0x0005
  2067. #define PM_REPEATTRACK 0x0006
  2068. #define PM_REPEATALL 0x0007
  2069. #define PM_RANDOM 0x0008
  2070. #define PM_PREVIEW 0x0009
  2071. #define DM_CDELA 0x0001
  2072. #define DM_CDREM 0x0002
  2073. #define DM_TRELA 0x0004
  2074. #define DM_TRREM 0x0008
  2075. DWORD
  2076. pConvertPlayMode (
  2077. IN PCTSTR OldSetting,
  2078. IN DWORD OldValue
  2079. )
  2080. {
  2081. if (StringIMatch (OldSetting, TEXT("ContinuousPlay"))) {
  2082. //
  2083. // if set, this will become Repeat All
  2084. //
  2085. if (OldValue) {
  2086. return PM_BASE | PM_REPEATALL;
  2087. }
  2088. } else if (StringIMatch (OldSetting, TEXT("InOrderPlay"))) {
  2089. //
  2090. // if not set, this will become Random
  2091. //
  2092. if (OldValue == 0) {
  2093. return PM_BASE | PM_RANDOM;
  2094. }
  2095. } else if (StringIMatch (OldSetting, TEXT("IntroPlay"))) {
  2096. //
  2097. // if set, this will become Preview
  2098. //
  2099. if (OldValue) {
  2100. return PM_BASE | PM_PREVIEW;
  2101. }
  2102. }
  2103. return 0;
  2104. }
  2105. DWORD
  2106. pConvertDispMode (
  2107. IN PCTSTR OldSetting,
  2108. IN DWORD OldValue
  2109. )
  2110. {
  2111. if (StringIMatch (OldSetting, TEXT("DisplayDr"))) {
  2112. //
  2113. // if set, this will become CD Time Elapsed
  2114. //
  2115. if (OldValue) {
  2116. return DM_CDREM;
  2117. }
  2118. } else if (StringIMatch (OldSetting, TEXT("DisplayT"))) {
  2119. //
  2120. // if set, this will become Track Time Elapsed
  2121. //
  2122. if (OldValue) {
  2123. return DM_TRELA;
  2124. }
  2125. } else if (StringIMatch (OldSetting, TEXT("DisplayTr"))) {
  2126. //
  2127. // if set, this will become Track Time Remaining
  2128. //
  2129. if (OldValue) {
  2130. return DM_TRREM;
  2131. }
  2132. }
  2133. return 0;
  2134. }
  2135. BOOL
  2136. ValFn_ConvertCDPlayerSettings (
  2137. PDATAOBJECT ObPtr
  2138. )
  2139. {
  2140. DWORD PlayMode;
  2141. DWORD DispMode;
  2142. //
  2143. // all values must be REG_DWORD
  2144. //
  2145. if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE) || ObPtr->Type != REG_DWORD) {
  2146. SetLastError (ERROR_SUCCESS);
  2147. return FALSE;
  2148. }
  2149. PlayMode = pConvertPlayMode (ObPtr->ValueName, *(DWORD*)ObPtr->Value.Buffer);
  2150. if (PlayMode) {
  2151. //
  2152. // set this last option; it will override previously set option
  2153. //
  2154. return ReplaceValue (ObPtr, (PBYTE)&PlayMode, sizeof (PlayMode));
  2155. }
  2156. DispMode = pConvertDispMode (ObPtr->ValueName, *(DWORD*)ObPtr->Value.Buffer);
  2157. if (DispMode) {
  2158. //
  2159. // only one of these options can be set
  2160. //
  2161. return ReplaceValue (ObPtr, (PBYTE)&DispMode, sizeof (DispMode));
  2162. }
  2163. SetLastError (ERROR_SUCCESS);
  2164. return FALSE;
  2165. }