windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/w95upg/init9x/defer.c
2020-09-26 16:20:57 +08:00

711 lines
16 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
defer.c
Abstract:
This module implements deferred initialization, code that must run only
after WINNT32 has obtained source directories.
Author:
Jim Schmidt (jimschm) 08-Jan-1998
Revision History:
jimschm 23-Sep-1998 InitNtEnvironment move
--*/
#include "pch.h"
#include "init9xp.h"
#include "ntverp.h"
//
// Local prototypes
//
HWND
pFindProcessWindow (
VOID
);
BOOL
pGetProfilesDirectory (
OUT PTSTR Path, OPTIONAL
IN OUT PDWORD Size
);
INT
pGetProcessorSpeed (
OUT PTSTR *Family
);
BOOL
pReloadWin95upgInf (
VOID
)
{
if (g_Win95UpgInf != INVALID_HANDLE_VALUE) {
InfCloseInfFile (g_Win95UpgInf);
g_Win95UpgInf = INVALID_HANDLE_VALUE;
}
MYASSERT (g_Win95UpgInfFile);
g_Win95UpgInf = InfOpenInfFile (g_Win95UpgInfFile);
return g_Win95UpgInf != INVALID_HANDLE_VALUE;
}
//
// Implementation
//
BOOL
pPutBootFileInUninstallTempDir (
IN PCTSTR SrcFileName,
IN PCTSTR DestFileName OPTIONAL
)
{
PCTSTR src;
PCTSTR dest;
UINT rc = ERROR_SUCCESS;
DWORD attribs;
src = JoinPaths (g_BootDrivePath, SrcFileName);
dest = JoinPaths (g_TempDir, DestFileName ? DestFileName : SrcFileName);
if (DoesFileExist (src)) {
SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
DeleteFile (dest);
if (!CopyFile (src, dest, FALSE)) {
DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", src, dest));
rc = GetLastError();
}
}
SetLastError (rc);
return rc == ERROR_SUCCESS;
}
BOOL
DeferredInit (
IN HWND WizardPageHandle
)
/*++
Routine Description:
DeferredInit performs all initialization that requires the source directories
to be provied by Windows NT. It runs after the user has selected the
correct source directory, and WINNT32 has validated the choice.
Arguments:
WizardPageHandle - Specifies handle to wizard page and is used to display
abnormal end popups.
Return Value:
TRUE if init succeeds, or FALSE if it fails. If FALSE is returned,
Setup terminates without any popups.
--*/
{
INT speed;
PSTR family;
MEMORYSTATUS memoryStatus;
UINT index;
TCHAR ProfileTemp[MAX_TCHAR_PATH];
DWORD Size;
BYTE bootSector[FAT_BOOT_SECTOR_SIZE];
HANDLE fileHandle = INVALID_HANDLE_VALUE;
DWORD dontCare;
DWORD attribs;
BOOL result = FALSE;
TCHAR dest[MAX_TCHAR_PATH];
HKEY key;
LOG ((LOG_INFORMATION, "UpgradeModuleBuild: %u", VER_PRODUCTBUILD));
__try {
//
// Update the list of INF modifications in %windir%\upginfs.
//
InitInfReplaceTable ();
//
// reload win95upg.inf if an update is available
//
if (g_UpginfsUpdated && *g_UpginfsUpdated) {
if (!pReloadWin95upgInf ()) {
LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_WIN95UPG_RELOAD_FAILED, g_Win95UpgInfFile));
__leave;
}
}
//
// Update the configuration settings (i.e. WINNT32 command line options)
//
if (!Cfg_InitializeUserOptions()) {
if (!g_ConfigOptions.Help) {
LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
}
__leave;
}
//
// Initialize safe/recovery mechanism
//
SafeModeInitialize (g_ConfigOptions.SafeMode);
//
// Initialize our fake NT environment block
//
InitNtEnvironment();
//
// Save parent window
//
g_ParentWndAlwaysValid = pFindProcessWindow();
if (!g_ParentWndAlwaysValid) {
DEBUGMSG ((DBG_WHOOPS, "Cannot find parent window handle!"));
g_ParentWndAlwaysValid = GetParent(WizardPageHandle);
}
//
// Make a symbol that is NULL in unattend mode, and a valid parent window
// handle otherwise. This is used by migration DLLs and LOG functions.
//
g_ParentWnd = UNATTENDED() ? NULL : g_ParentWndAlwaysValid;
LogReInit (&g_ParentWnd, NULL);
//
// Get information about the system we are running on...This can be very useful.
//
speed = pGetProcessorSpeed(&family);
memoryStatus.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&memoryStatus);
LOG((
LOG_INFORMATION,
"System Statistics:\n Family: %s\n Processor Speed: %u mhz\n Memory: %u bytes",
family ? family : "Unknown",
speed,
memoryStatus.dwTotalPhys
));
if (!Cfg_CreateWorkDirectories()) {
LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_COULD_NOT_CREATE_DIRECTORY));
__leave;
}
//
// Start background copy thread
//
StartCopyThread();
//
// Get NT Profile dir.
//
Size = sizeof (ProfileTemp) / sizeof (ProfileTemp[0]);
if (!pGetProfilesDirectory (ProfileTemp, &Size)) {
LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
__leave;
}
//
// replace any NT string env vars with actual values
//
ExpandNtEnvironmentVariables (ProfileTemp, ProfileTemp, sizeof (ProfileTemp));
g_ProfileDirNt = PoolMemDuplicateString (g_GlobalPool, ProfileTemp);
DEBUGMSG ((DBG_NAUSEA, "NT profile dir: %s", g_ProfileDirNt));
//
// Put current user name in the setup key
//
Size = ARRAYSIZE (ProfileTemp);
if (GetUserName (ProfileTemp, &Size)) {
key = CreateRegKeyStr (S_WIN9XUPG_KEY);
if (key) {
RegSetValueEx (
key,
S_CURRENT_USER_VALUENAME,
0,
REG_SZ,
(PBYTE) ProfileTemp,
SizeOfString (ProfileTemp)
);
CloseRegKey (key);
}
}
//
// Open txtsetup.sif
//
if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
g_TxtSetupSif = InfOpenInfInAllSources (S_TXTSETUP_SIF);
if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_TXTSETUP_SIF_ERROR));
__leave;
}
}
if (!BeginMigrationDllProcessing()) {
DEBUGMSG ((DBG_WARNING, "BeginMigrationDllProcessing returned FALSE"));
__leave;
}
if (!InitAccessibleDrives()) {
__leave;
}
//
// exclude all of the directories in source directories and optional directories from processing.
//
for (index = 0; index < SOURCEDIRECTORYCOUNT(); index++) {
ExcludePath (g_ExclusionValue, SOURCEDIRECTORY(index));
}
for (index = 0; index < OPTIONALDIRECTORYCOUNT(); index++) {
ExcludePath (g_ExclusionValue, OPTIONALDIRECTORY(index));
}
//
// also exclude the directory used by Dynamic Setup
//
if (g_DynamicUpdateLocalDir) {
ExcludePath (g_ExclusionValue, g_DynamicUpdateLocalDir);
}
//
// Put original boot.ini, bootfont.bin, ntdetect.com, ntldr and boot
// sector in setup temp dir
//
if (g_BootDrivePath && g_TempDir) {
if (!pPutBootFileInUninstallTempDir (S_BOOTINI, S_BOOTINI_BACKUP)) {
__leave;
}
if (!pPutBootFileInUninstallTempDir (S_BOOTFONT_BIN, S_BOOTFONT_BACKUP)) {
__leave;
}
if (!pPutBootFileInUninstallTempDir (S_NTDETECT, S_NTDETECT_BACKUP)) {
__leave;
}
if (!pPutBootFileInUninstallTempDir (S_NTLDR, S_NTLDR_BACKUP)) {
__leave;
}
if (ReadDiskSectors (
*g_BootDrive,
FAT_STARTING_SECTOR,
FAT_BOOT_SECTOR_COUNT,
FAT_BOOT_SECTOR_SIZE,
bootSector
)) {
StringCopy (dest, g_TempDir);
StringCopy (AppendWack (dest), S_BOOTSECT_BACKUP);
fileHandle = CreateFile (
dest,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (fileHandle == INVALID_HANDLE_VALUE) {
DEBUGMSG ((DBG_ERROR, "Can't create %s", dest));
__leave;
}
if (!WriteFile (fileHandle, bootSector, sizeof (bootSector), &dontCare, NULL)) {
DEBUGMSG ((DBG_ERROR, "Can't write boot sector to %s", dest));
__leave;
}
}
} else {
MYASSERT (FALSE);
__leave;
}
result = TRUE;
}
__finally {
if (fileHandle != INVALID_HANDLE_VALUE) {
CloseHandle (fileHandle);
}
}
return result;
}
BOOL
pGetProfilesDirectory (
OUT PTSTR Path, OPTIONAL
IN OUT PDWORD Size
)
/*++
Routine Description:
pGetProfileDirectory emulates the NT 5 API GetProfileDirectory. It looks in
hivesft.inf for Winlogon's ProfilesDirectory key. If an override to the NT
profile directory is given in the winnt.sif file, then the override is used
instead.
Arguments:
Path - Receives the user profile path
Size - Specifies the size of Path, in TCHAR characters. Receives the number
of characters needed to hold the profile path.
Return Value:
TRUE if the API succeeds, or FALSE if an unexpected error occurs.
--*/
{
TCHAR Buffer[MAX_TCHAR_PATH];
PCTSTR p;
BOOL b;
DWORD SizeNeeded;
PCTSTR EndOfString;
PCTSTR UserProfiles;
if (!Size) {
return FALSE;
}
MYASSERT (g_WinDir);
MYASSERT (g_SourceDirectoryCountFromWinnt32);
//
// Look in answer file for setting, use it if it exists
//
Buffer[0] = 0;
if (g_UnattendScriptFile && *g_UnattendScriptFile) {
GetPrivateProfileString (
S_GUIUNATTENDED,
S_PROFILEDIR,
S_EMPTY,
Buffer,
MAX_TCHAR_PATH,
*g_UnattendScriptFile
);
}
if (!(*Buffer)) {
//
// Default to %systemroot%\Documents and Settings
//
UserProfiles = GetStringResource (MSG_USER_PROFILE_ROOT);
MYASSERT (UserProfiles);
StringCopy (Buffer, UserProfiles);
FreeStringResource (UserProfiles);
}
Buffer[MAX_TCHAR_PATH - 1] = 0; // user can pass in anything via answer file!
SizeNeeded = ByteCount (Buffer) / sizeof (TCHAR);
if (Path) {
b = *Size >= SizeNeeded;
if (*Size) {
EndOfString = GetEndOfString (Buffer);
p = min (EndOfString, Buffer + *Size);
StringCopyAB (Path, Buffer, p);
}
} else {
b = TRUE;
}
*Size = SizeNeeded;
return b;
}
typedef struct {
DWORD ProcessId;
HWND hwnd;
} FINDPROCESSWINDOW, *PFINDPROCESSWINDOW;
BOOL
CALLBACK
pFindProcessWindowCallback (
HWND hwnd,
LPARAM lParam
)
/*++
Routine Description:
pFindProcessWindowCallback is called by the window enumeration started by
pFindProcessWindow. If the process ID of the window matches our process
ID, then the enumeration is stopped so the proper window handle can
be returned by pFindProcessWindow.
Arguments:
hwnd - Specifies the current enumerated window handle
lParam - Specifies the FINDPROCESSWINDOW structure allocated by
pFindProcessWindow
Return Value:
TRUE if enuemration should continue, or FALSE if it should stop.
--*/
{
PFINDPROCESSWINDOW p;
DWORD ProcessId = 0;
p = (PFINDPROCESSWINDOW) lParam;
GetWindowThreadProcessId (hwnd, &ProcessId);
if (ProcessId == p->ProcessId) {
p->hwnd = hwnd;
return FALSE;
}
return TRUE;
}
HWND
pFindProcessWindow (
VOID
)
/*++
Routine Description:
pFindProcessWindow enumerates all windows and returns the first one that
the current process owns. There should only be one, so the end result
is a handle to the main window of the process.
Arguments:
none
Return Value:
A handle to the process main window, or NULL if no windows exist for
the process.
--*/
{
FINDPROCESSWINDOW Enum;
ZeroMemory (&Enum, sizeof (Enum));
Enum.ProcessId = GetCurrentProcessId();
EnumWindows (pFindProcessWindowCallback, (LPARAM) &Enum);
return Enum.hwnd;
}
INT
pGetProcessorSpeed (
OUT PTSTR *Family
)
/*++
Routine Description:
pGetProcessorSpeed returns the speed in MHz of the computer, and identifies
the processor if it is a Pentium or better. Code from Todd Laney (toddla).
Arguments:
Family - Receives a pointer to the name of the processor family
Return Value:
The speed of the processor, in MHz.
--*/
{
SYSTEM_INFO si;
__int64 start, end, freq;
INT flags,family;
INT time;
INT clocks;
DWORD oldclass;
HANDLE hprocess;
INT familyIndex = 0;
static PTSTR familyStrings[] = {
"Unknown (0)",
"Unknown (1)",
"Unknown (2)",
"x386",
"x486",
"Pentium",
"Pentium Pro",
"Pentium II (?)",
"Unknown..."
};
*Family = NULL;
ZeroMemory(&si, sizeof(si));
GetSystemInfo(&si);
//Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
//Because wProcessor level is not implemented on Win95
if (si.wProcessorLevel) {
family = si.wProcessorLevel;
} else {
family = 0;
//Ok, we're on Win95
switch (si.dwProcessorType) {
case PROCESSOR_INTEL_386:
familyIndex=3;
break;
case PROCESSOR_INTEL_486:
familyIndex=4;
break;
default:
familyIndex=0;
break;
}
}
//
// make sure this is a INTEL Pentium (or clone) or higher.
//
if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
return 0;
if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
return 0;
//
// see if this chip supports rdtsc before using it.
//
__try
{
_asm
{
mov eax,1
_emit 00Fh ;; CPUID
_emit 0A2h
mov flags,edx
mov family,eax
}
}
__except(1)
{
flags = 0;
}
//check for support of CPUID and fail
if (!(flags & 0x10))
return 0;
//If we don't have a family, set it now
//Family is bits 11:8 of eax from CPU, with eax=1
if (!familyIndex) {
familyIndex=(family & 0x0F00) >> 8;
}
hprocess = GetCurrentProcess();
oldclass = GetPriorityClass(hprocess);
SetPriorityClass(hprocess, REALTIME_PRIORITY_CLASS);
Sleep(10);
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
QueryPerformanceCounter((LARGE_INTEGER*)&start);
_asm
{
_emit 0Fh ;; RDTSC
_emit 31h
mov ecx,100000
x: dec ecx
jnz x
mov ebx,eax
_emit 0Fh ;; RDTSC
_emit 31h
sub eax,ebx
mov dword ptr clocks[0],eax
}
QueryPerformanceCounter((LARGE_INTEGER*)&end);
SetPriorityClass(hprocess, oldclass);
time = MulDiv((int)(end-start),1000000,(int)freq);
if (familyIndex > 7) {
familyIndex = 7;
}
*Family = familyStrings[familyIndex];
return (clocks + time/2) / time;
}