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.

1992 lines
56 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. #pragma prefast(suppress:11, "Intentional AV for testing purposes")
  326. StringCopy (BadPtr, TEXT("Blow Up!!"));
  327. }
  328. }
  329. #endif
  330. }
  331. __except (1) {
  332. //
  333. // Caught an exception..
  334. //
  335. LOG ((LOG_WARNING, "Function %s threw an exception.", fn->FnName));
  336. SafeModeExceptionOccured ();
  337. if (fn->Critical && Request == REQUEST_RUN) {
  338. //
  339. // Since this was a critical function, inform the user and tank the upgrade.
  340. //
  341. SetLastError (ERROR_NOACCESS);
  342. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_UNEXPECTED_ERROR_ENCOUNTERED, GetLastError()));
  343. pGlobalProcessingTerminate();
  344. rc = ERROR_CANCELLED;
  345. }
  346. }
  347. if (CANCELLED()) {
  348. rc = ERROR_CANCELLED;
  349. }
  350. //
  351. // If running the function, end the progress bar slice
  352. //
  353. if (Request == REQUEST_RUN) {
  354. DEBUGLOGTIME (("Function complete: %s", fn->FnName));
  355. EndSliceProcessing();
  356. if (rc != ERROR_SUCCESS) {
  357. pGlobalProcessingTerminate();
  358. if (!CANCELLED()) {
  359. LOG ((LOG_ERROR, "Failure in %s, rc=%u", fn->FnName, rc));
  360. }
  361. ELSE_DEBUGMSG ((DBG_VERBOSE, "Winnt32 was cancelled during %s.", fn->FnName));
  362. }
  363. ProgressBar_ClearFnName();
  364. SetLastError (rc);
  365. }
  366. //
  367. // If querying the ticks, register them and add slice ID to grow buffer
  368. //
  369. else {
  370. fn->Ticks += rc;
  371. SliceId = (PDWORD) GrowBuffer (&fn->SliceIdArray, sizeof (DWORD));
  372. *SliceId = RegisterProgressBarSlice (rc);
  373. rc = ERROR_SUCCESS;
  374. }
  375. return rc;
  376. }
  377. DWORD
  378. pProcessTable (
  379. IN DWORD Request,
  380. IN PPROCESSING_ROUTINE Table
  381. )
  382. /*++
  383. Routine Description:
  384. pProcessTable calls all routines in the specified table to perform
  385. the specified request.
  386. Arguments:
  387. Request - Specifies REQUEST_QUERYTICKS when a tick estimate is needed,
  388. or REQUEST_RUN when the function needs to perform its
  389. processing.
  390. Return Value:
  391. Win32 status code.
  392. --*/
  393. {
  394. PPROCESSING_ROUTINE OrgStart;
  395. DWORD rc = ERROR_SUCCESS;
  396. USERENUM e;
  397. BOOL validUserFound = FALSE;
  398. static BOOL firstTime = TRUE;
  399. while (rc == ERROR_SUCCESS && (Table->SysFnPtr || Table->UserFnPtr)) {
  400. //
  401. // If the table is a system function table or the request is to begin/end user processing,
  402. // then this is the simple case. No enumeration of users is needed.
  403. //
  404. if (Table->SysFnPtr || Request == REQUEST_BEGINUSERPROCESSING || Request == REQUEST_ENDUSERPROCESSING) {
  405. rc = pProcessWorker (Request, Table, NULL);
  406. Table++;
  407. } else {
  408. MYASSERT (Table->UserFnPtr);
  409. //
  410. // Enumerate each user, and run through all the per-user
  411. // routines in the group.
  412. //
  413. OrgStart = Table;
  414. if (EnumFirstUser (&e, ENUMUSER_ENABLE_NAME_FIX)) {
  415. do {
  416. //
  417. // Skip invalid users
  418. //
  419. if (e.AccountType & INVALID_ACCOUNT) {
  420. continue;
  421. }
  422. //
  423. // Create user-specific environment variables
  424. //
  425. InitNtUserEnvironment (&e);
  426. //
  427. // Set global user profile root.
  428. //
  429. g_UserProfileRoot = e.OrgProfilePath;
  430. if (firstTime) {
  431. //
  432. // Log information about the user to the debug log.
  433. //
  434. DEBUGMSG ((
  435. DBG_SYSMIG,
  436. "--- User Info ---\n"
  437. " User Name: %s (%s)\n"
  438. " Admin User Name: %s (%s)\n"
  439. " User Hive: %s\n"
  440. " Profile Dir: %s\n"
  441. " User Hive Key: 0%0Xh\n"
  442. " Win9x Profile Path: %s\n"
  443. " WinNT Profile Path: %s\n"
  444. " Common Profiles: %s\n",
  445. e.UserName,
  446. e.FixedUserName,
  447. e.AdminUserName,
  448. e.FixedAdminUserName,
  449. e.UserDatPath,
  450. e.ProfileDirName,
  451. e.UserRegKey,
  452. e.OrgProfilePath,
  453. e.NewProfilePath,
  454. e.CommonProfilesEnabled ? TEXT("Yes") : TEXT("No")
  455. ));
  456. DEBUGMSG ((
  457. DBG_SYSMIG,
  458. "--- User Flags ---\n"
  459. " Named User: %s\n"
  460. " Default User: %s\n"
  461. " Administrator: %s\n"
  462. " Last Logged On User: %s\n"
  463. " Invalid Account: %s\n"
  464. " Logon Prompt Account: %s\n"
  465. " Current User: %s\n",
  466. e.AccountType & NAMED_USER ? TEXT("Yes") : TEXT("No"),
  467. e.AccountType & DEFAULT_USER ? TEXT("Yes") : TEXT("No"),
  468. e.AccountType & ADMINISTRATOR ? TEXT("Yes") : TEXT("No"),
  469. e.AccountType & LAST_LOGGED_ON_USER ? TEXT("Yes") : TEXT("No"),
  470. e.AccountType & INVALID_ACCOUNT ? TEXT("Yes") : TEXT("No"),
  471. e.AccountType & LOGON_PROMPT ? TEXT("Yes") : TEXT("No"),
  472. e.AccountType & CURRENT_USER ? TEXT("Yes") : TEXT("No")
  473. ));
  474. //
  475. // Special case: record the Administrator/Owner account
  476. //
  477. if ((e.AccountType & (ADMINISTRATOR|NAMED_USER)) == (ADMINISTRATOR|NAMED_USER)) {
  478. //
  479. // Administrator account on machine that has named users
  480. //
  481. MemDbSetValueEx (
  482. MEMDB_CATEGORY_ADMINISTRATOR_INFO, // "AdministratorInfo"
  483. MEMDB_ITEM_AI_ACCOUNT, // "Account"
  484. NULL, // no field
  485. e.FixedAdminUserName, // the Win9x user name
  486. 0,
  487. NULL
  488. );
  489. } else if ((e.AccountType & (ADMINISTRATOR|NAMED_USER|DEFAULT_USER)) ==
  490. (ADMINISTRATOR|DEFAULT_USER)
  491. ) {
  492. //
  493. // Administrator account on machine with no users at all
  494. //
  495. MemDbSetValueEx (
  496. MEMDB_CATEGORY_ADMINISTRATOR_INFO, // "AdministratorInfo"
  497. MEMDB_ITEM_AI_ACCOUNT, // "Account"
  498. NULL, // no field
  499. e.FixedUserName, // "Administrator" or "Owner"
  500. 0,
  501. NULL
  502. );
  503. }
  504. //
  505. // Save user account to memdb
  506. //
  507. pWriteAccountToMemDb(&e);
  508. }
  509. //
  510. // if we have gotten this far, then we have a valid user to process.
  511. //
  512. validUserFound = TRUE;
  513. //
  514. // Call all the user processing functions.
  515. //
  516. DEBUGMSG ((DBG_SYSMIG, "Processing User: %s.", e.UserName ));
  517. for (Table = OrgStart ; Table->UserFnPtr ; Table++) {
  518. if (rc == ERROR_SUCCESS) {
  519. rc = pProcessWorker (Request, Table, &e);
  520. }
  521. }
  522. //
  523. // Clear out the global user profile variable.
  524. //
  525. g_UserProfileRoot = NULL;
  526. //
  527. // Remove user-specific environment variables
  528. //
  529. TerminateNtUserEnvironment();
  530. } while (EnumNextUser (&e));
  531. }
  532. ELSE_DEBUGMSG ((DBG_WARNING, "No active users to process!"));
  533. //
  534. // Inform the user if there were no valid users to process
  535. // (Probably will never happen)
  536. //
  537. if (!validUserFound) {
  538. if (CANCELLED()) {
  539. rc = ERROR_CANCELLED;
  540. } else {
  541. OkBox (g_ParentWnd, MSG_NO_VALID_ACCOUNTS_POPUP);
  542. rc = ERROR_BADKEY;
  543. }
  544. }
  545. //
  546. // Make sure that we have passed all of the user functions in the
  547. // table.
  548. //
  549. while (Table->UserFnPtr) {
  550. Table++;
  551. }
  552. firstTime = FALSE;
  553. }
  554. }
  555. return rc;
  556. }
  557. VOID
  558. PrepareProcessingProgressBar (
  559. VOID
  560. )
  561. /*++
  562. Routine Description:
  563. Prepares the progress bar by estimating the number of ticks for each slice
  564. of the progress bar. pQueryWorker is called for each table of functions
  565. to run during the processing wizard page.
  566. Arguments:
  567. none
  568. Return value:
  569. none
  570. --*/
  571. {
  572. pGlobalProcessingInit();
  573. InitProcessingTable();
  574. pProcessTable (REQUEST_QUERYTICKS, g_FirstSystemRoutines);
  575. pProcessTable (REQUEST_QUERYTICKS, g_UserRoutines);
  576. pProcessTable (REQUEST_QUERYTICKS, g_LastSystemRoutines);
  577. }
  578. DWORD
  579. RunSysFirstMigrationRoutines (
  580. VOID
  581. )
  582. /*++
  583. Routine Description:
  584. runs all functions from g_FirstSystemRoutines array.
  585. If the messageId is not 0 also updates progress bar title.
  586. Arguments:
  587. none
  588. Return value:
  589. Win32 status code.
  590. --*/
  591. {
  592. return pProcessTable (REQUEST_RUN, g_FirstSystemRoutines);
  593. }
  594. DWORD
  595. RunUserMigrationRoutines (
  596. VOID
  597. )
  598. /*++
  599. Routine Description:
  600. RunUserMigrationRoutines is called by userloop.c, between the first system
  601. processing and the last system processing. Routines in the
  602. MIGMAIN_USER_FUNCTIONS macro expansion list are called. The progress bar
  603. is updated automatically.
  604. Arguments:
  605. User - Specifies the user name
  606. UserType - Specifies the user account type
  607. UserRoot - Specifies the mapped registry handle (equivalent to HKCU)
  608. Return value:
  609. Win32 status code.
  610. --*/
  611. {
  612. DWORD rc = ERROR_SUCCESS;
  613. //
  614. // First, let routines know that processing will soon begin. This gives them
  615. // an opportunity to allocate any needed resources.
  616. //
  617. rc = pProcessTable (REQUEST_BEGINUSERPROCESSING, g_UserRoutines);
  618. //
  619. // Now, do the actual work.
  620. //
  621. if (rc == ERROR_SUCCESS) {
  622. rc = pProcessTable (REQUEST_RUN, g_UserRoutines);
  623. }
  624. //
  625. // Finally, give the user routines a chance to clean up any resources that may
  626. // have been allocated in REQUEST_BEGINUSERPROCESSING.
  627. //
  628. if (rc == ERROR_SUCCESS) {
  629. rc = pProcessTable (REQUEST_ENDUSERPROCESSING, g_UserRoutines);
  630. }
  631. return rc;
  632. }
  633. DWORD
  634. RunSysLastMigrationRoutines (
  635. VOID
  636. )
  637. /*++
  638. Routine Description:
  639. runs all functions from g_LastSystemRoutines array.
  640. If the messageId is not 0 also updates progress bar title.
  641. Arguments:
  642. none
  643. Return value:
  644. Win32 status code.
  645. --*/
  646. {
  647. DWORD Result;
  648. Result = pProcessTable (REQUEST_RUN, g_LastSystemRoutines);
  649. TerminateProcessingTable();
  650. if (Result == ERROR_SUCCESS) {
  651. pGlobalProcessingTerminate();
  652. }
  653. return Result;
  654. }
  655. DWORD
  656. AddDefaultCleanUpDirs (
  657. DWORD Request
  658. )
  659. {
  660. switch (Request) {
  661. case REQUEST_QUERYTICKS:
  662. return TICKS_ADDDEFAULTCLEANUPDIRS;
  663. case REQUEST_RUN:
  664. MemDbSetValueEx (
  665. MEMDB_CATEGORY_CLEAN_UP_DIR,
  666. g_SystemDir,
  667. NULL,
  668. NULL,
  669. 0,
  670. NULL
  671. );
  672. MemDbSetValueEx (
  673. MEMDB_CATEGORY_CLEAN_UP_DIR,
  674. g_ProgramFilesDir,
  675. NULL,
  676. NULL,
  677. 0,
  678. NULL
  679. );
  680. break;
  681. }
  682. return ERROR_SUCCESS;
  683. }
  684. VOID
  685. pGlobalProcessingInit (
  686. VOID
  687. )
  688. {
  689. TCHAR TempPath[MAX_TCHAR_PATH];
  690. InitGlobalPaths();
  691. if (!BeginIconExtraction (&g_IconContext, NULL)) {
  692. LOG ((LOG_ERROR, "DefaultIconPreservation: Can't start icon extraction"));
  693. return;
  694. }
  695. wsprintf (TempPath, TEXT("%s\\%s"), g_TempDir, S_MIGICONS_DAT);
  696. if (!OpenIconImageFile (&g_IconContext, TempPath, TRUE)) {
  697. LOG ((LOG_ERROR, "DefaultIconPreservation: Can't create %s", TempPath));
  698. EndIconExtraction (&g_IconContext);
  699. }
  700. return;
  701. }
  702. VOID
  703. pGlobalProcessingTerminate (
  704. VOID
  705. )
  706. {
  707. EndIconExtraction (&g_IconContext);
  708. }
  709. VOID
  710. pAddAllIds (
  711. IN PCTSTR IdList
  712. )
  713. {
  714. PCTSTR Temp;
  715. PTSTR p;
  716. CHARTYPE ch;
  717. Temp = DuplicateText (IdList);
  718. p = _tcspbrk (Temp, TEXT("&\\"));
  719. while (p) {
  720. ch = *p;
  721. *p = 0;
  722. DEBUGMSG ((DBG_NAUSEA, "System has PNP ID: %s", Temp));
  723. MemDbSetValueEx (
  724. MEMDB_CATEGORY_PNPIDS,
  725. Temp,
  726. NULL,
  727. NULL,
  728. 0,
  729. NULL
  730. );
  731. *p = (TCHAR)ch;
  732. p = _tcspbrk (_tcsinc (p), TEXT("&\\"));
  733. }
  734. FreeText (Temp);
  735. }
  736. DWORD
  737. PreparePnpIdList (
  738. DWORD Request
  739. )
  740. /*++
  741. Routine Description:
  742. PreparePnpIdList puts all PNP IDs in a memdb category to allow the PNPID
  743. attribute to work in migdb.inf.
  744. Arguments:
  745. Request - Specifies REQUEST_QUERYTICKS or REQUEST_RUN.
  746. Return Value:
  747. Always TICKS_PREPAREPNPIDLIST for REQUEST_QUERYTICKS, always ERROR_SUCCESS for REQUEST_RUN.
  748. --*/
  749. {
  750. HARDWARE_ENUM e;
  751. PTSTR p;
  752. if (Request == REQUEST_RUN) {
  753. if (EnumFirstHardware (
  754. &e,
  755. ENUM_ALL_DEVICES,
  756. ENUM_DONT_WANT_DEV_FIELDS|ENUM_DONT_WANT_USER_SUPPLIED|ENUM_DONT_REQUIRE_HARDWAREID
  757. )) {
  758. do {
  759. //
  760. // Add each part of the PNP ID as an endpoint
  761. //
  762. //
  763. // Skip past HKLM\Enum and add all IDs with the root
  764. //
  765. p = _tcschr (e.FullKey, TEXT('\\'));
  766. p = _tcschr (_tcsinc (p), TEXT('\\'));
  767. p = _tcsinc (p);
  768. pAddAllIds (p);
  769. //
  770. // Add all IDs without the root
  771. //
  772. pAddAllIds (e.InstanceId);
  773. } while (EnumNextHardware (&e));
  774. }
  775. return ERROR_SUCCESS;
  776. } else {
  777. return TICKS_PREPAREPNPIDLIST;
  778. }
  779. }
  780. DWORD
  781. PrepareIconList (
  782. DWORD Request
  783. )
  784. /*++
  785. Routine Description:
  786. PrepareIconList reads win95upg.inf [Moved Icons] and puts them
  787. in memdb for future use.
  788. Arguments:
  789. Request - Specifies REQUEST_QUERYTICKS or REQUEST_RUN.
  790. Return Value:
  791. Always TICKS_PREPAREPNPIDLIST for REQUEST_QUERYTICKS, always ERROR_SUCCESS
  792. for REQUEST_RUN.
  793. --*/
  794. {
  795. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  796. PCTSTR srcPath;
  797. TCHAR expandedSrcPath[MAX_TCHAR_PATH];
  798. PCTSTR destPath;
  799. TCHAR expandedDestPath[MAX_TCHAR_PATH];
  800. INT srcIndex;
  801. INT destIndex;
  802. INT srcId;
  803. INT destId;
  804. BOOL ok;
  805. DWORD destOffset;
  806. TCHAR num[32];
  807. TCHAR node[MEMDB_MAX];
  808. if (Request == REQUEST_RUN) {
  809. if (InfFindFirstLine (g_Win95UpgInf, S_MOVED_ICONS, NULL, &is)) {
  810. do {
  811. srcPath = InfGetStringField (&is, 1);
  812. ok = (srcPath != NULL);
  813. ok = ok && InfGetIntField (&is, 2, &srcIndex);
  814. ok = ok && (srcIndex >= 0);
  815. ok = ok && InfGetIntField (&is, 3, &srcId);
  816. ok = ok && (srcId >= 0);
  817. destPath = InfGetStringField (&is, 4);
  818. ok = ok && (destPath != NULL);
  819. ok = ok && InfGetIntField (&is, 5, &destIndex);
  820. ok = ok && (destIndex >= 0);
  821. ok = ok && InfGetIntField (&is, 6, &destId);
  822. ok = ok && (destId >= 0);
  823. if (!ok) {
  824. DEBUGMSG ((DBG_WHOOPS, "Syntax error in %s of win95upg.inf", S_MOVED_ICONS));
  825. } else {
  826. //
  827. // Convert env vars in srcPath and destPath
  828. //
  829. Expand9xEnvironmentVariables (
  830. srcPath,
  831. expandedSrcPath,
  832. sizeof (expandedSrcPath)
  833. );
  834. Expand9xEnvironmentVariables (
  835. destPath,
  836. expandedDestPath,
  837. sizeof (expandedDestPath)
  838. );
  839. //
  840. // Write out memdb nodes
  841. //
  842. MemDbSetValueEx (
  843. MEMDB_CATEGORY_DATA,
  844. expandedDestPath,
  845. NULL,
  846. NULL,
  847. 0,
  848. &destOffset
  849. );
  850. wsprintf (num, TEXT("%i"), srcIndex);
  851. MemDbBuildKey (
  852. node,
  853. MEMDB_CATEGORY_ICONS_MOVED,
  854. expandedSrcPath,
  855. num,
  856. NULL
  857. );
  858. MemDbSetValueAndFlags (node, destOffset, destIndex, 0xFFFFFFFF);
  859. wsprintf (num, TEXT("-%i"), srcId);
  860. MemDbBuildKey (
  861. node,
  862. MEMDB_CATEGORY_ICONS_MOVED,
  863. expandedSrcPath,
  864. num,
  865. NULL
  866. );
  867. MemDbSetValueAndFlags (node, destOffset, destId, 0xFFFFFFFF);
  868. }
  869. } while (InfFindNextLine (&is));
  870. }
  871. return ERROR_SUCCESS;
  872. } else {
  873. return TICKS_PREPAREPNPIDLIST;
  874. }
  875. }
  876. VOID
  877. pWriteAccountToMemDb (
  878. PUSERENUM EnumPtr
  879. )
  880. {
  881. HKEY LogonKey, AuthAgentKey=NULL;
  882. PCTSTR LastLoggedOnUser, Provider, AuthAgent=NULL;
  883. TCHAR Domain[MAX_SERVER_NAME];
  884. BOOL MsNetInstalled = FALSE;
  885. //
  886. // Write account name to KnownDomain if the user was the
  887. // last logged on user
  888. //
  889. Domain[0] = 0;
  890. //
  891. // Determine if Microsoft Network is installed
  892. //
  893. if ((EnumPtr -> AccountType & LOGON_PROMPT) || (EnumPtr -> AccountType & DEFAULT_USER)) {
  894. //
  895. // Nothing to do for logon user.
  896. //
  897. return;
  898. } else if (EnumPtr -> AccountType & ADMINISTRATOR) {
  899. //
  900. // Because this user is the local Administrator, we must default
  901. // to a local account. We get this behavior by assuming the
  902. // MSNP32 key doesn't exist (even if it really does).
  903. //
  904. AuthAgentKey = NULL;
  905. } else if (EnumPtr -> AccountType & DEFAULT_USER) {
  906. //
  907. // Nothing to do for default user
  908. //
  909. return;
  910. } else {
  911. //
  912. // Real user. Get the MSNP32 key.
  913. //
  914. AuthAgentKey = OpenRegKeyStr (S_MSNP32);
  915. }
  916. if (AuthAgentKey) {
  917. //
  918. // If last logged on user was the same as the user being processed,
  919. // and the user is a Microsoft Network user, obtain the domain name.
  920. //
  921. MsNetInstalled = TRUE;
  922. LogonKey = OpenRegKeyStr (S_LOGON_KEY);
  923. if (LogonKey) {
  924. LastLoggedOnUser = GetRegValueData (LogonKey, S_USERNAME_VALUE);
  925. if (LastLoggedOnUser) {
  926. if (StringIMatch (LastLoggedOnUser, EnumPtr -> UserName)) {
  927. //
  928. // User is the same as last logged on user. If the primary
  929. // provider is Microsoft Network, then get the authenticating
  930. // agent (which is the domain name).
  931. //
  932. Provider = GetRegValueData (LogonKey, S_PRIMARY_PROVIDER);
  933. if (Provider) {
  934. if (StringIMatch (Provider, S_LANMAN)) {
  935. //
  936. // Obtain the domain name
  937. //
  938. if (AuthAgentKey) {
  939. AuthAgent = GetRegValueData (AuthAgentKey, S_AUTHENTICATING_AGENT);
  940. if (AuthAgent) {
  941. StringCopy (Domain, AuthAgent);
  942. MemFree (g_hHeap, 0, AuthAgent);
  943. }
  944. }
  945. }
  946. MemFree (g_hHeap, 0, Provider);
  947. }
  948. }
  949. MemFree (g_hHeap, 0, LastLoggedOnUser);
  950. }
  951. CloseRegKey (LogonKey);
  952. }
  953. CloseRegKey (AuthAgentKey);
  954. }
  955. if (!MsNetInstalled || *Domain) {
  956. //
  957. // Assuming we have a valid user name:
  958. // If MSNP32 is not installed, default to a local account.
  959. // If it is installed, we must have a valid domain name.
  960. //
  961. // If we do not have a valid user name, then the current user
  962. // is the .Default account, which does not need to be verified
  963. // on the net.
  964. //
  965. if (*EnumPtr -> UserName) {
  966. MemDbSetValueEx (MEMDB_CATEGORY_KNOWNDOMAIN, Domain, EnumPtr -> FixedUserName, NULL, 0, NULL);
  967. }
  968. } else {
  969. //
  970. // MSNP32 is installed, but the domain name for this user is unknown.
  971. // Perform a search.
  972. //
  973. MemDbSetValueEx (MEMDB_CATEGORY_AUTOSEARCH, EnumPtr -> FixedUserName, NULL, NULL, 0, NULL);
  974. }
  975. }
  976. BOOL
  977. pReportMapiIfNotHandled (
  978. VOID
  979. )
  980. {
  981. PCTSTR Group;
  982. PCTSTR Message;
  983. TCHAR pattern[MEMDB_MAX];
  984. MEMDB_ENUM enumItems;
  985. BOOL addMsg = FALSE;
  986. DWORD status = 0;
  987. HKEY key;
  988. key = OpenRegKeyStr (S_INBOX_CFG);
  989. if (key) {
  990. CloseRegKey (key);
  991. MemDbBuildKey (pattern, MEMDB_CATEGORY_MAPI32_LOCATIONS, TEXT("*"), NULL, NULL);
  992. if (MemDbEnumFirstValue (&enumItems, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  993. do {
  994. if (IsReportObjectHandled (enumItems.szName)) {
  995. continue;
  996. }
  997. status = GetFileStatusOnNt (enumItems.szName);
  998. if ((status & FILESTATUS_REPLACED) != FILESTATUS_REPLACED) {
  999. addMsg = TRUE;
  1000. break;
  1001. }
  1002. } while (MemDbEnumNextValue (&enumItems));
  1003. }
  1004. }
  1005. if (addMsg) {
  1006. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_MAPI_NOT_HANDLED_SUBGROUP, NULL);
  1007. Message = GetStringResource (MSG_MAPI_NOT_HANDLED);
  1008. if (Message && Group) {
  1009. MsgMgr_ObjectMsg_Add (TEXT("*MapiNotHandled"), Group, Message);
  1010. }
  1011. FreeText (Group);
  1012. FreeStringResource (Message);
  1013. }
  1014. return TRUE;
  1015. }
  1016. DWORD
  1017. ReportMapiIfNotHandled (
  1018. IN DWORD Request
  1019. )
  1020. {
  1021. switch (Request) {
  1022. case REQUEST_QUERYTICKS:
  1023. return TICKS_REPORTMAPIIFNOTHANDLED;
  1024. case REQUEST_RUN:
  1025. if (pReportMapiIfNotHandled ()) {
  1026. return ERROR_SUCCESS;
  1027. }
  1028. return GetLastError ();
  1029. }
  1030. return ERROR_SUCCESS;
  1031. }
  1032. DWORD
  1033. GatherImeInfo (
  1034. IN DWORD Request
  1035. )
  1036. {
  1037. REGKEY_ENUM e;
  1038. PCTSTR imeFile = NULL;
  1039. TCHAR imePath[MAX_TCHAR_PATH];
  1040. HKEY topKey = NULL;
  1041. HKEY layoutKey = NULL;
  1042. UINT status = 0;
  1043. switch (Request) {
  1044. case REQUEST_QUERYTICKS:
  1045. return TICKS_GATHER_IME_INFO;
  1046. break;
  1047. case REQUEST_RUN:
  1048. //
  1049. // Enumerate through the keyboard layout registry looking for IMEs.
  1050. //
  1051. topKey = OpenRegKeyStr (S_KEYBOARD_LAYOUT_REG);
  1052. if (!topKey) {
  1053. DEBUGMSG ((DBG_ERROR, "Could not open keyboard layouts registry."));
  1054. return ERROR_SUCCESS;
  1055. }
  1056. if (EnumFirstRegKey (&e, topKey)) {
  1057. do {
  1058. //
  1059. // We only care about IME entries.
  1060. //
  1061. if (*e.SubKeyName == TEXT('e') || *e.SubKeyName == TEXT('E')) {
  1062. layoutKey = OpenRegKey (topKey, e.SubKeyName);
  1063. if (layoutKey) {
  1064. imeFile = GetRegValueString (layoutKey, TEXT("IME File"));
  1065. if (imeFile && SearchPath (NULL, imeFile, NULL, MAX_TCHAR_PATH, imePath, NULL)) {
  1066. //
  1067. // We are only going to migrate this IME file if it is left around after we
  1068. // are done.
  1069. //
  1070. status = GetFileStatusOnNt (imePath);
  1071. if ((status & FILESTATUS_DELETED) == 0) {
  1072. MemDbSetValueEx (MEMDB_CATEGORY_GOOD_IMES, imeFile, NULL, NULL, 0, NULL);
  1073. }
  1074. ELSE_DEBUGMSG ((DBG_NAUSEA, "IME %s will be suppressed from the keyboard layout merge.", e.SubKeyName));
  1075. }
  1076. if (imeFile) {
  1077. MemFree (g_hHeap, 0, imeFile);
  1078. }
  1079. CloseRegKey (layoutKey);
  1080. }
  1081. }
  1082. } while (EnumNextRegKey (&e));
  1083. }
  1084. CloseRegKey (topKey);
  1085. break;
  1086. }
  1087. return ERROR_SUCCESS;
  1088. }
  1089. PEVALFN
  1090. pFindEvalFnByName (
  1091. IN PCTSTR FnName
  1092. )
  1093. {
  1094. INT i;
  1095. i = 0;
  1096. while (g_MapNameToEvalFn[i].FnName) {
  1097. if (StringMatch (FnName, g_MapNameToEvalFn[i].FnName)) {
  1098. return g_MapNameToEvalFn[i].EvalFn;
  1099. }
  1100. i++;
  1101. }
  1102. return NULL;
  1103. }
  1104. DWORD
  1105. DeleteStaticFiles (
  1106. IN DWORD Request
  1107. )
  1108. {
  1109. #define MAX_DRIVE_STRINGS (26 * 4 + 1)
  1110. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1111. PCTSTR Data;
  1112. TCHAR ExpandedData[MAX_TCHAR_PATH];
  1113. PTSTR Pattern;
  1114. FILE_ENUM e;
  1115. BOOL Negate, Eval;
  1116. PEVALFN fn;
  1117. DWORD attr;
  1118. TCHAR drives[MAX_DRIVE_STRINGS];
  1119. DWORD rc;
  1120. PTSTR p;
  1121. PCTSTR q;
  1122. TREE_ENUM eFiles;
  1123. switch (Request) {
  1124. case REQUEST_QUERYTICKS:
  1125. return TICKS_DELETESTATICFILES;
  1126. case REQUEST_RUN:
  1127. if (InfFindFirstLine (g_Win95UpgInf, S_FILES_TO_REMOVE, NULL, &is)) {
  1128. do {
  1129. Data = InfGetStringField (&is, 1);
  1130. if (!Data) {
  1131. continue;
  1132. }
  1133. Expand9xEnvironmentVariables (
  1134. Data,
  1135. ExpandedData,
  1136. sizeof (ExpandedData)
  1137. );
  1138. Data = InfGetStringField (&is, 2);
  1139. if (Data) {
  1140. if (*Data == TEXT('!')) {
  1141. ++Data;
  1142. Negate = TRUE;
  1143. } else {
  1144. Negate = FALSE;
  1145. }
  1146. //
  1147. // call the function by name
  1148. //
  1149. fn = pFindEvalFnByName (Data);
  1150. //
  1151. // did you forget to implement it?
  1152. //
  1153. MYASSERT (fn);
  1154. if (!fn) {
  1155. //
  1156. // don't remove the file/dir
  1157. //
  1158. continue;
  1159. }
  1160. } else {
  1161. fn = NULL;
  1162. }
  1163. p = drives;
  1164. if (*ExpandedData == TEXT('?')) {
  1165. ACCESSIBLE_DRIVE_ENUM ae;
  1166. if (GetFirstAccessibleDrive (&ae)) {
  1167. do {
  1168. *p++ = ae->Drive[0];
  1169. } while (GetNextAccessibleDrive (&ae));
  1170. }
  1171. } else {
  1172. *p++ = *ExpandedData;
  1173. }
  1174. *p = 0;
  1175. p = drives;
  1176. do {
  1177. *ExpandedData = *p++;
  1178. attr = GetFileAttributes (ExpandedData);
  1179. if ((attr != -1) && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
  1180. if (fn) {
  1181. Eval = (*fn)(ExpandedData, &is, 3) ? TRUE : FALSE;
  1182. //
  1183. // !Negate && !Eval || Negate && Eval means !(Negate ^ Eval)
  1184. //
  1185. if (!(Negate ^ Eval)) {
  1186. //
  1187. // don't remove the directory
  1188. //
  1189. continue;
  1190. }
  1191. }
  1192. if (IsDriveExcluded (ExpandedData)) {
  1193. DEBUGMSG ((DBG_VERBOSE, "Skipping static file %s because it is excluded", ExpandedData));
  1194. continue;
  1195. }
  1196. if (!IsDriveAccessible (ExpandedData)) {
  1197. DEBUGMSG ((DBG_VERBOSE, "Skipping static file %s because it is not accessible", ExpandedData));
  1198. continue;
  1199. }
  1200. if (EnumFirstFileInTree (&eFiles, ExpandedData, NULL, FALSE)) {
  1201. do {
  1202. //
  1203. // Tally up the saved bytes, and free the space on the drive.
  1204. //
  1205. FreeSpace (
  1206. eFiles.FullPath,
  1207. eFiles.FindData->nFileSizeHigh * MAXDWORD + eFiles.FindData->nFileSizeLow
  1208. );
  1209. } while (EnumNextFileInTree (&eFiles));
  1210. }
  1211. MemDbSetValueEx (MEMDB_CATEGORY_FULL_DIR_DELETES, ExpandedData, NULL, NULL, 0, NULL);
  1212. } else {
  1213. Pattern = _tcsrchr (ExpandedData, TEXT('\\'));
  1214. //
  1215. // full path please
  1216. //
  1217. MYASSERT (Pattern);
  1218. if (!Pattern) {
  1219. continue;
  1220. }
  1221. *Pattern = 0;
  1222. if (EnumFirstFile (&e, ExpandedData, Pattern + 1)) {
  1223. do {
  1224. if (fn) {
  1225. Eval = (*fn)(e.FullPath, &is, 3) ? TRUE : FALSE;
  1226. //
  1227. // !Negate && !Eval || Negate && Eval means !(Negate ^ Eval)
  1228. //
  1229. if (!(Negate ^ Eval)) {
  1230. //
  1231. // don't remove the file
  1232. //
  1233. continue;
  1234. }
  1235. }
  1236. MarkFileForDelete (e.FullPath);
  1237. } while (EnumNextFile (&e));
  1238. }
  1239. *Pattern = TEXT('\\');
  1240. }
  1241. } while (*p);
  1242. } while (InfFindNextLine (&is));
  1243. }
  1244. InfCleanUpInfStruct (&is);
  1245. break;
  1246. }
  1247. return ERROR_SUCCESS;
  1248. }
  1249. BOOL
  1250. Boot16Enabled (
  1251. IN PCTSTR PathToEval,
  1252. IN OUT PINFSTRUCT InfStruct,
  1253. IN UINT FirstArgIndex
  1254. )
  1255. {
  1256. //
  1257. // at this point, check *g_ForceNTFSConversion to be FALSE
  1258. // and *g_Boot16 not to be disabled
  1259. //
  1260. return (!*g_ForceNTFSConversion) && (*g_Boot16 != BOOT16_NO);
  1261. }
  1262. BOOL
  1263. DoesRegKeyValuesExist (
  1264. IN PCTSTR PathToEval,
  1265. IN OUT PINFSTRUCT InfStruct,
  1266. IN UINT FirstArgIndex
  1267. )
  1268. {
  1269. PCTSTR RegKey;
  1270. PCTSTR Value;
  1271. HKEY key;
  1272. BOOL b = FALSE;
  1273. RegKey = InfGetStringField (InfStruct, FirstArgIndex++);
  1274. if (RegKey) {
  1275. key = OpenRegKeyStr (RegKey);
  1276. if (key) {
  1277. b = TRUE;
  1278. while (b && (Value = InfGetStringField (InfStruct, FirstArgIndex++)) != NULL) {
  1279. b = (RegQueryValueEx (key, Value, NULL, NULL, NULL, NULL) == ERROR_SUCCESS);
  1280. }
  1281. CloseRegKey (key);
  1282. }
  1283. }
  1284. return b;
  1285. }
  1286. BOOL
  1287. IsMillennium (
  1288. IN PCTSTR PathToEval,
  1289. IN OUT PINFSTRUCT InfStruct,
  1290. IN UINT FirstArgIndex
  1291. )
  1292. {
  1293. return ISMILLENNIUM();
  1294. }
  1295. /*++
  1296. Routine Description:
  1297. GatherDead() gathers disabled or bad objects (apps, cpls, runkeys,
  1298. links) and saves them to a file (dead.ini) so they can be tested
  1299. to see if they actually are not bad. This functions only in
  1300. PRERELEASE mode.
  1301. Arguments:
  1302. Request - reason for calling function
  1303. Return Value:
  1304. if in REQUEST_RUN mode, always returns ERROR_SUCCESS
  1305. because we don't want to break setup.
  1306. --*/
  1307. DWORD
  1308. GatherDead (
  1309. IN DWORD Request
  1310. )
  1311. {
  1312. FILEOP_ENUM FileEnum;
  1313. MEMDB_ENUM MemDbEnum;
  1314. REGVALUE_ENUM RegEnum;
  1315. HKEY Key;
  1316. HANDLE File;
  1317. TCHAR Temp[MEMDB_MAX];
  1318. TCHAR MemDbKey[MEMDB_MAX];
  1319. TCHAR DeadPath[MEMDB_MAX];
  1320. PTSTR Data;
  1321. switch (Request) {
  1322. case REQUEST_QUERYTICKS:
  1323. #ifndef PRERELEASE
  1324. return 0;
  1325. #else
  1326. return TICKS_GATHERDEAD;
  1327. #endif //PRERELEASE
  1328. case REQUEST_RUN:
  1329. //
  1330. // We only do stuff here if in PRERELEASE mode, because
  1331. // in release mode REQUEST_QUERYTICKS returns 0, so
  1332. // REQUEST_RUN is not called.
  1333. //
  1334. wsprintf (DeadPath, TEXT("%s\\%s"), g_WinDir, DEAD_FILE);
  1335. File = CreateFile (
  1336. DeadPath,
  1337. GENERIC_WRITE,
  1338. 0,
  1339. NULL,
  1340. CREATE_ALWAYS,
  1341. FILE_ATTRIBUTE_NORMAL,
  1342. NULL
  1343. );
  1344. if (File==INVALID_HANDLE_VALUE) {
  1345. DEBUGMSG ((DBG_WARNING, "Could not create " DEAD_FILE "!"));
  1346. return ERROR_SUCCESS;
  1347. }
  1348. WriteFileString(File, TEXT("[Version]\r\nSignature=\"$Chicago$\""));
  1349. WriteFileString(File, TEXT("\r\n\r\n[DEAD]\r\n"));
  1350. //
  1351. // add links to dead.ini file
  1352. //
  1353. if (MemDbEnumFirstValue (
  1354. &MemDbEnum,
  1355. MEMDB_CATEGORY_LINKEDIT,
  1356. MEMDB_ALL_SUBLEVELS,
  1357. MEMDB_ENDPOINTS_ONLY
  1358. ))
  1359. {
  1360. do {
  1361. wsprintf(Temp, TEXT("%s=%d\r\n"), MemDbEnum.szName, OBJECTTYPE_LINK);
  1362. WriteFileString(File, Temp);
  1363. } while (MemDbEnumNextValue (&MemDbEnum));
  1364. }
  1365. //
  1366. // add bad apps to dead.ini file
  1367. //
  1368. if (MemDbEnumFirstValue (
  1369. &MemDbEnum,
  1370. MEMDB_CATEGORY_MODULE_CHECK,
  1371. MEMDB_ALL_SUBLEVELS,
  1372. MEMDB_ENDPOINTS_ONLY
  1373. ))
  1374. {
  1375. do {
  1376. //
  1377. // only include app if it is marked as 'bad'
  1378. //
  1379. if (MemDbEnum.dwValue==MODULESTATUS_BAD) {
  1380. wsprintf(Temp, TEXT("%s=%d\r\n"), MemDbEnum.szName, OBJECTTYPE_APP);
  1381. WriteFileString(File, Temp);
  1382. }
  1383. } while (MemDbEnumNextValue (&MemDbEnum));
  1384. }
  1385. //
  1386. // add CPLs in OPERATION_FILE_DISABLED
  1387. //
  1388. if (EnumFirstPathInOperation (&FileEnum, OPERATION_FILE_DISABLED)) {
  1389. do {
  1390. //
  1391. // only include disabled CPLs (for now, thats all there is)
  1392. //
  1393. if (_tcsistr(FileEnum.Path, TEXT(".cpl"))) {
  1394. wsprintf(Temp, TEXT("%s=%d\r\n"), FileEnum.Path, OBJECTTYPE_CPL);
  1395. WriteFileString(File, Temp);
  1396. }
  1397. } while (EnumNextPathInOperation (&FileEnum));
  1398. }
  1399. //
  1400. // add RunKeys that are not in COMPATIBLE_RUNKEY list
  1401. //
  1402. if (Key = OpenRegKeyStr (S_RUN_KEY))
  1403. {
  1404. if (EnumFirstRegValue(&RegEnum, Key))
  1405. {
  1406. do {
  1407. Data=GetRegValueString(Key, RegEnum.ValueName);
  1408. MemDbBuildKey (
  1409. MemDbKey,
  1410. MEMDB_CATEGORY_COMPATIBLE_RUNKEY,
  1411. Data,
  1412. NULL,
  1413. NULL
  1414. );
  1415. //
  1416. // only add runkey to dead.ini if it was not put
  1417. // in the compatible runkey memdb category.
  1418. // (we only want incompatible runkeys)
  1419. //
  1420. if (!MemDbGetValue(MemDbKey, NULL))
  1421. {
  1422. //
  1423. // we have a friendly name (ValueName)
  1424. // so include it in dead.ini
  1425. //
  1426. wsprintf (
  1427. Temp,
  1428. TEXT("%s=%d,%s\r\n"),
  1429. Data,
  1430. OBJECTTYPE_RUNKEY,
  1431. RegEnum.ValueName
  1432. );
  1433. WriteFileString(File, Temp);
  1434. }
  1435. MemFreeWrapper(Data);
  1436. } while (EnumNextRegValue(&RegEnum));
  1437. }
  1438. CloseRegKey (Key);
  1439. }
  1440. WriteFileString(File, TEXT("\r\n"));
  1441. CloseHandle(File);
  1442. break;
  1443. }
  1444. return ERROR_SUCCESS;
  1445. }
  1446. VOID
  1447. pReportDarwinIfNotHandled (
  1448. VOID
  1449. )
  1450. {
  1451. PCTSTR Group;
  1452. PCTSTR Message;
  1453. HKEY key;
  1454. DWORD rc;
  1455. DWORD subkeys;
  1456. MSGMGROBJENUM e;
  1457. key = OpenRegKeyStr (S_REGKEY_DARWIN_COMPONENTS);
  1458. if (key) {
  1459. rc = RegQueryInfoKey (key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  1460. if (rc == ERROR_SUCCESS && subkeys) {
  1461. if (!IsReportObjectHandled (S_REGKEY_DARWIN_COMPONENTS)) {
  1462. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_DARWIN_NOT_HANDLED_SUBGROUP, NULL);
  1463. Message = GetStringResource (MSG_DARWIN_NOT_HANDLED);
  1464. if (Message && Group) {
  1465. MsgMgr_ObjectMsg_Add (TEXT("*DarwinNotHandled"), Group, Message);
  1466. //
  1467. // disable Outlook 2000 message
  1468. //
  1469. if (MsgMgr_EnumFirstObject (&e)) {
  1470. do {
  1471. if (StringMatch (e.Context, TEXT("Microsoft_Outlook_2000"))) {
  1472. HandleReportObject (e.Object);
  1473. break;
  1474. }
  1475. } while (MsgMgr_EnumNextObject (&e));
  1476. }
  1477. }
  1478. FreeText (Group);
  1479. FreeStringResource (Message);
  1480. }
  1481. }
  1482. CloseRegKey (key);
  1483. }
  1484. }
  1485. DWORD
  1486. ReportDarwinIfNotHandled (
  1487. IN DWORD Request
  1488. )
  1489. {
  1490. switch (Request) {
  1491. case REQUEST_QUERYTICKS:
  1492. return TICKS_REPORTDARWINIFNOTHANDLED;
  1493. case REQUEST_RUN:
  1494. pReportDarwinIfNotHandled ();
  1495. break;
  1496. }
  1497. return ERROR_SUCCESS;
  1498. }
  1499. DWORD
  1500. ElevateReportObjects (
  1501. IN DWORD Request
  1502. )
  1503. {
  1504. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  1505. PCTSTR data;
  1506. switch (Request) {
  1507. case REQUEST_QUERYTICKS:
  1508. return 1;
  1509. case REQUEST_RUN:
  1510. if (InfFindFirstLine (g_Win95UpgInf, TEXT("ShowInSimplifiedView"), NULL, &is)) {
  1511. do {
  1512. data = InfGetStringField (&is, 1);
  1513. if (data) {
  1514. ElevateObject (data);
  1515. }
  1516. } while (InfFindNextLine (&is));
  1517. }
  1518. InfCleanUpInfStruct (&is);
  1519. return ERROR_SUCCESS;
  1520. default:
  1521. DEBUGMSG ((DBG_ERROR, "Bad parameter in CopyStaticFiles."));
  1522. }
  1523. return 0;
  1524. }