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

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