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.

1991 lines
54 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. migmain.c
  5. Abstract:
  6. Main migration file for Win95 side. Calls all migration functions
  7. Author:
  8. Calin Negreanu (calinn) 09-Feb-1998
  9. Revision History:
  10. jimschm 19-Mar-2001 Removed DVD code
  11. mvander 26-Map-1999 Added GatherDead()
  12. ovidiut 18-May-1999 Enhanced DeleteStaticFiles; added eval fn. support
  13. jimschm 12-May-1999 DVD Video check
  14. marcw 10-Feb-1999 Scan the File system before calling user routines.
  15. jimschm 18-Jan-1999 Added forced-good GUID
  16. jimschm 04-Dec-1998 Added generalized file delete
  17. jimschm 29-Sep-1998 TWAIN and Joystick messages
  18. jimschm 23-Sep-1998 Very early TWAIN check code
  19. jimschm 24-Aug-1998 Support for NT environment vars
  20. marcw 06-Jul-1998 Cleaned up user function processing.
  21. jimschm 06-Jul-1998 Added support for PNP ID attribute
  22. jimschm 30-Apr-1998 global init/termination, icon context
  23. jimschm 25-Feb-1998 Added ProcessUninstallSections
  24. --*/
  25. #include "pch.h"
  26. #include "sysmigp.h"
  27. ICON_EXTRACT_CONTEXT g_IconContext;
  28. /*++
  29. Macro Expansion Lists Description:
  30. The following three lists represent all the function called during the scan page.
  31. MIGMAIN_SYSFIRST_FUNCTIONS are called first, then for each user MIGMAIN_USER_FUNCTIONS
  32. are called and, finally, MIGMAIN_SYSFIRST_FUNCTIONS are called.
  33. Line Syntax:
  34. DEFMAC(Function, MessageId, Critical)
  35. Arguments:
  36. Function - These functions must return DWORD and are called with a request as a parameter,
  37. request that can be either REQUEST_QUERYTICKS (the function should return the
  38. number of ticks it needs) or REQUEST_RUN (the function can actually do it's job).
  39. For user functions there are also three more parameters (UserName, UserAccount,
  40. and a handle to HKCU)
  41. MessageId - This is the message that will be displayed during the run phase for each function.
  42. If a function needs to update the progress bar by itself you should let this
  43. HAS_DYNAMIC_UI_PROCESSING.
  44. Critical - TRUE if the upgrade should be cancelled if an exception is encountered during that function.
  45. Variables Generated From List:
  46. g_FirstSystemRoutines
  47. g_UserRoutines
  48. g_LastSystemRoutines
  49. For accessing the arrays there are the following functions:
  50. PrepareProcessingProgressBar
  51. RunSysFirstMigrationRoutines
  52. RunUserMigrationRoutines
  53. RunSysLastMigrationRoutines
  54. --*/
  55. #define HAS_DYNAMIC_UI_PROCESSING 0
  56. #define MIGMAIN_SYSFIRST_FUNCTIONS \
  57. DEFMAC(PreparePnpIdList, MSG_INITIALIZING, TRUE) \
  58. DEFMAC(PrepareIconList, MSG_INITIALIZING, TRUE) \
  59. DEFMAC(AddDefaultCleanUpDirs, MSG_INITIALIZING, FALSE) \
  60. DEFMAC(DeleteWinDirWackInf, MSG_INITIALIZING, TRUE) \
  61. DEFMAC(HardwareProfileWarning, MSG_INITIALIZING, FALSE) \
  62. DEFMAC(UnsupportedProtocolsWarning, MSG_INITIALIZING, FALSE) \
  63. DEFMAC(SaveMMSettings_System, MSG_INITIALIZING, FALSE) \
  64. DEFMAC(BadNamesWarning, MSG_INITIALIZING, TRUE) \
  65. DEFMAC(InitWin95Registry, MSG_INITIALIZING, TRUE) \
  66. DEFMAC(InitIniProcessing, MSG_INITIALIZING, TRUE) \
  67. DEFMAC(ReadNtFiles, HAS_DYNAMIC_UI_PROCESSING, TRUE) \
  68. DEFMAC(MigrateShellFolders, MSG_INITIALIZING, TRUE) \
  69. DEFMAC(DeleteStaticFiles, MSG_INITIALIZING, FALSE) \
  70. DEFMAC(ProcessDllsOnCd, HAS_DYNAMIC_UI_PROCESSING, TRUE) \
  71. DEFMAC(InitMigDb, MSG_MIGAPP, TRUE) \
  72. DEFMAC(InitHlpProcessing, MSG_MIGAPP, TRUE) \
  73. DEFMAC(ScanFileSystem, HAS_DYNAMIC_UI_PROCESSING, TRUE) \
  74. #define MIGMAIN_USER_FUNCTIONS \
  75. DEFMAC(SaveMMSettings_User, MSG_INITIALIZING, FALSE) \
  76. DEFMAC(ProcessRasSettings, MSG_INITIALIZING, TRUE) \
  77. DEFMAC(ProcessRunKey_User, MSG_INITIALIZING, TRUE) \
  78. #define MIGMAIN_SYSLAST_FUNCTIONS \
  79. DEFMAC(ConditionalIncompatibilities, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  80. DEFMAC(ProcessMigrationSections, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  81. DEFMAC(ProcessAllLocalDlls, HAS_DYNAMIC_UI_PROCESSING, TRUE) \
  82. DEFMAC(MoveSystemRegistry, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  83. DEFMAC(ProcessCompatibleSection, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  84. DEFMAC(CheckNtDirs, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  85. DEFMAC(MoveSystemDir, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  86. DEFMAC(MoveStaticFiles, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  87. DEFMAC(CopyStaticFiles, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  88. DEFMAC(ElevateReportObjects, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  89. DEFMAC(PrepareProcessModules, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  90. DEFMAC(ProcessModules, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  91. DEFMAC(ProcessRunKey, MSG_PROCESSING_SHELL_LINKS, TRUE) \
  92. DEFMAC(ProcessLinks, MSG_PROCESSING_SHELL_LINKS, TRUE) \
  93. DEFMAC(ProcessCPLs, MSG_PROCESSING_SHELL_LINKS, TRUE) \
  94. DEFMAC(ProcessShellSettings, MSG_PROCESSING_SHELL_LINKS, TRUE) \
  95. DEFMAC(TwainCheck, MSG_PROCESSING_SHELL_LINKS, FALSE) \
  96. DEFMAC(ReportIncompatibleJoysticks, MSG_PROCESSING_SHELL_LINKS, FALSE) \
  97. DEFMAC(ProcessDosConfigFiles, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  98. DEFMAC(SuppressOleGuids, HAS_DYNAMIC_UI_PROCESSING, TRUE) \
  99. DEFMAC(SaveShares, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  100. DEFMAC(PreserveShellIcons, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  101. DEFMAC(MoveWindowsIniFiles, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  102. DEFMAC(SaveDosFiles, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  103. DEFMAC(BuildWinntSifFile, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  104. DEFMAC(ProcessMiscMessages, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  105. DEFMAC(AnswerFileDetection, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  106. DEFMAC(ProcessRecycleBins, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  107. DEFMAC(EndMigrationDllProcessing, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  108. DEFMAC(GatherImeInfo, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  109. DEFMAC(ReportMapiIfNotHandled, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  110. DEFMAC(ReportDarwinIfNotHandled, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  111. DEFMAC(CreateFileLists, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  112. DEFMAC(ComputeBackupLayout, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  113. DEFMAC(DetermineSpaceUsage, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  114. DEFMAC(DoneMigDb, MSG_PROCESSING_SYSTEM_FILES, TRUE) \
  115. DEFMAC(GatherDead, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  116. #if 0
  117. //
  118. // the appcompat team doesn't support "APPMIG.INF" any longer
  119. // and they requested us to no longer depend on it
  120. //
  121. DEFMAC(InitAppCompat, MSG_MIGAPP, FALSE) \
  122. DEFMAC(DoneAppCompat, MSG_PROCESSING_SYSTEM_FILES, FALSE) \
  123. #endif
  124. //
  125. // Declare tables of processing structures
  126. //
  127. // Processing functions types
  128. typedef DWORD (MIGMAIN_SYS_PROTOTYPE) (DWORD Request);
  129. typedef MIGMAIN_SYS_PROTOTYPE * MIGMAIN_SYS_FN;
  130. typedef DWORD (MIGMAIN_USER_PROTOTYPE) (DWORD Request, PUSERENUM EnumPtr);
  131. typedef MIGMAIN_USER_PROTOTYPE * MIGMAIN_USER_FN;
  132. // Structure holding state for processing functions
  133. typedef struct {
  134. // One of the two will be NULL, the other will be a valid fn ptr:
  135. MIGMAIN_SYS_FN SysFnPtr;
  136. MIGMAIN_USER_FN UserFnPtr;
  137. DWORD MsgId;
  138. UINT Ticks;
  139. PCTSTR FnName;
  140. GROWBUFFER SliceIdArray;
  141. BOOL Critical;
  142. } PROCESSING_ROUTINE, *PPROCESSING_ROUTINE;
  143. #define PROCESSING_ROUTINE_TERMINATOR {NULL, NULL, 0, 0, NULL, GROWBUF_INIT}
  144. // Declaration of prototypes
  145. #define DEFMAC(fn, MsgId, Critical) MIGMAIN_SYS_PROTOTYPE fn;
  146. MIGMAIN_SYSFIRST_FUNCTIONS
  147. MIGMAIN_SYSLAST_FUNCTIONS
  148. #undef DEFMAC
  149. #define DEFMAC(fn, MsgId, Critical) MIGMAIN_USER_PROTOTYPE fn;
  150. MIGMAIN_USER_FUNCTIONS
  151. #undef DEFMAC
  152. // Declaration of tables
  153. #define DEFMAC(fn, MsgId, Critical) {fn, NULL, MsgId, 0, #fn, GROWBUF_INIT, Critical},
  154. static PROCESSING_ROUTINE g_FirstSystemRoutines[] = {
  155. MIGMAIN_SYSFIRST_FUNCTIONS /* , */
  156. PROCESSING_ROUTINE_TERMINATOR
  157. };
  158. static PROCESSING_ROUTINE g_LastSystemRoutines[] = {
  159. MIGMAIN_SYSLAST_FUNCTIONS /* , */
  160. PROCESSING_ROUTINE_TERMINATOR
  161. };
  162. #undef DEFMAC
  163. #define DEFMAC(fn, MsgId, Critical) {NULL, fn, MsgId, 0, #fn, GROWBUF_INIT, Critical},
  164. static PROCESSING_ROUTINE g_UserRoutines[] = {
  165. MIGMAIN_USER_FUNCTIONS /* , */
  166. PROCESSING_ROUTINE_TERMINATOR
  167. };
  168. #undef DEFMAC
  169. /*++
  170. Macro Expansion Lists Description:
  171. FILESTODELETE_EVALUATION_FUNCTIONS contains a list of functions related with [Delete Files]
  172. section in win95upg.inf; if a file should be conditionally deleted, the corresponding eval
  173. function is called; if it returns TRUE and the result is not negated or if it returns FALSE
  174. and the result is negated, then the file is deleted.
  175. (see comments in win95upg.inx\[Delete Files])
  176. Line Syntax:
  177. DEFMAC(Function)
  178. Arguments:
  179. Function - Name of an evaluation function; it receives as a parameter the name of
  180. the file for which it is called
  181. Variables Generated From List:
  182. g_MapNameToEvalFn
  183. For accessing the arrays there are the following functions:
  184. pFindEvalFnByName
  185. --*/
  186. #define FILESTODELETE_EVALUATION_FUNCTIONS \
  187. DEFMAC(Boot16Enabled) \
  188. DEFMAC(DoesRegKeyValuesExist) \
  189. DEFMAC(IsMillennium) \
  190. //
  191. // define function prototipes
  192. //
  193. typedef BOOL (EVALFN) (IN PCTSTR PathToEval, IN OUT PINFSTRUCT InfStruct, IN UINT FirstArgIndex);
  194. typedef EVALFN* PEVALFN;
  195. #define DEFMAC(Fn) EVALFN Fn;
  196. FILESTODELETE_EVALUATION_FUNCTIONS
  197. #undef DEFMAC
  198. //
  199. // define the mapping structure
  200. //
  201. typedef struct {
  202. PCTSTR FnName;
  203. PEVALFN EvalFn;
  204. } MAP_NAME_TO_EVALFN;
  205. #define DEFMAC(Fn) TEXT(#Fn), Fn,
  206. static MAP_NAME_TO_EVALFN g_MapNameToEvalFn[] = {
  207. FILESTODELETE_EVALUATION_FUNCTIONS
  208. NULL, NULL
  209. };
  210. #undef DEFMAC
  211. typedef SYNCENGAPI TWINRESULT (WINAPI *POPENBRIEFCASE) (LPCTSTR, DWORD, HWND, PHBRFCASE);
  212. typedef SYNCENGAPI TWINRESULT (WINAPI *PANYTWINS)(HBRFCASE, PBOOL);
  213. typedef SYNCENGAPI TWINRESULT (WINAPI *PCLOSEBRIEFCASE)(HBRFCASE);
  214. //
  215. // Local private prototypes
  216. //
  217. VOID
  218. pGlobalProcessingInit (
  219. VOID
  220. );
  221. VOID
  222. pGlobalProcessingTerminate (
  223. VOID
  224. );
  225. VOID
  226. pWriteAccountToMemDb (
  227. PUSERENUM EnumPtr
  228. );
  229. //
  230. // Implementation
  231. //
  232. VOID
  233. pInitTable (
  234. PPROCESSING_ROUTINE p
  235. )
  236. {
  237. for ( ; p->SysFnPtr || p->UserFnPtr ; p++) {
  238. p->SliceIdArray.GrowSize = sizeof (DWORD) * 8;
  239. }
  240. }
  241. VOID
  242. InitProcessingTable (
  243. VOID
  244. )
  245. {
  246. pInitTable (g_FirstSystemRoutines);
  247. pInitTable (g_UserRoutines);
  248. pInitTable (g_LastSystemRoutines);
  249. }
  250. VOID
  251. pTerminateTable (
  252. PPROCESSING_ROUTINE p
  253. )
  254. {
  255. for ( ; p->SysFnPtr || p->UserFnPtr ; p++) {
  256. FreeGrowBuffer (&p->SliceIdArray);
  257. }
  258. }
  259. VOID
  260. TerminateProcessingTable (
  261. VOID
  262. )
  263. {
  264. pTerminateTable (g_FirstSystemRoutines);
  265. pTerminateTable (g_UserRoutines);
  266. pTerminateTable (g_LastSystemRoutines);
  267. }
  268. DWORD
  269. pProcessWorker (
  270. IN DWORD Request,
  271. IN PPROCESSING_ROUTINE fn,
  272. IN PUSERENUM EnumPtr OPTIONAL
  273. )
  274. {
  275. DWORD rc;
  276. PDWORD SliceId;
  277. DWORD Size;
  278. //
  279. // If running the function, start the progress bar slice
  280. //
  281. if (Request == REQUEST_RUN) {
  282. if (fn->Ticks == 0) {
  283. return ERROR_SUCCESS;
  284. }
  285. Size = fn->SliceIdArray.End / sizeof (DWORD);
  286. if (fn->SliceIdArray.UserIndex >= Size) {
  287. DEBUGMSG ((DBG_WHOOPS, "pProcessWorker: QUERYTICKS vs. RUN mismatch"));
  288. return ERROR_SUCCESS;
  289. }
  290. SliceId = (PDWORD) fn->SliceIdArray.Buf + fn->SliceIdArray.UserIndex;
  291. fn->SliceIdArray.UserIndex += 1;
  292. //
  293. // Set the progress bar title
  294. //
  295. if (fn->MsgId) {
  296. ProgressBar_SetComponentById (fn->MsgId);
  297. ProgressBar_SetSubComponent (NULL);
  298. }
  299. ProgressBar_SetFnName (fn->FnName);
  300. BeginSliceProcessing (*SliceId);
  301. DEBUGLOGTIME (("Starting function: %s (slice %u)", fn->FnName, *SliceId));
  302. }
  303. __try {
  304. //
  305. // Now call the function
  306. //
  307. if (fn->SysFnPtr) {
  308. //
  309. // System processing
  310. //
  311. rc = fn->SysFnPtr (Request);
  312. } else {
  313. //
  314. // User processing
  315. //
  316. MYASSERT (EnumPtr || Request == REQUEST_BEGINUSERPROCESSING || Request == REQUEST_ENDUSERPROCESSING);
  317. MYASSERT (fn->UserFnPtr);
  318. rc = fn->UserFnPtr (Request, EnumPtr);
  319. }
  320. #ifdef DEBUG
  321. if (!g_ConfigOptions.Fast) {
  322. TCHAR dbgBuf[256];
  323. PTSTR BadPtr = NULL;
  324. if (GetPrivateProfileString ("Exception", fn->FnName, "", dbgBuf, 256, g_DebugInfPath)) {
  325. StringCopy (BadPtr, TEXT("Blow Up!!"));
  326. }
  327. }
  328. #endif
  329. }
  330. __except (1) {
  331. //
  332. // Caught an exception..
  333. //
  334. LOG ((LOG_WARNING, "Function %s threw an exception.", fn->FnName));
  335. SafeModeExceptionOccured ();
  336. if (fn->Critical && Request == REQUEST_RUN) {
  337. //
  338. // Since this was a critical function, inform the user and tank the upgrade.
  339. //
  340. SetLastError (ERROR_NOACCESS);
  341. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_UNEXPECTED_ERROR_ENCOUNTERED, GetLastError()));
  342. pGlobalProcessingTerminate();
  343. rc = ERROR_CANCELLED;
  344. }
  345. }
  346. if (CANCELLED()) {
  347. rc = ERROR_CANCELLED;
  348. }
  349. //
  350. // If running the function, end the progress bar slice
  351. //
  352. if (Request == REQUEST_RUN) {
  353. DEBUGLOGTIME (("Function complete: %s", fn->FnName));
  354. EndSliceProcessing();
  355. if (rc != ERROR_SUCCESS) {
  356. pGlobalProcessingTerminate();
  357. if (!CANCELLED()) {
  358. LOG ((LOG_ERROR, "Failure in %s, rc=%u", fn->FnName, rc));
  359. }
  360. ELSE_DEBUGMSG ((DBG_VERBOSE, "Winnt32 was cancelled during %s.", fn->FnName));
  361. }
  362. ProgressBar_ClearFnName();
  363. SetLastError (rc);
  364. }
  365. //
  366. // If querying the ticks, register them and add slice ID to grow buffer
  367. //
  368. else {
  369. fn->Ticks += rc;
  370. SliceId = (PDWORD) GrowBuffer (&fn->SliceIdArray, sizeof (DWORD));
  371. *SliceId = RegisterProgressBarSlice (rc);
  372. rc = ERROR_SUCCESS;
  373. }
  374. return rc;
  375. }
  376. DWORD
  377. pProcessTable (
  378. IN DWORD Request,
  379. IN PPROCESSING_ROUTINE Table
  380. )
  381. /*++
  382. Routine Description:
  383. pProcessTable calls all routines in the specified table to perform
  384. the specified request.
  385. Arguments:
  386. Request - Specifies REQUEST_QUERYTICKS when a tick estimate is needed,
  387. or REQUEST_RUN when the function needs to perform its
  388. processing.
  389. Return Value:
  390. Win32 status code.
  391. --*/
  392. {
  393. PPROCESSING_ROUTINE OrgStart;
  394. DWORD rc = ERROR_SUCCESS;
  395. USERENUM e;
  396. BOOL validUserFound = FALSE;
  397. static BOOL firstTime = TRUE;
  398. while (rc == ERROR_SUCCESS && (Table->SysFnPtr || Table->UserFnPtr)) {
  399. //
  400. // If the table is a system function table or the request is to begin/end user processing,
  401. // then this is the simple case. No enumeration of users is needed.
  402. //
  403. if (Table->SysFnPtr || Request == REQUEST_BEGINUSERPROCESSING || Request == REQUEST_ENDUSERPROCESSING) {
  404. rc = pProcessWorker (Request, Table, NULL);
  405. Table++;
  406. } else {
  407. MYASSERT (Table->UserFnPtr);
  408. //
  409. // Enumerate each user, and run through all the per-user
  410. // routines in the group.
  411. //
  412. OrgStart = Table;
  413. if (EnumFirstUser (&e, ENUMUSER_ENABLE_NAME_FIX)) {
  414. do {
  415. //
  416. // Skip invalid users
  417. //
  418. if (e.AccountType & INVALID_ACCOUNT) {
  419. continue;
  420. }
  421. //
  422. // Create user-specific environment variables
  423. //
  424. InitNtUserEnvironment (&e);
  425. //
  426. // Set global user profile root.
  427. //
  428. g_UserProfileRoot = e.OrgProfilePath;
  429. if (firstTime) {
  430. //
  431. // Log information about the user to the debug log.
  432. //
  433. DEBUGMSG ((
  434. DBG_SYSMIG,
  435. "--- User Info ---\n"
  436. " User Name: %s (%s)\n"
  437. " Admin User Name: %s (%s)\n"
  438. " User Hive: %s\n"
  439. " Profile Dir: %s\n"
  440. " User Hive Key: 0%0Xh\n"
  441. " Win9x Profile Path: %s\n"
  442. " WinNT Profile Path: %s\n"
  443. " Common Profiles: %s\n",
  444. e.UserName,
  445. e.FixedUserName,
  446. e.AdminUserName,
  447. e.FixedAdminUserName,
  448. e.UserDatPath,
  449. e.ProfileDirName,
  450. e.UserRegKey,
  451. e.OrgProfilePath,
  452. e.NewProfilePath,
  453. e.CommonProfilesEnabled ? TEXT("Yes") : TEXT("No")
  454. ));
  455. DEBUGMSG ((
  456. DBG_SYSMIG,
  457. "--- User Flags ---\n"
  458. " Named User: %s\n"
  459. " Default User: %s\n"
  460. " Administrator: %s\n"
  461. " Last Logged On User: %s\n"
  462. " Invalid Account: %s\n"
  463. " Logon Prompt Account: %s\n"
  464. " Current User: %s\n",
  465. e.AccountType & NAMED_USER ? TEXT("Yes") : TEXT("No"),
  466. e.AccountType & DEFAULT_USER ? TEXT("Yes") : TEXT("No"),
  467. e.AccountType & ADMINISTRATOR ? TEXT("Yes") : TEXT("No"),
  468. e.AccountType & LAST_LOGGED_ON_USER ? TEXT("Yes") : TEXT("No"),
  469. e.AccountType & INVALID_ACCOUNT ? TEXT("Yes") : TEXT("No"),
  470. e.AccountType & LOGON_PROMPT ? TEXT("Yes") : TEXT("No"),
  471. e.AccountType & CURRENT_USER ? TEXT("Yes") : TEXT("No")
  472. ));
  473. //
  474. // Special case: record the Administrator/Owner account
  475. //
  476. if ((e.AccountType & (ADMINISTRATOR|NAMED_USER)) == (ADMINISTRATOR|NAMED_USER)) {
  477. //
  478. // Administrator account on machine that has named users
  479. //
  480. MemDbSetValueEx (
  481. MEMDB_CATEGORY_ADMINISTRATOR_INFO, // "AdministratorInfo"
  482. MEMDB_ITEM_AI_ACCOUNT, // "Account"
  483. NULL, // no field
  484. e.FixedAdminUserName, // the Win9x user name
  485. 0,
  486. NULL
  487. );
  488. } else if ((e.AccountType & (ADMINISTRATOR|NAMED_USER|DEFAULT_USER)) ==
  489. (ADMINISTRATOR|DEFAULT_USER)
  490. ) {
  491. //
  492. // Administrator account on machine with no users at all
  493. //
  494. MemDbSetValueEx (
  495. MEMDB_CATEGORY_ADMINISTRATOR_INFO, // "AdministratorInfo"
  496. MEMDB_ITEM_AI_ACCOUNT, // "Account"
  497. NULL, // no field
  498. e.FixedUserName, // "Administrator" or "Owner"
  499. 0,
  500. NULL
  501. );
  502. }
  503. //
  504. // Save user account to memdb
  505. //
  506. pWriteAccountToMemDb(&e);
  507. }
  508. //
  509. // if we have gotten this far, then we have a valid user to process.
  510. //
  511. validUserFound = TRUE;
  512. //
  513. // Call all the user processing functions.
  514. //
  515. DEBUGMSG ((DBG_SYSMIG, "Processing User: %s.", e.UserName ));
  516. for (Table = OrgStart ; Table->UserFnPtr ; Table++) {
  517. if (rc == ERROR_SUCCESS) {
  518. rc = pProcessWorker (Request, Table, &e);
  519. }
  520. }
  521. //
  522. // Clear out the global user profile variable.
  523. //
  524. g_UserProfileRoot = NULL;
  525. //
  526. // Remove user-specific environment variables
  527. //
  528. TerminateNtUserEnvironment();
  529. } while (EnumNextUser (&e));
  530. }
  531. ELSE_DEBUGMSG ((DBG_WARNING, "No active users to process!"));
  532. //
  533. // Inform the user if there were no valid users to process
  534. // (Probably will never happen)
  535. //
  536. if (!validUserFound) {
  537. if (CANCELLED()) {
  538. rc = ERROR_CANCELLED;
  539. } else {
  540. OkBox (g_ParentWnd, MSG_NO_VALID_ACCOUNTS_POPUP);
  541. rc = ERROR_BADKEY;
  542. }
  543. }
  544. //
  545. // Make sure that we have passed all of the user functions in the
  546. // table.
  547. //
  548. while (Table->UserFnPtr) {
  549. Table++;
  550. }
  551. firstTime = FALSE;
  552. }
  553. }
  554. return rc;
  555. }
  556. VOID
  557. PrepareProcessingProgressBar (
  558. VOID
  559. )
  560. /*++
  561. Routine Description:
  562. Prepares the progress bar by estimating the number of ticks for each slice
  563. of the progress bar. pQueryWorker is called for each table of functions
  564. to run during the processing wizard page.
  565. Arguments:
  566. none
  567. Return value:
  568. none
  569. --*/
  570. {
  571. pGlobalProcessingInit();
  572. InitProcessingTable();
  573. pProcessTable (REQUEST_QUERYTICKS, g_FirstSystemRoutines);
  574. pProcessTable (REQUEST_QUERYTICKS, g_UserRoutines);
  575. pProcessTable (REQUEST_QUERYTICKS, g_LastSystemRoutines);
  576. }
  577. DWORD
  578. RunSysFirstMigrationRoutines (
  579. VOID
  580. )
  581. /*++
  582. Routine Description:
  583. runs all functions from g_FirstSystemRoutines array.
  584. If the messageId is not 0 also updates progress bar title.
  585. Arguments:
  586. none
  587. Return value:
  588. Win32 status code.
  589. --*/
  590. {
  591. return pProcessTable (REQUEST_RUN, g_FirstSystemRoutines);
  592. }
  593. DWORD
  594. RunUserMigrationRoutines (
  595. VOID
  596. )
  597. /*++
  598. Routine Description:
  599. RunUserMigrationRoutines is called by userloop.c, between the first system
  600. processing and the last system processing. Routines in the
  601. MIGMAIN_USER_FUNCTIONS macro expansion list are called. The progress bar
  602. is updated automatically.
  603. Arguments:
  604. User - Specifies the user name
  605. UserType - Specifies the user account type
  606. UserRoot - Specifies the mapped registry handle (equivalent to HKCU)
  607. Return value:
  608. Win32 status code.
  609. --*/
  610. {
  611. DWORD rc = ERROR_SUCCESS;
  612. //
  613. // First, let routines know that processing will soon begin. This gives them
  614. // an opportunity to allocate any needed resources.
  615. //
  616. rc = pProcessTable (REQUEST_BEGINUSERPROCESSING, g_UserRoutines);
  617. //
  618. // Now, do the actual work.
  619. //
  620. if (rc == ERROR_SUCCESS) {
  621. rc = pProcessTable (REQUEST_RUN, g_UserRoutines);
  622. }
  623. //
  624. // Finally, give the user routines a chance to clean up any resources that may
  625. // have been allocated in REQUEST_BEGINUSERPROCESSING.
  626. //
  627. if (rc == ERROR_SUCCESS) {
  628. rc = pProcessTable (REQUEST_ENDUSERPROCESSING, g_UserRoutines);
  629. }
  630. return rc;
  631. }
  632. DWORD
  633. RunSysLastMigrationRoutines (
  634. VOID
  635. )
  636. /*++
  637. Routine Description:
  638. runs all functions from g_LastSystemRoutines array.
  639. If the messageId is not 0 also updates progress bar title.
  640. Arguments:
  641. none
  642. Return value:
  643. Win32 status code.
  644. --*/
  645. {
  646. DWORD Result;
  647. Result = pProcessTable (REQUEST_RUN, g_LastSystemRoutines);
  648. TerminateProcessingTable();
  649. if (Result == ERROR_SUCCESS) {
  650. pGlobalProcessingTerminate();
  651. }
  652. return Result;
  653. }
  654. DWORD
  655. AddDefaultCleanUpDirs (
  656. DWORD Request
  657. )
  658. {
  659. switch (Request) {
  660. case REQUEST_QUERYTICKS:
  661. return TICKS_ADDDEFAULTCLEANUPDIRS;
  662. case REQUEST_RUN:
  663. MemDbSetValueEx (
  664. MEMDB_CATEGORY_CLEAN_UP_DIR,
  665. g_SystemDir,
  666. NULL,
  667. NULL,
  668. 0,
  669. NULL
  670. );
  671. MemDbSetValueEx (
  672. MEMDB_CATEGORY_CLEAN_UP_DIR,
  673. g_ProgramFilesDir,
  674. NULL,
  675. NULL,
  676. 0,
  677. NULL
  678. );
  679. break;
  680. }
  681. return ERROR_SUCCESS;
  682. }
  683. VOID
  684. pGlobalProcessingInit (
  685. VOID
  686. )
  687. {
  688. TCHAR TempPath[MAX_TCHAR_PATH];
  689. InitGlobalPaths();
  690. if (!BeginIconExtraction (&g_IconContext, NULL)) {
  691. LOG ((LOG_ERROR, "DefaultIconPreservation: Can't start icon extraction"));
  692. return;
  693. }
  694. wsprintf (TempPath, TEXT("%s\\%s"), g_TempDir, S_MIGICONS_DAT);
  695. if (!OpenIconImageFile (&g_IconContext, TempPath, TRUE)) {
  696. LOG ((LOG_ERROR, "DefaultIconPreservation: Can't create %s", TempPath));
  697. EndIconExtraction (&g_IconContext);
  698. }
  699. return;
  700. }
  701. VOID
  702. pGlobalProcessingTerminate (
  703. VOID
  704. )
  705. {
  706. EndIconExtraction (&g_IconContext);
  707. }
  708. VOID
  709. pAddAllIds (
  710. IN PCTSTR IdList
  711. )
  712. {
  713. PCTSTR Temp;
  714. PTSTR p;
  715. CHARTYPE ch;
  716. Temp = DuplicateText (IdList);
  717. p = _tcspbrk (Temp, TEXT("&\\"));
  718. while (p) {
  719. ch = *p;
  720. *p = 0;
  721. DEBUGMSG ((DBG_NAUSEA, "System has PNP ID: %s", Temp));
  722. MemDbSetValueEx (
  723. MEMDB_CATEGORY_PNPIDS,
  724. Temp,
  725. NULL,
  726. NULL,
  727. 0,
  728. NULL
  729. );
  730. *p = (TCHAR)ch;
  731. p = _tcspbrk (_tcsinc (p), TEXT("&\\"));
  732. }
  733. FreeText (Temp);
  734. }
  735. DWORD
  736. PreparePnpIdList (
  737. DWORD Request
  738. )
  739. /*++
  740. Routine Description:
  741. PreparePnpIdList puts all PNP IDs in a memdb category to allow the PNPID
  742. attribute to work in migdb.inf.
  743. Arguments:
  744. Request - Specifies REQUEST_QUERYTICKS or REQUEST_RUN.
  745. Return Value:
  746. Always TICKS_PREPAREPNPIDLIST for REQUEST_QUERYTICKS, always ERROR_SUCCESS for REQUEST_RUN.
  747. --*/
  748. {
  749. HARDWARE_ENUM e;
  750. PTSTR p;
  751. if (Request == REQUEST_RUN) {
  752. if (EnumFirstHardware (
  753. &e,
  754. ENUM_ALL_DEVICES,
  755. ENUM_DONT_WANT_DEV_FIELDS|ENUM_DONT_WANT_USER_SUPPLIED|ENUM_DONT_REQUIRE_HARDWAREID
  756. )) {
  757. do {
  758. //
  759. // Add each part of the PNP ID as an endpoint
  760. //
  761. //
  762. // Skip past HKLM\Enum and add all IDs with the root
  763. //
  764. p = _tcschr (e.FullKey, TEXT('\\'));
  765. p = _tcschr (_tcsinc (p), TEXT('\\'));
  766. p = _tcsinc (p);
  767. pAddAllIds (p);
  768. //
  769. // Add all IDs without the root
  770. //
  771. pAddAllIds (e.InstanceId);
  772. } while (EnumNextHardware (&e));
  773. }
  774. return ERROR_SUCCESS;
  775. } else {
  776. return TICKS_PREPAREPNPIDLIST;
  777. }
  778. }
  779. DWORD
  780. PrepareIconList (
  781. DWORD Request
  782. )
  783. /*++
  784. Routine Description:
  785. PrepareIconList reads win95upg.inf [Moved Icons] and puts them
  786. in memdb for future use.
  787. Arguments:
  788. Request - Specifies REQUEST_QUERYTICKS or REQUEST_RUN.
  789. Return Value:
  790. Always TICKS_PREPAREPNPIDLIST for REQUEST_QUERYTICKS, always ERROR_SUCCESS
  791. for REQUEST_RUN.
  792. --*/
  793. {
  794. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  795. PCTSTR srcPath;
  796. TCHAR expandedSrcPath[MAX_TCHAR_PATH];
  797. PCTSTR destPath;
  798. TCHAR expandedDestPath[MAX_TCHAR_PATH];
  799. INT srcIndex;
  800. INT destIndex;
  801. INT srcId;
  802. INT destId;
  803. BOOL ok;
  804. DWORD destOffset;
  805. TCHAR num[32];
  806. TCHAR node[MEMDB_MAX];
  807. if (Request == REQUEST_RUN) {
  808. if (InfFindFirstLine (g_Win95UpgInf, S_MOVED_ICONS, NULL, &is)) {
  809. do {
  810. srcPath = InfGetStringField (&is, 1);
  811. ok = (srcPath != NULL);
  812. ok = ok && InfGetIntField (&is, 2, &srcIndex);
  813. ok = ok && (srcIndex >= 0);
  814. ok = ok && InfGetIntField (&is, 3, &srcId);
  815. ok = ok && (srcId >= 0);
  816. destPath = InfGetStringField (&is, 4);
  817. ok = ok && (destPath != NULL);
  818. ok = ok && InfGetIntField (&is, 5, &destIndex);
  819. ok = ok && (destIndex >= 0);
  820. ok = ok && InfGetIntField (&is, 6, &destId);
  821. ok = ok && (destId >= 0);
  822. if (!ok) {
  823. DEBUGMSG ((DBG_WHOOPS, "Syntax error in %s of win95upg.inf", S_MOVED_ICONS));
  824. } else {
  825. //
  826. // Convert env vars in srcPath and destPath
  827. //
  828. Expand9xEnvironmentVariables (
  829. srcPath,
  830. expandedSrcPath,
  831. sizeof (expandedSrcPath)
  832. );
  833. Expand9xEnvironmentVariables (
  834. destPath,
  835. expandedDestPath,
  836. sizeof (expandedDestPath)
  837. );
  838. //
  839. // Write out memdb nodes
  840. //
  841. MemDbSetValueEx (
  842. MEMDB_CATEGORY_DATA,
  843. expandedDestPath,
  844. NULL,
  845. NULL,
  846. 0,
  847. &destOffset
  848. );
  849. wsprintf (num, TEXT("%i"), srcIndex);
  850. MemDbBuildKey (
  851. node,
  852. MEMDB_CATEGORY_ICONS_MOVED,
  853. expandedSrcPath,
  854. num,
  855. NULL
  856. );
  857. MemDbSetValueAndFlags (node, destOffset, destIndex, 0xFFFFFFFF);
  858. wsprintf (num, TEXT("-%i"), srcId);
  859. MemDbBuildKey (
  860. node,
  861. MEMDB_CATEGORY_ICONS_MOVED,
  862. expandedSrcPath,
  863. num,
  864. NULL
  865. );
  866. MemDbSetValueAndFlags (node, destOffset, destId, 0xFFFFFFFF);
  867. }
  868. } while (InfFindNextLine (&is));
  869. }
  870. return ERROR_SUCCESS;
  871. } else {
  872. return TICKS_PREPAREPNPIDLIST;
  873. }
  874. }
  875. VOID
  876. pWriteAccountToMemDb (
  877. PUSERENUM EnumPtr
  878. )
  879. {
  880. HKEY LogonKey, AuthAgentKey=NULL;
  881. PCTSTR LastLoggedOnUser, Provider, AuthAgent=NULL;
  882. TCHAR Domain[MAX_SERVER_NAME];
  883. BOOL MsNetInstalled = FALSE;
  884. //
  885. // Write account name to KnownDomain if the user was the
  886. // last logged on user
  887. //
  888. Domain[0] = 0;
  889. //
  890. // Determine if Microsoft Network is installed
  891. //
  892. if ((EnumPtr -> AccountType & LOGON_PROMPT) || (EnumPtr -> AccountType & DEFAULT_USER)) {
  893. //
  894. // Nothing to do for logon user.
  895. //
  896. return;
  897. } else if (EnumPtr -> AccountType & ADMINISTRATOR) {
  898. //
  899. // Because this user is the local Administrator, we must default
  900. // to a local account. We get this behavior by assuming the
  901. // MSNP32 key doesn't exist (even if it really does).
  902. //
  903. AuthAgentKey = NULL;
  904. } else if (EnumPtr -> AccountType & DEFAULT_USER) {
  905. //
  906. // Nothing to do for default user
  907. //
  908. return;
  909. } else {
  910. //
  911. // Real user. Get the MSNP32 key.
  912. //
  913. AuthAgentKey = OpenRegKeyStr (S_MSNP32);
  914. }
  915. if (AuthAgentKey) {
  916. //
  917. // If last logged on user was the same as the user being processed,
  918. // and the user is a Microsoft Network user, obtain the domain name.
  919. //
  920. MsNetInstalled = TRUE;
  921. LogonKey = OpenRegKeyStr (S_LOGON_KEY);
  922. if (LogonKey) {
  923. LastLoggedOnUser = GetRegValueData (LogonKey, S_USERNAME_VALUE);
  924. if (LastLoggedOnUser) {
  925. if (StringIMatch (LastLoggedOnUser, EnumPtr -> UserName)) {
  926. //
  927. // User is the same as last logged on user. If the primary
  928. // provider is Microsoft Network, then get the authenticating
  929. // agent (which is the domain name).
  930. //
  931. Provider = GetRegValueData (LogonKey, S_PRIMARY_PROVIDER);
  932. if (Provider) {
  933. if (StringIMatch (Provider, S_LANMAN)) {
  934. //
  935. // Obtain the domain name
  936. //
  937. if (AuthAgentKey) {
  938. AuthAgent = GetRegValueData (AuthAgentKey, S_AUTHENTICATING_AGENT);
  939. if (AuthAgent) {
  940. StringCopy (Domain, AuthAgent);
  941. MemFree (g_hHeap, 0, AuthAgent);
  942. }
  943. }
  944. }
  945. MemFree (g_hHeap, 0, Provider);
  946. }
  947. }
  948. MemFree (g_hHeap, 0, LastLoggedOnUser);
  949. }
  950. CloseRegKey (LogonKey);
  951. }
  952. CloseRegKey (AuthAgentKey);
  953. }
  954. if (!MsNetInstalled || *Domain) {
  955. //
  956. // Assuming we have a valid user name:
  957. // If MSNP32 is not installed, default to a local account.
  958. // If it is installed, we must have a valid domain name.
  959. //
  960. // If we do not have a valid user name, then the current user
  961. // is the .Default account, which does not need to be verified
  962. // on the net.
  963. //
  964. if (*EnumPtr -> UserName) {
  965. MemDbSetValueEx (MEMDB_CATEGORY_KNOWNDOMAIN, Domain, EnumPtr -> FixedUserName, NULL, 0, NULL);
  966. }
  967. } else {
  968. //
  969. // MSNP32 is installed, but the domain name for this user is unknown.
  970. // Perform a search.
  971. //
  972. MemDbSetValueEx (MEMDB_CATEGORY_AUTOSEARCH, EnumPtr -> FixedUserName, NULL, NULL, 0, NULL);
  973. }
  974. }
  975. BOOL
  976. pReportMapiIfNotHandled (
  977. VOID
  978. )
  979. {
  980. PCTSTR Group;
  981. PCTSTR Message;
  982. TCHAR pattern[MEMDB_MAX];
  983. MEMDB_ENUM enumItems;
  984. BOOL addMsg = FALSE;
  985. DWORD status = 0;
  986. HKEY key;
  987. key = OpenRegKeyStr (S_INBOX_CFG);
  988. if (key) {
  989. CloseRegKey (key);
  990. MemDbBuildKey (pattern, MEMDB_CATEGORY_MAPI32_LOCATIONS, TEXT("*"), NULL, NULL);
  991. if (MemDbEnumFirstValue (&enumItems, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  992. do {
  993. if (IsReportObjectHandled (enumItems.szName)) {
  994. continue;
  995. }
  996. status = GetFileStatusOnNt (enumItems.szName);
  997. if ((status & FILESTATUS_REPLACED) != FILESTATUS_REPLACED) {
  998. addMsg = TRUE;
  999. break;
  1000. }
  1001. } while (MemDbEnumNextValue (&enumItems));
  1002. }
  1003. }
  1004. if (addMsg) {
  1005. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_MAPI_NOT_HANDLED_SUBGROUP, NULL);
  1006. Message = GetStringResource (MSG_MAPI_NOT_HANDLED);
  1007. if (Message && Group) {
  1008. MsgMgr_ObjectMsg_Add (TEXT("*MapiNotHandled"), Group, Message);
  1009. }
  1010. FreeText (Group);
  1011. FreeStringResource (Message);
  1012. }
  1013. return TRUE;
  1014. }
  1015. DWORD
  1016. ReportMapiIfNotHandled (
  1017. IN DWORD Request
  1018. )
  1019. {
  1020. switch (Request) {
  1021. case REQUEST_QUERYTICKS:
  1022. return TICKS_REPORTMAPIIFNOTHANDLED;
  1023. case REQUEST_RUN:
  1024. if (pReportMapiIfNotHandled ()) {
  1025. return ERROR_SUCCESS;
  1026. }
  1027. return GetLastError ();
  1028. }
  1029. return ERROR_SUCCESS;
  1030. }
  1031. DWORD
  1032. GatherImeInfo (
  1033. IN DWORD Request
  1034. )
  1035. {
  1036. REGKEY_ENUM e;
  1037. PCTSTR imeFile = NULL;
  1038. TCHAR imePath[MAX_TCHAR_PATH];
  1039. HKEY topKey = NULL;
  1040. HKEY layoutKey = NULL;
  1041. UINT status = 0;
  1042. switch (Request) {
  1043. case REQUEST_QUERYTICKS:
  1044. return TICKS_GATHER_IME_INFO;
  1045. break;
  1046. case REQUEST_RUN:
  1047. //
  1048. // Enumerate through the keyboard layout registry looking for IMEs.
  1049. //
  1050. topKey = OpenRegKeyStr (S_KEYBOARD_LAYOUT_REG);
  1051. if (!topKey) {
  1052. DEBUGMSG ((DBG_ERROR, "Could not open keyboard layouts registry."));
  1053. return ERROR_SUCCESS;
  1054. }
  1055. if (EnumFirstRegKey (&e, topKey)) {
  1056. do {
  1057. //
  1058. // We only care about IME entries.
  1059. //
  1060. if (*e.SubKeyName == TEXT('e') || *e.SubKeyName == TEXT('E')) {
  1061. layoutKey = OpenRegKey (topKey, e.SubKeyName);
  1062. if (layoutKey) {
  1063. imeFile = GetRegValueString (layoutKey, TEXT("IME File"));
  1064. if (imeFile && SearchPath (NULL, imeFile, NULL, MAX_TCHAR_PATH, imePath, NULL)) {
  1065. //
  1066. // We are only going to migrate this IME file if it is left around after we
  1067. // are done.
  1068. //
  1069. status = GetFileStatusOnNt (imePath);
  1070. if ((status & FILESTATUS_DELETED) == 0) {
  1071. MemDbSetValueEx (MEMDB_CATEGORY_GOOD_IMES, imeFile, NULL, NULL, 0, NULL);
  1072. }
  1073. ELSE_DEBUGMSG ((DBG_NAUSEA, "IME %s will be suppressed from the keyboard layout merge.", e.SubKeyName));
  1074. }
  1075. if (imeFile) {
  1076. MemFree (g_hHeap, 0, imeFile);
  1077. }
  1078. CloseRegKey (layoutKey);
  1079. }
  1080. }
  1081. } while (EnumNextRegKey (&e));
  1082. }
  1083. CloseRegKey (topKey);
  1084. break;
  1085. }
  1086. return ERROR_SUCCESS;
  1087. }
  1088. PEVALFN
  1089. pFindEvalFnByName (
  1090. IN PCTSTR FnName
  1091. )
  1092. {
  1093. INT i;
  1094. i = 0;
  1095. while (g_MapNameToEvalFn[i].FnName) {
  1096. if (StringMatch (FnName, g_MapNameToEvalFn[i].FnName)) {
  1097. return g_MapNameToEvalFn[i].EvalFn;
  1098. }
  1099. i++;
  1100. }
  1101. return NULL;
  1102. }
  1103. DWORD
  1104. DeleteStaticFiles (
  1105. IN DWORD Request
  1106. )
  1107. {
  1108. #define MAX_DRIVE_STRINGS (26 * 4 + 1)
  1109. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1110. PCTSTR Data;
  1111. TCHAR ExpandedData[MAX_TCHAR_PATH];
  1112. PTSTR Pattern;
  1113. FILE_ENUM e;
  1114. BOOL Negate, Eval;
  1115. PEVALFN fn;
  1116. DWORD attr;
  1117. TCHAR drives[MAX_DRIVE_STRINGS];
  1118. DWORD rc;
  1119. PTSTR p;
  1120. PCTSTR q;
  1121. TREE_ENUM eFiles;
  1122. switch (Request) {
  1123. case REQUEST_QUERYTICKS:
  1124. return TICKS_DELETESTATICFILES;
  1125. case REQUEST_RUN:
  1126. if (InfFindFirstLine (g_Win95UpgInf, S_FILES_TO_REMOVE, NULL, &is)) {
  1127. do {
  1128. Data = InfGetStringField (&is, 1);
  1129. if (!Data) {
  1130. continue;
  1131. }
  1132. Expand9xEnvironmentVariables (
  1133. Data,
  1134. ExpandedData,
  1135. sizeof (ExpandedData)
  1136. );
  1137. Data = InfGetStringField (&is, 2);
  1138. if (Data) {
  1139. if (*Data == TEXT('!')) {
  1140. ++Data;
  1141. Negate = TRUE;
  1142. } else {
  1143. Negate = FALSE;
  1144. }
  1145. //
  1146. // call the function by name
  1147. //
  1148. fn = pFindEvalFnByName (Data);
  1149. //
  1150. // did you forget to implement it?
  1151. //
  1152. MYASSERT (fn);
  1153. if (!fn) {
  1154. //
  1155. // don't remove the file/dir
  1156. //
  1157. continue;
  1158. }
  1159. } else {
  1160. fn = NULL;
  1161. }
  1162. p = drives;
  1163. if (*ExpandedData == TEXT('?')) {
  1164. ACCESSIBLE_DRIVE_ENUM e;
  1165. if (GetFirstAccessibleDrive (&e)) {
  1166. do {
  1167. *p++ = e->Drive[0];
  1168. } while (GetNextAccessibleDrive (&e));
  1169. }
  1170. } else {
  1171. *p++ = *ExpandedData;
  1172. }
  1173. *p = 0;
  1174. p = drives;
  1175. do {
  1176. *ExpandedData = *p++;
  1177. attr = GetFileAttributes (ExpandedData);
  1178. if ((attr != -1) && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
  1179. if (fn) {
  1180. Eval = (*fn)(ExpandedData, &is, 3) ? TRUE : FALSE;
  1181. //
  1182. // !Negate && !Eval || Negate && Eval means !(Negate ^ Eval)
  1183. //
  1184. if (!(Negate ^ Eval)) {
  1185. //
  1186. // don't remove the directory
  1187. //
  1188. continue;
  1189. }
  1190. }
  1191. if (IsDriveExcluded (ExpandedData)) {
  1192. DEBUGMSG ((DBG_VERBOSE, "Skipping static file %s because it is excluded", ExpandedData));
  1193. continue;
  1194. }
  1195. if (!IsDriveAccessible (ExpandedData)) {
  1196. DEBUGMSG ((DBG_VERBOSE, "Skipping static file %s because it is not accessible", ExpandedData));
  1197. continue;
  1198. }
  1199. if (EnumFirstFileInTree (&eFiles, ExpandedData, NULL, FALSE)) {
  1200. do {
  1201. //
  1202. // Tally up the saved bytes, and free the space on the drive.
  1203. //
  1204. FreeSpace (
  1205. eFiles.FullPath,
  1206. eFiles.FindData->nFileSizeHigh * MAXDWORD + eFiles.FindData->nFileSizeLow
  1207. );
  1208. } while (EnumNextFileInTree (&eFiles));
  1209. }
  1210. MemDbSetValueEx (MEMDB_CATEGORY_FULL_DIR_DELETES, ExpandedData, NULL, NULL, 0, NULL);
  1211. } else {
  1212. Pattern = _tcsrchr (ExpandedData, TEXT('\\'));
  1213. //
  1214. // full path please
  1215. //
  1216. MYASSERT (Pattern);
  1217. if (!Pattern) {
  1218. continue;
  1219. }
  1220. *Pattern = 0;
  1221. if (EnumFirstFile (&e, ExpandedData, Pattern + 1)) {
  1222. do {
  1223. if (fn) {
  1224. Eval = (*fn)(e.FullPath, &is, 3) ? TRUE : FALSE;
  1225. //
  1226. // !Negate && !Eval || Negate && Eval means !(Negate ^ Eval)
  1227. //
  1228. if (!(Negate ^ Eval)) {
  1229. //
  1230. // don't remove the file
  1231. //
  1232. continue;
  1233. }
  1234. }
  1235. MarkFileForDelete (e.FullPath);
  1236. } while (EnumNextFile (&e));
  1237. }
  1238. *Pattern = TEXT('\\');
  1239. }
  1240. } while (*p);
  1241. } while (InfFindNextLine (&is));
  1242. }
  1243. InfCleanUpInfStruct (&is);
  1244. break;
  1245. }
  1246. return ERROR_SUCCESS;
  1247. }
  1248. BOOL
  1249. Boot16Enabled (
  1250. IN PCTSTR PathToEval,
  1251. IN OUT PINFSTRUCT InfStruct,
  1252. IN UINT FirstArgIndex
  1253. )
  1254. {
  1255. //
  1256. // at this point, check *g_ForceNTFSConversion to be FALSE
  1257. // and *g_Boot16 not to be disabled
  1258. //
  1259. return (!*g_ForceNTFSConversion) && (*g_Boot16 != BOOT16_NO);
  1260. }
  1261. BOOL
  1262. DoesRegKeyValuesExist (
  1263. IN PCTSTR PathToEval,
  1264. IN OUT PINFSTRUCT InfStruct,
  1265. IN UINT FirstArgIndex
  1266. )
  1267. {
  1268. PCTSTR RegKey;
  1269. PCTSTR Value;
  1270. HKEY key;
  1271. BOOL b = FALSE;
  1272. RegKey = InfGetStringField (InfStruct, FirstArgIndex++);
  1273. if (RegKey) {
  1274. key = OpenRegKeyStr (RegKey);
  1275. if (key) {
  1276. b = TRUE;
  1277. while (b && (Value = InfGetStringField (InfStruct, FirstArgIndex++)) != NULL) {
  1278. b = (RegQueryValueEx (key, Value, NULL, NULL, NULL, NULL) == ERROR_SUCCESS);
  1279. }
  1280. CloseRegKey (key);
  1281. }
  1282. }
  1283. return b;
  1284. }
  1285. BOOL
  1286. IsMillennium (
  1287. IN PCTSTR PathToEval,
  1288. IN OUT PINFSTRUCT InfStruct,
  1289. IN UINT FirstArgIndex
  1290. )
  1291. {
  1292. return ISMILLENNIUM();
  1293. }
  1294. /*++
  1295. Routine Description:
  1296. GatherDead() gathers disabled or bad objects (apps, cpls, runkeys,
  1297. links) and saves them to a file (dead.ini) so they can be tested
  1298. to see if they actually are not bad. This functions only in
  1299. PRERELEASE mode.
  1300. Arguments:
  1301. Request - reason for calling function
  1302. Return Value:
  1303. if in REQUEST_RUN mode, always returns ERROR_SUCCESS
  1304. because we don't want to break setup.
  1305. --*/
  1306. DWORD
  1307. GatherDead (
  1308. IN DWORD Request
  1309. )
  1310. {
  1311. FILEOP_ENUM FileEnum;
  1312. MEMDB_ENUM MemDbEnum;
  1313. REGVALUE_ENUM RegEnum;
  1314. HKEY Key;
  1315. HANDLE File;
  1316. TCHAR Temp[MEMDB_MAX];
  1317. TCHAR MemDbKey[MEMDB_MAX];
  1318. TCHAR DeadPath[MEMDB_MAX];
  1319. PTSTR Data;
  1320. switch (Request) {
  1321. case REQUEST_QUERYTICKS:
  1322. #ifndef PRERELEASE
  1323. return 0;
  1324. #else
  1325. return TICKS_GATHERDEAD;
  1326. #endif //PRERELEASE
  1327. case REQUEST_RUN:
  1328. //
  1329. // We only do stuff here if in PRERELEASE mode, because
  1330. // in release mode REQUEST_QUERYTICKS returns 0, so
  1331. // REQUEST_RUN is not called.
  1332. //
  1333. wsprintf (DeadPath, TEXT("%s\\%s"), g_WinDir, DEAD_FILE);
  1334. File = CreateFile (
  1335. DeadPath,
  1336. GENERIC_WRITE,
  1337. 0,
  1338. NULL,
  1339. CREATE_ALWAYS,
  1340. FILE_ATTRIBUTE_NORMAL,
  1341. NULL
  1342. );
  1343. if (File==INVALID_HANDLE_VALUE) {
  1344. DEBUGMSG ((DBG_WARNING, "Could not create " DEAD_FILE "!"));
  1345. return ERROR_SUCCESS;
  1346. }
  1347. WriteFileString(File, TEXT("[Version]\r\nSignature=\"$Chicago$\""));
  1348. WriteFileString(File, TEXT("\r\n\r\n[DEAD]\r\n"));
  1349. //
  1350. // add links to dead.ini file
  1351. //
  1352. if (MemDbEnumFirstValue (
  1353. &MemDbEnum,
  1354. MEMDB_CATEGORY_LINKEDIT,
  1355. MEMDB_ALL_SUBLEVELS,
  1356. MEMDB_ENDPOINTS_ONLY
  1357. ))
  1358. {
  1359. do {
  1360. wsprintf(Temp, TEXT("%s=%d\r\n"), MemDbEnum.szName, OBJECTTYPE_LINK);
  1361. WriteFileString(File, Temp);
  1362. } while (MemDbEnumNextValue (&MemDbEnum));
  1363. }
  1364. //
  1365. // add bad apps to dead.ini file
  1366. //
  1367. if (MemDbEnumFirstValue (
  1368. &MemDbEnum,
  1369. MEMDB_CATEGORY_MODULE_CHECK,
  1370. MEMDB_ALL_SUBLEVELS,
  1371. MEMDB_ENDPOINTS_ONLY
  1372. ))
  1373. {
  1374. do {
  1375. //
  1376. // only include app if it is marked as 'bad'
  1377. //
  1378. if (MemDbEnum.dwValue==MODULESTATUS_BAD) {
  1379. wsprintf(Temp, TEXT("%s=%d\r\n"), MemDbEnum.szName, OBJECTTYPE_APP);
  1380. WriteFileString(File, Temp);
  1381. }
  1382. } while (MemDbEnumNextValue (&MemDbEnum));
  1383. }
  1384. //
  1385. // add CPLs in OPERATION_FILE_DISABLED
  1386. //
  1387. if (EnumFirstPathInOperation (&FileEnum, OPERATION_FILE_DISABLED)) {
  1388. do {
  1389. //
  1390. // only include disabled CPLs (for now, thats all there is)
  1391. //
  1392. if (_tcsistr(FileEnum.Path, TEXT(".cpl"))) {
  1393. wsprintf(Temp, TEXT("%s=%d\r\n"), FileEnum.Path, OBJECTTYPE_CPL);
  1394. WriteFileString(File, Temp);
  1395. }
  1396. } while (EnumNextPathInOperation (&FileEnum));
  1397. }
  1398. //
  1399. // add RunKeys that are not in COMPATIBLE_RUNKEY list
  1400. //
  1401. if (Key = OpenRegKeyStr (S_RUN_KEY))
  1402. {
  1403. if (EnumFirstRegValue(&RegEnum, Key))
  1404. {
  1405. do {
  1406. Data=GetRegValueString(Key, RegEnum.ValueName);
  1407. MemDbBuildKey (
  1408. MemDbKey,
  1409. MEMDB_CATEGORY_COMPATIBLE_RUNKEY,
  1410. Data,
  1411. NULL,
  1412. NULL
  1413. );
  1414. //
  1415. // only add runkey to dead.ini if it was not put
  1416. // in the compatible runkey memdb category.
  1417. // (we only want incompatible runkeys)
  1418. //
  1419. if (!MemDbGetValue(MemDbKey, NULL))
  1420. {
  1421. //
  1422. // we have a friendly name (ValueName)
  1423. // so include it in dead.ini
  1424. //
  1425. wsprintf (
  1426. Temp,
  1427. TEXT("%s=%d,%s\r\n"),
  1428. Data,
  1429. OBJECTTYPE_RUNKEY,
  1430. RegEnum.ValueName
  1431. );
  1432. WriteFileString(File, Temp);
  1433. }
  1434. MemFreeWrapper(Data);
  1435. } while (EnumNextRegValue(&RegEnum));
  1436. }
  1437. CloseRegKey (Key);
  1438. }
  1439. WriteFileString(File, TEXT("\r\n"));
  1440. CloseHandle(File);
  1441. break;
  1442. }
  1443. return ERROR_SUCCESS;
  1444. }
  1445. VOID
  1446. pReportDarwinIfNotHandled (
  1447. VOID
  1448. )
  1449. {
  1450. PCTSTR Group;
  1451. PCTSTR Message;
  1452. HKEY key;
  1453. DWORD rc;
  1454. DWORD subkeys;
  1455. MSGMGROBJENUM e;
  1456. key = OpenRegKeyStr (S_REGKEY_DARWIN_COMPONENTS);
  1457. if (key) {
  1458. rc = RegQueryInfoKey (key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  1459. if (rc == ERROR_SUCCESS && subkeys) {
  1460. if (!IsReportObjectHandled (S_REGKEY_DARWIN_COMPONENTS)) {
  1461. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_DARWIN_NOT_HANDLED_SUBGROUP, NULL);
  1462. Message = GetStringResource (MSG_DARWIN_NOT_HANDLED);
  1463. if (Message && Group) {
  1464. MsgMgr_ObjectMsg_Add (TEXT("*DarwinNotHandled"), Group, Message);
  1465. //
  1466. // disable Outlook 2000 message
  1467. //
  1468. if (MsgMgr_EnumFirstObject (&e)) {
  1469. do {
  1470. if (StringMatch (e.Context, TEXT("Microsoft_Outlook_2000"))) {
  1471. HandleReportObject (e.Object);
  1472. break;
  1473. }
  1474. } while (MsgMgr_EnumNextObject (&e));
  1475. }
  1476. }
  1477. FreeText (Group);
  1478. FreeStringResource (Message);
  1479. }
  1480. }
  1481. CloseRegKey (key);
  1482. }
  1483. }
  1484. DWORD
  1485. ReportDarwinIfNotHandled (
  1486. IN DWORD Request
  1487. )
  1488. {
  1489. switch (Request) {
  1490. case REQUEST_QUERYTICKS:
  1491. return TICKS_REPORTDARWINIFNOTHANDLED;
  1492. case REQUEST_RUN:
  1493. pReportDarwinIfNotHandled ();
  1494. break;
  1495. }
  1496. return ERROR_SUCCESS;
  1497. }
  1498. DWORD
  1499. ElevateReportObjects (
  1500. IN DWORD Request
  1501. )
  1502. {
  1503. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  1504. PCTSTR data;
  1505. switch (Request) {
  1506. case REQUEST_QUERYTICKS:
  1507. return 1;
  1508. case REQUEST_RUN:
  1509. if (InfFindFirstLine (g_Win95UpgInf, TEXT("ShowInSimplifiedView"), NULL, &is)) {
  1510. do {
  1511. data = InfGetStringField (&is, 1);
  1512. if (data) {
  1513. ElevateObject (data);
  1514. }
  1515. } while (InfFindNextLine (&is));
  1516. }
  1517. InfCleanUpInfStruct (&is);
  1518. return ERROR_SUCCESS;
  1519. default:
  1520. DEBUGMSG ((DBG_ERROR, "Bad parameter in CopyStaticFiles."));
  1521. }
  1522. return 0;
  1523. }