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.

710 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. defer.c
  5. Abstract:
  6. This module implements deferred initialization, code that must run only
  7. after WINNT32 has obtained source directories.
  8. Author:
  9. Jim Schmidt (jimschm) 08-Jan-1998
  10. Revision History:
  11. jimschm 23-Sep-1998 InitNtEnvironment move
  12. --*/
  13. #include "pch.h"
  14. #include "init9xp.h"
  15. #include "ntverp.h"
  16. //
  17. // Local prototypes
  18. //
  19. HWND
  20. pFindProcessWindow (
  21. VOID
  22. );
  23. BOOL
  24. pGetProfilesDirectory (
  25. OUT PTSTR Path, OPTIONAL
  26. IN OUT PDWORD Size
  27. );
  28. INT
  29. pGetProcessorSpeed (
  30. OUT PTSTR *Family
  31. );
  32. BOOL
  33. pReloadWin95upgInf (
  34. VOID
  35. )
  36. {
  37. if (g_Win95UpgInf != INVALID_HANDLE_VALUE) {
  38. InfCloseInfFile (g_Win95UpgInf);
  39. g_Win95UpgInf = INVALID_HANDLE_VALUE;
  40. }
  41. MYASSERT (g_Win95UpgInfFile);
  42. g_Win95UpgInf = InfOpenInfFile (g_Win95UpgInfFile);
  43. return g_Win95UpgInf != INVALID_HANDLE_VALUE;
  44. }
  45. //
  46. // Implementation
  47. //
  48. BOOL
  49. pPutBootFileInUninstallTempDir (
  50. IN PCTSTR SrcFileName,
  51. IN PCTSTR DestFileName OPTIONAL
  52. )
  53. {
  54. PCTSTR src;
  55. PCTSTR dest;
  56. UINT rc = ERROR_SUCCESS;
  57. DWORD attribs;
  58. src = JoinPaths (g_BootDrivePath, SrcFileName);
  59. dest = JoinPaths (g_TempDir, DestFileName ? DestFileName : SrcFileName);
  60. if (DoesFileExist (src)) {
  61. SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
  62. DeleteFile (dest);
  63. if (!CopyFile (src, dest, FALSE)) {
  64. DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", src, dest));
  65. rc = GetLastError();
  66. }
  67. }
  68. SetLastError (rc);
  69. return rc == ERROR_SUCCESS;
  70. }
  71. BOOL
  72. DeferredInit (
  73. IN HWND WizardPageHandle
  74. )
  75. /*++
  76. Routine Description:
  77. DeferredInit performs all initialization that requires the source directories
  78. to be provied by Windows NT. It runs after the user has selected the
  79. correct source directory, and WINNT32 has validated the choice.
  80. Arguments:
  81. WizardPageHandle - Specifies handle to wizard page and is used to display
  82. abnormal end popups.
  83. Return Value:
  84. TRUE if init succeeds, or FALSE if it fails. If FALSE is returned,
  85. Setup terminates without any popups.
  86. --*/
  87. {
  88. INT speed;
  89. PSTR family;
  90. MEMORYSTATUS memoryStatus;
  91. UINT index;
  92. TCHAR ProfileTemp[MAX_TCHAR_PATH];
  93. DWORD Size;
  94. BYTE bootSector[FAT_BOOT_SECTOR_SIZE];
  95. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  96. DWORD dontCare;
  97. DWORD attribs;
  98. BOOL result = FALSE;
  99. TCHAR dest[MAX_TCHAR_PATH];
  100. HKEY key;
  101. LOG ((LOG_INFORMATION, "UpgradeModuleBuild: %u", VER_PRODUCTBUILD));
  102. __try {
  103. //
  104. // Update the list of INF modifications in %windir%\upginfs.
  105. //
  106. InitInfReplaceTable ();
  107. //
  108. // reload win95upg.inf if an update is available
  109. //
  110. if (g_UpginfsUpdated && *g_UpginfsUpdated) {
  111. if (!pReloadWin95upgInf ()) {
  112. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_WIN95UPG_RELOAD_FAILED, g_Win95UpgInfFile));
  113. __leave;
  114. }
  115. }
  116. //
  117. // Update the configuration settings (i.e. WINNT32 command line options)
  118. //
  119. if (!Cfg_InitializeUserOptions()) {
  120. if (!g_ConfigOptions.Help) {
  121. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
  122. }
  123. __leave;
  124. }
  125. //
  126. // Initialize safe/recovery mechanism
  127. //
  128. SafeModeInitialize (g_ConfigOptions.SafeMode);
  129. //
  130. // Initialize our fake NT environment block
  131. //
  132. InitNtEnvironment();
  133. //
  134. // Save parent window
  135. //
  136. g_ParentWndAlwaysValid = pFindProcessWindow();
  137. if (!g_ParentWndAlwaysValid) {
  138. DEBUGMSG ((DBG_WHOOPS, "Cannot find parent window handle!"));
  139. g_ParentWndAlwaysValid = GetParent(WizardPageHandle);
  140. }
  141. //
  142. // Make a symbol that is NULL in unattend mode, and a valid parent window
  143. // handle otherwise. This is used by migration DLLs and LOG functions.
  144. //
  145. g_ParentWnd = UNATTENDED() ? NULL : g_ParentWndAlwaysValid;
  146. LogReInit (&g_ParentWnd, NULL);
  147. //
  148. // Get information about the system we are running on...This can be very useful.
  149. //
  150. speed = pGetProcessorSpeed(&family);
  151. memoryStatus.dwLength = sizeof(MEMORYSTATUS);
  152. GlobalMemoryStatus(&memoryStatus);
  153. LOG((
  154. LOG_INFORMATION,
  155. "System Statistics:\n Family: %s\n Processor Speed: %u mhz\n Memory: %u bytes",
  156. family ? family : "Unknown",
  157. speed,
  158. memoryStatus.dwTotalPhys
  159. ));
  160. if (!Cfg_CreateWorkDirectories()) {
  161. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_COULD_NOT_CREATE_DIRECTORY));
  162. __leave;
  163. }
  164. //
  165. // Start background copy thread
  166. //
  167. StartCopyThread();
  168. //
  169. // Get NT Profile dir.
  170. //
  171. Size = sizeof (ProfileTemp) / sizeof (ProfileTemp[0]);
  172. if (!pGetProfilesDirectory (ProfileTemp, &Size)) {
  173. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
  174. __leave;
  175. }
  176. //
  177. // replace any NT string env vars with actual values
  178. //
  179. ExpandNtEnvironmentVariables (ProfileTemp, ProfileTemp, sizeof (ProfileTemp));
  180. g_ProfileDirNt = PoolMemDuplicateString (g_GlobalPool, ProfileTemp);
  181. DEBUGMSG ((DBG_NAUSEA, "NT profile dir: %s", g_ProfileDirNt));
  182. //
  183. // Put current user name in the setup key
  184. //
  185. Size = ARRAYSIZE (ProfileTemp);
  186. if (GetUserName (ProfileTemp, &Size)) {
  187. key = CreateRegKeyStr (S_WIN9XUPG_KEY);
  188. if (key) {
  189. RegSetValueEx (
  190. key,
  191. S_CURRENT_USER_VALUENAME,
  192. 0,
  193. REG_SZ,
  194. (PBYTE) ProfileTemp,
  195. SizeOfString (ProfileTemp)
  196. );
  197. CloseRegKey (key);
  198. }
  199. }
  200. //
  201. // Open txtsetup.sif
  202. //
  203. if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
  204. g_TxtSetupSif = InfOpenInfInAllSources (S_TXTSETUP_SIF);
  205. if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
  206. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_TXTSETUP_SIF_ERROR));
  207. __leave;
  208. }
  209. }
  210. if (!BeginMigrationDllProcessing()) {
  211. DEBUGMSG ((DBG_WARNING, "BeginMigrationDllProcessing returned FALSE"));
  212. __leave;
  213. }
  214. if (!InitAccessibleDrives()) {
  215. __leave;
  216. }
  217. //
  218. // exclude all of the directories in source directories and optional directories from processing.
  219. //
  220. for (index = 0; index < SOURCEDIRECTORYCOUNT(); index++) {
  221. ExcludePath (g_ExclusionValue, SOURCEDIRECTORY(index));
  222. }
  223. for (index = 0; index < OPTIONALDIRECTORYCOUNT(); index++) {
  224. ExcludePath (g_ExclusionValue, OPTIONALDIRECTORY(index));
  225. }
  226. //
  227. // also exclude the directory used by Dynamic Setup
  228. //
  229. if (g_DynamicUpdateLocalDir) {
  230. ExcludePath (g_ExclusionValue, g_DynamicUpdateLocalDir);
  231. }
  232. //
  233. // Put original boot.ini, bootfont.bin, ntdetect.com, ntldr and boot
  234. // sector in setup temp dir
  235. //
  236. if (g_BootDrivePath && g_TempDir) {
  237. if (!pPutBootFileInUninstallTempDir (S_BOOTINI, S_BOOTINI_BACKUP)) {
  238. __leave;
  239. }
  240. if (!pPutBootFileInUninstallTempDir (S_BOOTFONT_BIN, S_BOOTFONT_BACKUP)) {
  241. __leave;
  242. }
  243. if (!pPutBootFileInUninstallTempDir (S_NTDETECT, S_NTDETECT_BACKUP)) {
  244. __leave;
  245. }
  246. if (!pPutBootFileInUninstallTempDir (S_NTLDR, S_NTLDR_BACKUP)) {
  247. __leave;
  248. }
  249. if (ReadDiskSectors (
  250. *g_BootDrive,
  251. FAT_STARTING_SECTOR,
  252. FAT_BOOT_SECTOR_COUNT,
  253. FAT_BOOT_SECTOR_SIZE,
  254. bootSector
  255. )) {
  256. StringCopy (dest, g_TempDir);
  257. StringCopy (AppendWack (dest), S_BOOTSECT_BACKUP);
  258. fileHandle = CreateFile (
  259. dest,
  260. GENERIC_WRITE,
  261. 0,
  262. NULL,
  263. CREATE_ALWAYS,
  264. FILE_ATTRIBUTE_NORMAL,
  265. NULL
  266. );
  267. if (fileHandle == INVALID_HANDLE_VALUE) {
  268. DEBUGMSG ((DBG_ERROR, "Can't create %s", dest));
  269. __leave;
  270. }
  271. if (!WriteFile (fileHandle, bootSector, sizeof (bootSector), &dontCare, NULL)) {
  272. DEBUGMSG ((DBG_ERROR, "Can't write boot sector to %s", dest));
  273. __leave;
  274. }
  275. }
  276. } else {
  277. MYASSERT (FALSE);
  278. __leave;
  279. }
  280. result = TRUE;
  281. }
  282. __finally {
  283. if (fileHandle != INVALID_HANDLE_VALUE) {
  284. CloseHandle (fileHandle);
  285. }
  286. }
  287. return result;
  288. }
  289. BOOL
  290. pGetProfilesDirectory (
  291. OUT PTSTR Path, OPTIONAL
  292. IN OUT PDWORD Size
  293. )
  294. /*++
  295. Routine Description:
  296. pGetProfileDirectory emulates the NT 5 API GetProfileDirectory. It looks in
  297. hivesft.inf for Winlogon's ProfilesDirectory key. If an override to the NT
  298. profile directory is given in the winnt.sif file, then the override is used
  299. instead.
  300. Arguments:
  301. Path - Receives the user profile path
  302. Size - Specifies the size of Path, in TCHAR characters. Receives the number
  303. of characters needed to hold the profile path.
  304. Return Value:
  305. TRUE if the API succeeds, or FALSE if an unexpected error occurs.
  306. --*/
  307. {
  308. TCHAR Buffer[MAX_TCHAR_PATH];
  309. PCTSTR p;
  310. BOOL b;
  311. DWORD SizeNeeded;
  312. PCTSTR EndOfString;
  313. PCTSTR UserProfiles;
  314. if (!Size) {
  315. return FALSE;
  316. }
  317. MYASSERT (g_WinDir);
  318. MYASSERT (g_SourceDirectoryCountFromWinnt32);
  319. //
  320. // Look in answer file for setting, use it if it exists
  321. //
  322. Buffer[0] = 0;
  323. if (g_UnattendScriptFile && *g_UnattendScriptFile) {
  324. GetPrivateProfileString (
  325. S_GUIUNATTENDED,
  326. S_PROFILEDIR,
  327. S_EMPTY,
  328. Buffer,
  329. MAX_TCHAR_PATH,
  330. *g_UnattendScriptFile
  331. );
  332. }
  333. if (!(*Buffer)) {
  334. //
  335. // Default to %systemroot%\Documents and Settings
  336. //
  337. UserProfiles = GetStringResource (MSG_USER_PROFILE_ROOT);
  338. MYASSERT (UserProfiles);
  339. StringCopy (Buffer, UserProfiles);
  340. FreeStringResource (UserProfiles);
  341. }
  342. Buffer[MAX_TCHAR_PATH - 1] = 0; // user can pass in anything via answer file!
  343. SizeNeeded = ByteCount (Buffer) / sizeof (TCHAR);
  344. if (Path) {
  345. b = *Size >= SizeNeeded;
  346. if (*Size) {
  347. EndOfString = GetEndOfString (Buffer);
  348. p = min (EndOfString, Buffer + *Size);
  349. StringCopyAB (Path, Buffer, p);
  350. }
  351. } else {
  352. b = TRUE;
  353. }
  354. *Size = SizeNeeded;
  355. return b;
  356. }
  357. typedef struct {
  358. DWORD ProcessId;
  359. HWND hwnd;
  360. } FINDPROCESSWINDOW, *PFINDPROCESSWINDOW;
  361. BOOL
  362. CALLBACK
  363. pFindProcessWindowCallback (
  364. HWND hwnd,
  365. LPARAM lParam
  366. )
  367. /*++
  368. Routine Description:
  369. pFindProcessWindowCallback is called by the window enumeration started by
  370. pFindProcessWindow. If the process ID of the window matches our process
  371. ID, then the enumeration is stopped so the proper window handle can
  372. be returned by pFindProcessWindow.
  373. Arguments:
  374. hwnd - Specifies the current enumerated window handle
  375. lParam - Specifies the FINDPROCESSWINDOW structure allocated by
  376. pFindProcessWindow
  377. Return Value:
  378. TRUE if enuemration should continue, or FALSE if it should stop.
  379. --*/
  380. {
  381. PFINDPROCESSWINDOW p;
  382. DWORD ProcessId = 0;
  383. p = (PFINDPROCESSWINDOW) lParam;
  384. GetWindowThreadProcessId (hwnd, &ProcessId);
  385. if (ProcessId == p->ProcessId) {
  386. p->hwnd = hwnd;
  387. return FALSE;
  388. }
  389. return TRUE;
  390. }
  391. HWND
  392. pFindProcessWindow (
  393. VOID
  394. )
  395. /*++
  396. Routine Description:
  397. pFindProcessWindow enumerates all windows and returns the first one that
  398. the current process owns. There should only be one, so the end result
  399. is a handle to the main window of the process.
  400. Arguments:
  401. none
  402. Return Value:
  403. A handle to the process main window, or NULL if no windows exist for
  404. the process.
  405. --*/
  406. {
  407. FINDPROCESSWINDOW Enum;
  408. ZeroMemory (&Enum, sizeof (Enum));
  409. Enum.ProcessId = GetCurrentProcessId();
  410. EnumWindows (pFindProcessWindowCallback, (LPARAM) &Enum);
  411. return Enum.hwnd;
  412. }
  413. INT
  414. pGetProcessorSpeed (
  415. OUT PTSTR *Family
  416. )
  417. /*++
  418. Routine Description:
  419. pGetProcessorSpeed returns the speed in MHz of the computer, and identifies
  420. the processor if it is a Pentium or better. Code from Todd Laney (toddla).
  421. Arguments:
  422. Family - Receives a pointer to the name of the processor family
  423. Return Value:
  424. The speed of the processor, in MHz.
  425. --*/
  426. {
  427. SYSTEM_INFO si;
  428. __int64 start, end, freq;
  429. INT flags,family;
  430. INT time;
  431. INT clocks;
  432. DWORD oldclass;
  433. HANDLE hprocess;
  434. INT familyIndex = 0;
  435. static PTSTR familyStrings[] = {
  436. "Unknown (0)",
  437. "Unknown (1)",
  438. "Unknown (2)",
  439. "x386",
  440. "x486",
  441. "Pentium",
  442. "Pentium Pro",
  443. "Pentium II (?)",
  444. "Unknown..."
  445. };
  446. *Family = NULL;
  447. ZeroMemory(&si, sizeof(si));
  448. GetSystemInfo(&si);
  449. //Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
  450. //Because wProcessor level is not implemented on Win95
  451. if (si.wProcessorLevel) {
  452. family = si.wProcessorLevel;
  453. } else {
  454. family = 0;
  455. //Ok, we're on Win95
  456. switch (si.dwProcessorType) {
  457. case PROCESSOR_INTEL_386:
  458. familyIndex=3;
  459. break;
  460. case PROCESSOR_INTEL_486:
  461. familyIndex=4;
  462. break;
  463. default:
  464. familyIndex=0;
  465. break;
  466. }
  467. }
  468. //
  469. // make sure this is a INTEL Pentium (or clone) or higher.
  470. //
  471. if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
  472. return 0;
  473. if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
  474. return 0;
  475. //
  476. // see if this chip supports rdtsc before using it.
  477. //
  478. __try
  479. {
  480. _asm
  481. {
  482. mov eax,1
  483. _emit 00Fh ;; CPUID
  484. _emit 0A2h
  485. mov flags,edx
  486. mov family,eax
  487. }
  488. }
  489. __except(1)
  490. {
  491. flags = 0;
  492. }
  493. //check for support of CPUID and fail
  494. if (!(flags & 0x10))
  495. return 0;
  496. //If we don't have a family, set it now
  497. //Family is bits 11:8 of eax from CPU, with eax=1
  498. if (!familyIndex) {
  499. familyIndex=(family & 0x0F00) >> 8;
  500. }
  501. hprocess = GetCurrentProcess();
  502. oldclass = GetPriorityClass(hprocess);
  503. SetPriorityClass(hprocess, REALTIME_PRIORITY_CLASS);
  504. Sleep(10);
  505. QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  506. QueryPerformanceCounter((LARGE_INTEGER*)&start);
  507. _asm
  508. {
  509. _emit 0Fh ;; RDTSC
  510. _emit 31h
  511. mov ecx,100000
  512. x: dec ecx
  513. jnz x
  514. mov ebx,eax
  515. _emit 0Fh ;; RDTSC
  516. _emit 31h
  517. sub eax,ebx
  518. mov dword ptr clocks[0],eax
  519. }
  520. QueryPerformanceCounter((LARGE_INTEGER*)&end);
  521. SetPriorityClass(hprocess, oldclass);
  522. time = MulDiv((int)(end-start),1000000,(int)freq);
  523. if (familyIndex > 7) {
  524. familyIndex = 7;
  525. }
  526. *Family = familyStrings[familyIndex];
  527. return (clocks + time/2) / time;
  528. }