mirror of https://github.com/lianthony/NT4.0
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.
1966 lines
44 KiB
1966 lines
44 KiB
#include "setupp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
// Boolean value indicating whether setup is installing cairo
|
|
//
|
|
BOOL CairoSetup = FALSE;
|
|
|
|
//
|
|
// Product type: workstation, standalone server, dc server.
|
|
//
|
|
UINT ProductType;
|
|
|
|
//
|
|
// Boolean value indicating whether this installation
|
|
// originated with winnt/winnt32.
|
|
// And, original source path, saved away for us by winnt/winnt32.
|
|
//
|
|
BOOL WinntBased;
|
|
PCWSTR OriginalSourcePath;
|
|
|
|
//
|
|
// Boolean value indicating whether we're upgrading.
|
|
//
|
|
BOOL Upgrade;
|
|
BOOL Win31Upgrade;
|
|
BOOL Win95Upgrade;
|
|
|
|
//
|
|
// Boolean value indicating whether we're in Setup or in appwiz.
|
|
//
|
|
BOOL IsSetup = FALSE;
|
|
|
|
//
|
|
// Window handle of topmost setup window.
|
|
//
|
|
HWND MainWindowHandle;
|
|
|
|
//
|
|
// Source path for installation.
|
|
//
|
|
WCHAR SourcePath[MAX_PATH];
|
|
|
|
//
|
|
// System setup inf.
|
|
//
|
|
HINF SyssetupInf;
|
|
|
|
//
|
|
// Flag indicating whether this is an unattended mode install/upgrade.
|
|
// Also a flag indicating whether this is a preinstallation.
|
|
// And a flag indicating whether we are supposed to allow rollback
|
|
// once setup has been completed.
|
|
// And a flag that tells us whether to skip the eula in the preinstall case.
|
|
//
|
|
BOOL Unattended;
|
|
BOOL Preinstall;
|
|
BOOL AllowRollback;
|
|
BOOL OemSkipEula;
|
|
|
|
//
|
|
// Flag indicating whether to skip missing files.
|
|
//
|
|
BOOL SkipMissingFiles;
|
|
|
|
//
|
|
// User command to execute, if any.
|
|
//
|
|
PWSTR UserExecuteCmd;
|
|
|
|
//
|
|
// This flag tracks whether any errors were encountered during Setup.
|
|
//
|
|
BOOL AnyErrors;
|
|
|
|
//
|
|
// String id of the string to be used for titles -- "Windows NT Setup"
|
|
//
|
|
UINT SetupTitleStringId;
|
|
|
|
//
|
|
// Strings used with date/timezone applet
|
|
//
|
|
PCWSTR DateTimeCpl = L"timedate.cpl";
|
|
PCWSTR DateTimeParam = L"/firstboot";
|
|
PCWSTR UnattendDateTimeParam = L"/z ";
|
|
|
|
//
|
|
// Global structure that contains information that will be used
|
|
// by net setup. We pass a pointer to this structure when we call
|
|
// NetSetupRequestWizardPages, then fill it in before we call into
|
|
// the net setup wizard.
|
|
//
|
|
INTERNAL_SETUP_DATA InternalSetupData;
|
|
|
|
//
|
|
// In the initial install case, we time how long the wizard takes
|
|
// to help randomize the sid we generate.
|
|
//
|
|
DWORD PreWizardTickCount;
|
|
|
|
//
|
|
// Global variable that contains the handle of the PnP Initialization
|
|
// thread that is spawned at the beginning of setup. (This value is
|
|
// NULL if we couldn't spawn the thread.)
|
|
//
|
|
HANDLE PnPInitThreadHandle;
|
|
|
|
|
|
VOID
|
|
CallNetworkSetupBack(
|
|
IN PCSTR ProcName
|
|
);
|
|
|
|
VOID
|
|
SetUpDataBlock(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DisplayEula(
|
|
IN OUT HWND *Billboard
|
|
);
|
|
|
|
VOID
|
|
RemoveMSKeyboardPtrPropSheet (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
FixWordPadReg (
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
|
|
VOID
|
|
InitializeCairoSetupFlag(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Examine the registry to find out if this is Cairo setup.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Error;
|
|
HKEY Key;
|
|
DWORD Type;
|
|
DWORD Data;
|
|
DWORD cbData;
|
|
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\Setup",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&Key );
|
|
|
|
if( Error == ERROR_SUCCESS ) {
|
|
cbData = sizeof( DWORD );
|
|
Error = RegQueryValueEx( Key,
|
|
L"CairoSystem",
|
|
NULL,
|
|
&Type,
|
|
( PBYTE )&Data,
|
|
&cbData );
|
|
|
|
RegCloseKey( Key );
|
|
|
|
if( Error == ERROR_SUCCESS ) {
|
|
//
|
|
// Initialize the global variable
|
|
//
|
|
CairoSetup = ( ( Type == REG_DWORD ) && ( Data == 1 ) );
|
|
} else {
|
|
//
|
|
// Log the error as it is unexpected
|
|
//
|
|
CairoSetup = FALSE;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Log the error as it is unexpected
|
|
//
|
|
CairoSetup = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FatalError(
|
|
IN UINT MessageId,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform the user of an error which prevents Setup from continuing.
|
|
The error is logged as a fatal error, and a message box is presented.
|
|
|
|
Arguments:
|
|
|
|
MessageId - supplies the id for the message in the message table.
|
|
|
|
Additional agruments specify parameters to be inserted in the message.
|
|
|
|
Return Value:
|
|
|
|
DOES NOT RETURN.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCWSTR Message;
|
|
va_list arglist;
|
|
|
|
va_start(arglist,MessageId);
|
|
Message = RetreiveAndFormatMessageV(MessageId,&arglist);
|
|
va_end(arglist);
|
|
|
|
if(Message) {
|
|
|
|
//
|
|
// Log the error first.
|
|
//
|
|
LogItem(LogSevFatalError,Message);
|
|
|
|
//
|
|
// Now tell the user.
|
|
//
|
|
MessageBoxFromMessage(
|
|
MainWindowHandle,
|
|
MSG_FATAL_ERROR,
|
|
NULL,
|
|
IDS_FATALERROR,
|
|
MB_ICONERROR | MB_OK | MB_SYSTEMMODAL,
|
|
Message
|
|
);
|
|
|
|
} else {
|
|
OutOfMemory(MainWindowHandle);
|
|
}
|
|
|
|
ViewSetupActionLog (MainWindowHandle, NULL, NULL);
|
|
ExitProcess(1);
|
|
}
|
|
|
|
|
|
VOID
|
|
CommonInitialization(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize GUI Setup. This is common to upgrades and initial installs.
|
|
In this phase, we perform initialization tasks such as creating the
|
|
main background window, initializing the action log (into which we will
|
|
store error and other info), and fetch setup parameters from the
|
|
response file.
|
|
|
|
We also load system infs.
|
|
|
|
Note that any errors that occur during this phase are fatal.
|
|
|
|
(LonnyM): We also now spawn off a separate thread to 'sweep' the system32
|
|
directory for certain classes of legacy INFs, then precompile all INFs in
|
|
the Inf directory, and migrate legacy device instances for certain classes.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
HWND Billboard;
|
|
WCHAR Path[MAX_PATH];
|
|
PWSTR Answer;
|
|
PWSTR Cmd;
|
|
PWSTR Args;
|
|
WCHAR PathBuffer[4*MAX_PATH];
|
|
PWSTR Backup;
|
|
PWSTR Sentinel;
|
|
int i;
|
|
HANDLE h;
|
|
|
|
//
|
|
// CAIROSETUP
|
|
// Determine whether we are installing Cairo. We have to make
|
|
// a bunch of run-time checks and do a whole bunch of stuff differently
|
|
// in the Cairo case.
|
|
//
|
|
InitializeCairoSetupFlag();
|
|
|
|
//
|
|
// Create the main setup background window.
|
|
//
|
|
MainWindowHandle = CreateSetupWindow();
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_INITIALIZING);
|
|
|
|
//
|
|
// Initialize the action log. This is where we log any errors or other
|
|
// info we think might be useful to the user.
|
|
//
|
|
InitializeSetupActionLog(TRUE);
|
|
|
|
//
|
|
// Figure out whether we are supposed to support rollback
|
|
// after gui setup has been completed at the end-user site.
|
|
// This is for OEM test/audit. For now we merely check for the
|
|
// presence of a file in drive A:.
|
|
//
|
|
AllowRollback = FileExists(L"A:\\" WINNT_OEM_ROLLBACK_FILE,NULL);
|
|
|
|
//
|
|
// Fetch our parameters. Note that this also takes care of initializing
|
|
// uniqueness stuff, so later initialization of preinstall and unattend mode
|
|
// don't ever have to know anything about the uniqueness stuff -- it's
|
|
// totally transparent to them.
|
|
//
|
|
if(!SpSetupProcessParameters(&Billboard)) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_LEGACYINTERFACE,0);
|
|
}
|
|
|
|
//
|
|
// Initialize preinstallation.
|
|
//
|
|
InitializePreinstall();
|
|
|
|
//
|
|
// End user license agreement. Do this here, after the Unattended and Preinstall
|
|
// globals have been initialized. Both are checked in DisplayEula().
|
|
//
|
|
DisplayEula(&Billboard);
|
|
|
|
//
|
|
// fix problem with IntelliType Manager conflict.
|
|
//
|
|
RemoveMSKeyboardPtrPropSheet ();
|
|
|
|
//
|
|
// Fix Wordpad registry entry.
|
|
//
|
|
FixWordPadReg ();
|
|
|
|
if(Unattended) {
|
|
//
|
|
// Initialize unattended operation now.
|
|
//
|
|
UnattendInitialize();
|
|
|
|
//
|
|
// Set the current dir to %windir% -- to be consistent with
|
|
// UserExecuteCmd
|
|
//
|
|
GetWindowsDirectory(PathBuffer,MAX_PATH);
|
|
SetCurrentDirectory(PathBuffer);
|
|
|
|
//
|
|
// The program to execute is in 2 parts: DetachedProgram and Arguments.
|
|
//
|
|
if(Cmd = UnattendFetchString(UAE_PROGRAM)) {
|
|
|
|
if(Cmd[0]) {
|
|
|
|
Args = UnattendFetchString(UAE_ARGUMENT);
|
|
|
|
ExpandEnvironmentStrings(Cmd,PathBuffer,MAX_PATH);
|
|
ExpandEnvironmentStrings(Args ? Args : L"",PathBuffer+MAX_PATH,3*MAX_PATH);
|
|
|
|
if(!InvokeExternalApplication(PathBuffer,PathBuffer+MAX_PATH,NULL)) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
|
|
if(Args) {
|
|
MyFree(Args);
|
|
}
|
|
}
|
|
|
|
MyFree(Cmd);
|
|
}
|
|
}
|
|
|
|
SetupTitleStringId = (ProductType == PRODUCT_WORKSTATION)
|
|
? (Upgrade ? IDS_TITLE_UPGRADE_W : IDS_TITLE_INSTALL_W)
|
|
: (Upgrade ? IDS_TITLE_UPGRADE_S : IDS_TITLE_INSTALL_S);
|
|
|
|
//
|
|
// Now load the system setup (win95-style!) infs.
|
|
//
|
|
SyssetupInf = SetupOpenInfFile(L"syssetup.inf",NULL,INF_STYLE_WIN4,NULL);
|
|
if(SyssetupInf == INVALID_HANDLE_VALUE) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SYSINFBAD,L"syssetup.inf");
|
|
} else {
|
|
if(!SetupOpenAppendInfFile(NULL,SyssetupInf,NULL)) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SYSINFBAD,L"(syssetup.inf layout)");
|
|
}
|
|
}
|
|
|
|
if(!Upgrade) {
|
|
//
|
|
// Path gets the path of the Profiles directory
|
|
// PathBuffer[0] gets the path of the backup profiles directory
|
|
// PathBuffer[MAX_PATH] gets the path of the sentinel file
|
|
//
|
|
Backup = PathBuffer;
|
|
Sentinel = PathBuffer+MAX_PATH;
|
|
|
|
GetWindowsDirectory(Path,MAX_PATH);
|
|
lstrcpy(Backup,Path);
|
|
|
|
ConcatenatePaths(Path,L"Profiles",MAX_PATH,NULL);
|
|
ConcatenatePaths(Backup,PROFILEBACK_DIRECTORY,MAX_PATH,NULL);
|
|
|
|
lstrcpy(Sentinel,Backup);
|
|
ConcatenatePaths(Sentinel,PROFILEBACK_SENTINEL,MAX_PATH,NULL);
|
|
|
|
//
|
|
// In preinstall scenarios the OEM might "preload" the Default Users
|
|
// or All Users profile with links. In any scenario as the user
|
|
// progresses through GUI Setup these profiles will get modified.
|
|
// However if the power goes out and thus GUI Setup is restarted
|
|
// (or if the OEM does a rollback), then the presence of stuff
|
|
// in the profiles directories can be an annoyance.
|
|
//
|
|
// For example in the rollback case, the OEM logged on once -- say as
|
|
// Administrator. The directory for that profile is now on the disk.
|
|
// When the end-user first logs in winlogon will create a profile in
|
|
// Administrator.000 which is not what we want. Or the OEM might have done
|
|
// some stuff that modified the common user profile (All Users),
|
|
// which would wind up polluting the end-user's use of the machine.
|
|
// Another example is the regular old retail case where the user
|
|
// goes through and makes different choices. Existing links in
|
|
// the Default User profile might wind up as turds.
|
|
//
|
|
// To make this all really clean and make things airtight for the
|
|
// OEM and retail cases we do some magic with the Profiles directory.
|
|
//
|
|
// Note that in the retail case simply delnoding any existing
|
|
// Profiles directory does exactly what we want since there can be
|
|
// no legitimate Profiles directory on the disk at this point --
|
|
// nothing can be preloaded in that directory and if we restart GUI
|
|
// Setup, we want to start from scratch.
|
|
//
|
|
// Also note that InitializeProfiles() does not nuke Default User
|
|
// or All Users and that it doesn't care if those directories
|
|
// already exist. Thus we can InitializeProfiles() over the top
|
|
// of any existing preloaded stuff in the preinstall case.
|
|
//
|
|
if(Preinstall) {
|
|
//
|
|
// If we get here and there is a valid backup copy of the
|
|
// profiles directory, then we were restarted because the
|
|
// power went out, the OEM did a rollback, etc. Get rid of
|
|
// the existing profiles directory and copy the backup dir
|
|
// into the Profiles directory.
|
|
//
|
|
// If there is not a valid backup copy of the profiles
|
|
// directory, then this is the first time through GUI Setup
|
|
// or the power went out while we were previously trying to
|
|
// create a backup copy.
|
|
//
|
|
if(FileExists(Sentinel,NULL)) {
|
|
Delnode(Path);
|
|
TreeCopy(Backup,Path);
|
|
//
|
|
// No need or desire to have the sentinel file in the actual
|
|
// profiles dir.
|
|
//
|
|
ConcatenatePaths(Path,PROFILEBACK_SENTINEL,MAX_PATH,NULL);
|
|
DeleteFile(Path);
|
|
} else {
|
|
Delnode(Backup);
|
|
TreeCopy(Path,Backup);
|
|
|
|
h = CreateFile(
|
|
Sentinel,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if(h != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(h);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Regular old retail case. Nuke any existing Profiles dir
|
|
// so we are guaranteed to start from scratch.
|
|
//
|
|
Delnode(Path);
|
|
}
|
|
}
|
|
InitializeProfiles();
|
|
|
|
//
|
|
// Set fonts directory to system + read only. This causes
|
|
// explorer to treat the directory specially and allows the font
|
|
// folder to work.
|
|
//
|
|
GetWindowsDirectory(Path,MAX_PATH);
|
|
ConcatenatePaths(Path,L"FONTS",MAX_PATH,NULL);
|
|
SetFileAttributes(Path,FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Copy some files.
|
|
//
|
|
if(!Upgrade) {
|
|
if(!CopySystemFiles()) {
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
if(!UpgradeSystemFiles()) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
if( !SetProgramFilesDirInRegistry() ) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Spawn off a thread to do device INF precompilation/PnP device migration. Failure
|
|
// here simply indicates we couldn't create the thread--it says nothing about what
|
|
// we actually do in the other thread.
|
|
//
|
|
// Failure to spawn this thread does not constitute a fatal error.
|
|
//
|
|
if(!(PnPInitThreadHandle = SpawnPnPInitialization())) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
|
|
//
|
|
// Do cryptography stuff. Errors not fatal.
|
|
//
|
|
if(!InstallOrUpgradeCapi()) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FinishUp(
|
|
VOID
|
|
)
|
|
{
|
|
int i;
|
|
WCHAR PathBuffer[4*MAX_PATH];
|
|
DWORD DontCare;
|
|
HWND Billboard;
|
|
|
|
//
|
|
// Fix up the legacy install source.
|
|
//
|
|
CreateWindowsNtSoftwareEntry(FALSE);
|
|
|
|
//
|
|
// Before executing any user-specified commands, we should make sure that the
|
|
// PnP migration is done (and if not, then wait until it is). This is because
|
|
// it is possible that one of these commands could be using CM/DI APIs to work
|
|
// with a list of devices that we're not finished building yet.
|
|
//
|
|
// BUGBUG (lonnym): now that we're passing this handle off to the network guys,
|
|
// who are waiting on it, there's no need for us to do this anymore. But it
|
|
// doesn't hurt anything.
|
|
//
|
|
if(PnPInitThreadHandle) {
|
|
WaitForPnPInitToFinish(PnPInitThreadHandle);
|
|
CloseHandle(PnPInitThreadHandle);
|
|
}
|
|
|
|
//
|
|
// Execute user-specified command, if any.
|
|
//
|
|
if(UserExecuteCmd) {
|
|
|
|
//
|
|
// Set current directory to %windir%
|
|
//
|
|
GetWindowsDirectory(PathBuffer,sizeof(PathBuffer)/sizeof(PathBuffer[0]));
|
|
SetCurrentDirectory(PathBuffer);
|
|
|
|
ExpandEnvironmentStrings(
|
|
UserExecuteCmd,
|
|
PathBuffer,
|
|
sizeof(PathBuffer)/sizeof(PathBuffer[0])
|
|
);
|
|
|
|
if(!InvokeExternalApplication(NULL,PathBuffer,(PDWORD)&i)) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize softpub.dll if it's available.
|
|
//
|
|
|
|
InvokeExternalApplication(NULL,L"spinit.exe",NULL);
|
|
|
|
//
|
|
// Note the order of the following operations.
|
|
// If the order were changed, there is a small window where if the system
|
|
// were to be rebooted, setup would not restart, but the SKU stuff would
|
|
// be inconsistent, causing a licensing bugcheck.
|
|
//
|
|
SetUpEvaluationSKUStuff();
|
|
//
|
|
// Indicate that setup is no longer in progress.
|
|
// Do this before creating repair info! Also do it before
|
|
// removing restart stuff. This way we will always either restart setup
|
|
// or be able to log in.
|
|
//
|
|
if(!ResetSetupInProgress()) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
RemoveRestartStuff();
|
|
|
|
if(Preinstall && !AllowRollback) {
|
|
//
|
|
// Get rid of backup profiles directory which is
|
|
// now no longer needed since setup can't be restarted.
|
|
//
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_REMOVING_LOCALSRC);
|
|
GetWindowsDirectory(PathBuffer,MAX_PATH);
|
|
ConcatenatePaths(PathBuffer,PROFILEBACK_DIRECTORY,MAX_PATH,NULL);
|
|
Delnode(PathBuffer);
|
|
KillBillboard(Billboard);
|
|
}
|
|
|
|
//
|
|
// FROM THIS POINT ON DO NOTHING THAT IS CRITICAL TO THE OPERATION
|
|
// OF THE SYSTEM. OPERATIONS AFTER THIS POINT ARE NOT PROTECTED BY
|
|
// RESTARTABILITY.
|
|
//
|
|
|
|
//
|
|
// Do the repair disk thing.
|
|
//
|
|
if(!InvokeExternalApplication(L"RDISK",CreateRepairDisk ? L"/s+" : L"/s-",&DontCare)) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_REMOVING_LOCALSRC);
|
|
DeleteLocalSource();
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Call the net guys back once again to let them do any final
|
|
// processing, such as BDC replication.
|
|
//
|
|
CallNetworkSetupBack(NETSETUPFINISHINSTALLPROCNAME);
|
|
|
|
//
|
|
// Inform the user if there were errors, and optionally view the log.
|
|
//
|
|
if(AnyErrors) {
|
|
|
|
i = MessageBoxFromMessage(
|
|
MainWindowHandle,
|
|
MSG_SETUP_HAD_ERRORS,
|
|
NULL,
|
|
SetupTitleStringId,
|
|
MB_SYSTEMMODAL | MB_YESNO | MB_ICONASTERISK | MB_SETFOREGROUND,
|
|
ActionLogFileName ? ActionLogFileName : L""
|
|
);
|
|
|
|
if(i == IDYES) {
|
|
ViewSetupActionLog (MainWindowHandle, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for NoWaitAfterGuiMode flag. Non-0 value means skip the done dialog.
|
|
//
|
|
if(!GetPrivateProfileInt(pwUnattended,L"NoWaitAfterGuiMode",0,AnswerFile)
|
|
&& (!Unattended || Preinstall)) {
|
|
DialogBoxParam(
|
|
MyModuleHandle,
|
|
MAKEINTRESOURCE(IDD_DONE_SUCCESS),
|
|
MainWindowHandle,
|
|
DoneDlgProc,
|
|
AnyErrors ? MSG_SETUP_DONE_GENERIC
|
|
: (Upgrade ? MSG_UPGRADE_DONE_SUCCESS : MSG_SETUP_DONE_SUCCESS)
|
|
);
|
|
|
|
}
|
|
|
|
EnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
|
|
ExitWindowsEx(EWX_REBOOT,0);
|
|
}
|
|
|
|
|
|
VOID
|
|
PrepareForNetSetup(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD TickCount;
|
|
BOOL b;
|
|
SYSTEMTIME SysTime;
|
|
|
|
b = TRUE;
|
|
|
|
TickCount = GetTickCount() - PreWizardTickCount;
|
|
GetSystemTime(&SysTime);
|
|
|
|
//
|
|
// Create Windows NT software key entry and set product type in registry.
|
|
//
|
|
if(!SetProductTypeInRegistry()) {
|
|
FatalError(MSG_LOG_SETPRODTYPE);
|
|
}
|
|
if(!CreateWindowsNtSoftwareEntry(TRUE)) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetProductIdInRegistry()) {
|
|
b = FALSE;
|
|
}
|
|
if(!StoreNameOrgInRegistry()) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetEnabledProcessorCount()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set account domain sid, as well as the computer name.
|
|
// Also create the sam event that SAM will use to signal us
|
|
// when it's finished initializing.
|
|
// Any failures here are fatal.
|
|
//
|
|
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if( !CairoSetup ) {
|
|
if(!SetAccountsDomainSid(SysTime.wMilliseconds+TickCount,ComputerName)) {
|
|
FatalError(MSG_LOG_SECURITY_CATASTROPHE);
|
|
}
|
|
}
|
|
if(!SetComputerName(ComputerName)
|
|
|| !CreateSamEvent()) {
|
|
FatalError(MSG_LOG_SECURITY_CATASTROPHE);
|
|
}
|
|
|
|
//
|
|
// Change boot.ini/nvram timeout to something reasonable.
|
|
//
|
|
if(!ChangeBootTimeout(30)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Install netdde
|
|
//
|
|
if(!InstallNetDDE()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// CAIROSETUP
|
|
// Invoke the [DoCairoInitialization] section of cairo.inf.
|
|
//
|
|
if(CairoSetup) {
|
|
SpSetupDoLegacyInf("CAIRO.INF","DoCairoInitialization");
|
|
}
|
|
|
|
SetUpDataBlock();
|
|
|
|
if(!b) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
PrepareForNetUpgrade(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL b;
|
|
|
|
b = TRUE;
|
|
|
|
if(!ChangeBootTimeout(30)) {
|
|
b = FALSE;
|
|
}
|
|
if(!UpdateSoundDriverSettings()) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetProductTypeInRegistry()) {
|
|
FatalError(MSG_LOG_SETPRODTYPE);
|
|
}
|
|
if(!CreateWindowsNtSoftwareEntry(TRUE)) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetEnabledProcessorCount()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
SetUpDataBlock();
|
|
|
|
if(!b) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FinishSetup(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL b;
|
|
WCHAR TempString[MAX_PATH];
|
|
WCHAR adminName[MAX_USERNAME+1];
|
|
HWND Billboard;
|
|
PWSTR Answer;
|
|
|
|
MYASSERT(!Upgrade);
|
|
b = TRUE;
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_CONFIGURING_COMPUTER);
|
|
//
|
|
// Set product type one more time, in case it changed, say from
|
|
// dc server to standalone server.
|
|
//
|
|
if(!SetProductTypeInRegistry()) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SETPRODTYPE);
|
|
}
|
|
|
|
//
|
|
// Signal the LSA event. Fatal error if this fails!
|
|
//
|
|
if(!SignalLsa()) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SECURITY_CATASTROPHE);
|
|
}
|
|
|
|
//
|
|
// CAIROSETUP
|
|
// Perform additional Cairo stuff now.
|
|
//
|
|
if(CairoSetup) {
|
|
SpSetupDoLegacyInf("CAIRO.INF","GetCairoParams");
|
|
SpSetupDoLegacyInf("CAIRO.INF","DoCairoSetup");
|
|
}
|
|
|
|
//
|
|
// Set up the path, which involves appending %systemroot% if not
|
|
// doing a win31 upgrade.
|
|
//
|
|
if(!SetUpPath()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Create config.nt/autoexec.nt.
|
|
//
|
|
if(!ConfigureMsDosSubsystem()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Make the appropriate entries for wow.
|
|
//
|
|
if(!MakeWowEntry()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Enable and start the spooler.
|
|
//
|
|
if(!MyChangeServiceStart(szSpooler,SERVICE_AUTO_START)) {
|
|
b = FALSE;
|
|
}
|
|
if(!StartSpooler()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Set up program groups.
|
|
//
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_CREATING_MENU_OBJECTS);
|
|
if(!CreateStartMenuItems(SyssetupInf)) {
|
|
b = FALSE;
|
|
}
|
|
KillBillboard(Billboard);
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_CONFIGURING_COMPUTER);
|
|
//
|
|
// Change some service start values.
|
|
//
|
|
if(!MyChangeServiceStart(L"EventLog",SERVICE_AUTO_START)) {
|
|
b = FALSE;
|
|
}
|
|
if(!MyChangeServiceStart(L"ClipSrv",SERVICE_DEMAND_START)) {
|
|
b = FALSE;
|
|
}
|
|
if(!MyChangeServiceStart(L"NetDDE",SERVICE_DEMAND_START)) {
|
|
b = FALSE;
|
|
}
|
|
if(!MyChangeServiceStart(L"NetDDEdsdm",SERVICE_DEMAND_START)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if(CairoSetup) {
|
|
if(!MyChangeServiceStart(L"CiFilter",SERVICE_AUTO_START)) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Miscellaneous spooler initialization.
|
|
//
|
|
if(!MiscSpoolerInit()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Wait for SAM to finish initializing.
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if(!CairoSetup) {
|
|
if(!WaitForSam()) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SECURITY_CATASTROPHE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set administrator password and create local user account.
|
|
// Also create PDC account for domain controllers.
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if(!CairoSetup && (ProductType != PRODUCT_SERVER_SECONDARY)) {
|
|
LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
|
|
if(!SetLocalUserPassword(adminName,L"",AdminPassword)) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
#ifdef DOLOCALUSER
|
|
if(CreateUserAccount) {
|
|
if(!CreateLocalUserAccount(UserName,UserPassword)) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if(!CairoSetup && (ProductType == PRODUCT_SERVER_PRIMARY)) {
|
|
if(!CreatePdcAccount(ComputerName)) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set temp/tmp variables.
|
|
//
|
|
lstrcpy(TempString,L"%SystemDrive%\\TEMP");
|
|
if(!SetEnvironmentVariableInRegistry(L"TEMP",TempString,FALSE)) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetEnvironmentVariableInRegistry(L"TMP",TempString,FALSE)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Create aux directories.
|
|
//
|
|
GetWindowsDirectory(TempString,MAX_PATH);
|
|
lstrcpy(TempString+3,L"TEMP");
|
|
CreateDirectory(TempString,NULL);
|
|
|
|
// lstrcpy(TempString+3,L"USERS");
|
|
// CreateDirectory(TempString,NULL);
|
|
// lstrcpy(TempString+8,L"\\DEFAULT");
|
|
// CreateDirectory(TempString,NULL);
|
|
//
|
|
// lstrcpy(TempString+3,L"WIN32APP");
|
|
// CreateDirectory(TempString,NULL);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Set NPX emulation state.
|
|
//
|
|
if(!SetNpxEmulationState()) {
|
|
b = FALSE;
|
|
}
|
|
#endif // def _X86_
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Call the network setup back to handle Internet Server issues.
|
|
//
|
|
CallNetworkSetupBack(NETSETUPINSTALLSOFTWAREPROCNAME);
|
|
|
|
//
|
|
// Invoke applets.
|
|
//
|
|
|
|
if( Unattended ) {
|
|
|
|
wcscpy(TempString,UnattendDateTimeParam);
|
|
//
|
|
// Note: we use the default string internal to the Unattend
|
|
// module.
|
|
//
|
|
if(Answer = UnattendFetchString(UAE_TIMEZONE)) {
|
|
//
|
|
// Send the correct parameter to the applet
|
|
//
|
|
wcsncat(TempString,Answer,MAX_PATH-4);
|
|
TempString[MAX_PATH-1] = 0;
|
|
//
|
|
// Clean up any memory allocated for the answer
|
|
//
|
|
MyFree(Answer);
|
|
}
|
|
|
|
if(!InvokeControlPanelApplet(DateTimeCpl,L"",0,TempString)) {
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
if(!InvokeControlPanelApplet(DateTimeCpl,L"",0,DateTimeParam)) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
if(!InvokeControlPanelApplet(L"desk.cpl",NULL,IDS_DISPLAYAPPLET,L"setup")) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Stamp build number
|
|
//
|
|
StampBuildNumber();
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_CONFIGURING_COMPUTER);
|
|
|
|
//
|
|
// Set some misc stuff in win.ini
|
|
//
|
|
if(!WinIniAlter1()) {
|
|
b = FALSE;
|
|
}
|
|
if(!WinIniAlter2()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Fonts.
|
|
//
|
|
if(!InstallOrUpgradeFonts()) {
|
|
b = FALSE;
|
|
}
|
|
pSetupMarkHiddenFonts();
|
|
|
|
//
|
|
// Set up pagefile and crashdump.
|
|
//
|
|
if(!SetUpVirtualMemory()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set shutdown variables in the registry.
|
|
//
|
|
if(!SetShutdownVariables()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Do Win95 migration, if necessary
|
|
//
|
|
if( Win95Upgrade ) {
|
|
HWND Win9xBillboard;
|
|
CHAR WindowsDirectoryAnsi[ MAX_PATH + 1 ];
|
|
|
|
// Win9xBillboard = DisplayBillboard(MainWindowHandle,MSG_MIGRATING_WIN95);
|
|
GetWindowsDirectoryA( WindowsDirectoryAnsi, MAX_PATH );
|
|
if( !MigrateWin95Settings( SyssetupInf, WindowsDirectoryAnsi ) ) {
|
|
b = FALSE;
|
|
}
|
|
// KillBillboard(Win9xBillboard);
|
|
}
|
|
#endif // def _X86_
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Install optional components.
|
|
//
|
|
DoInstallOptionalComponents();
|
|
|
|
//
|
|
// There's nothing specific to preinstall about cmdlines.txt.
|
|
// In retail cases the file simply won't exit. Calling this in
|
|
// all cases simplifies things for some people out there.
|
|
//
|
|
if(!ExecutePreinstallCommands()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_CONFIGURING_COMPUTER);
|
|
|
|
//
|
|
// Save off the userdef hive. Don't change the ordering here
|
|
// unless you know what you're doing!
|
|
//
|
|
GetWindowsDirectory(TempString,MAX_PATH);
|
|
ConcatenatePaths(TempString,L"PROFILES\\DEFAULT USER\\NTUSER.DAT",MAX_PATH,NULL);
|
|
if(!SaveHive(HKEY_USERS,L".DEFAULT",TempString)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set wallpaper and screen saver.
|
|
//
|
|
if(!SetDefaultWallpaper()) {
|
|
b = FALSE;
|
|
}
|
|
if(!SetLogonScreensaver()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
if(!CopyOptionalDirectories()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Apply ACLs.
|
|
//
|
|
if(ApplyAcls(MainWindowHandle,L"perms.inf",0,NULL) != NO_ERROR) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!b) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FinishUpgrade(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL b;
|
|
WCHAR TempString[MAX_PATH];
|
|
DWORD DontCare;
|
|
HWND Billboard;
|
|
DWORD VolumeFreeSpaceMB[26];
|
|
|
|
MYASSERT(Upgrade);
|
|
b = TRUE;
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_UPGRADING);
|
|
|
|
//
|
|
// Fix security - BobDay/EricFlo hack
|
|
// Remove this after NT 4.0
|
|
//
|
|
InvokeExternalApplication(L"SHMGRATE",
|
|
L"Fix-Win-Security",
|
|
&DontCare);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Reset the Win9xUpg flag in the registry.
|
|
// This should always be done in the upgrade case.
|
|
//
|
|
ResetWin9xUpgValue();
|
|
#endif // def _X86_
|
|
|
|
//
|
|
// Create config.sys/autoexec.bat/msdos.sys/io.sys, if they
|
|
// don't already exist
|
|
//
|
|
if(!ConfigureMsDosSubsystem()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!FixQuotaEntries()) {
|
|
b = FALSE;
|
|
}
|
|
if(!WinIniAlter2()) {
|
|
b = FALSE;
|
|
}
|
|
if(!InstallOrUpgradeFonts()) {
|
|
b = FALSE;
|
|
}
|
|
pSetupMarkHiddenFonts();
|
|
//
|
|
// Restore the page file information saved during textmode setup.
|
|
// Ignore any error, since there is nothing that the user can do.
|
|
//
|
|
RestoreVirtualMemoryInfo();
|
|
if(!SetShutdownVariables()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!PerfMergeCounterNames()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
//
|
|
// Get list of free space available on each hard drive. We don't care
|
|
// about this, but it has the side effect of deleting all pagefiles,
|
|
// which we do want to do.
|
|
//
|
|
BuildVolumeFreeSpaceList(VolumeFreeSpaceMB);
|
|
|
|
//
|
|
// CAIROSETUP
|
|
//
|
|
if(!CairoSetup) {
|
|
if(!UpgradeSamDatabase()) {
|
|
KillBillboard(Billboard);
|
|
FatalError(MSG_LOG_SECURITY_CATASTROPHE);
|
|
}
|
|
}
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Upgrade program groups.
|
|
//
|
|
if(!UpgradeStartMenuItems(SyssetupInf)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!MyChangeServiceStart(szSpooler,SERVICE_AUTO_START)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
SetUpDataBlock();
|
|
DontCare = UpgradePrinters();
|
|
if(DontCare != NO_ERROR) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if( !UpdateServicesDependencies(SyssetupInf) ) {
|
|
b = FALSE;
|
|
}
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_UPGRADING);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Set NPX emulation state.
|
|
//
|
|
if(!SetNpxEmulationState()) {
|
|
b = FALSE;
|
|
}
|
|
#endif // def _X86_
|
|
|
|
if(!SetProductIdInRegistry()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
CallNetworkSetupBack(NETSETUPINSTALLSOFTWAREPROCNAME);
|
|
|
|
//
|
|
// Stamp build number
|
|
//
|
|
|
|
StampBuildNumber();
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
//
|
|
// Install optional components.
|
|
//
|
|
DoInstallOptionalComponents();
|
|
|
|
Billboard = DisplayBillboard(MainWindowHandle,MSG_UPGRADING);
|
|
|
|
//
|
|
// Save off the userdef hive. Don't change the ordering here
|
|
// unless you know what you're doing!
|
|
//
|
|
GetWindowsDirectory(TempString,MAX_PATH);
|
|
ConcatenatePaths(TempString,L"PROFILES\\DEFAULT USER\\NTUSER.DAT",MAX_PATH,NULL);
|
|
if(!SaveHive(HKEY_USERS,L".DEFAULT",TempString)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!SetDefaultWallpaper()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
KillBillboard(Billboard);
|
|
|
|
if(!CopyOptionalDirectories()) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(!b) {
|
|
AnyErrors = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CallNetworkSetupBack(
|
|
IN PCSTR ProcName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Call out to the network setup dll to allow it to install any extra software,
|
|
etc, that it needs to.
|
|
|
|
Arguments:
|
|
|
|
ProcName - supplies name of entry point in NETSETUP.DLL to call.
|
|
The routine is called with 2 args: the window handle of our main
|
|
window and a pointer to the internal setup data structure.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
HMODULE NetSetupModule;
|
|
NETSETUPINSTALLSOFTWAREPROC NetProc;
|
|
DWORD d;
|
|
BOOL b;
|
|
|
|
if(NetSetupModule = LoadLibrary(L"NETSETUP")) {
|
|
|
|
if(NetProc = (NETSETUPINSTALLSOFTWAREPROC)GetProcAddress(NetSetupModule,ProcName)) {
|
|
SetUpDataBlock();
|
|
NetProc(MainWindowHandle,&InternalSetupData);
|
|
}
|
|
|
|
//
|
|
// We don't free the library because it might create threads
|
|
// that are hanging around.
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SetUpDataBlock(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up the internal setup data block structure that
|
|
we use to communicate information to the network setup wizard.
|
|
Note that we passed a pointer to this structure when we fetched
|
|
the net setup wizard pages but at that point the structure was completely
|
|
uninitialized.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR p;
|
|
WCHAR str[1024];
|
|
|
|
InternalSetupData.dwSizeOf = sizeof(INTERNAL_SETUP_DATA);
|
|
|
|
//
|
|
// Set the mode: custom, laptop, minimal, typical
|
|
//
|
|
InternalSetupData.SetupMode = SetupMode;
|
|
|
|
//
|
|
// Set the product type: workstation, dc, etc.
|
|
//
|
|
InternalSetupData.ProductType = ProductType;
|
|
|
|
//
|
|
// Set the operation flags.
|
|
//
|
|
if(Win31Upgrade) {
|
|
InternalSetupData.OperationFlags |= SETUPOPER_WIN31UPGRADE;
|
|
}
|
|
if(Win95Upgrade) {
|
|
InternalSetupData.OperationFlags |= SETUPOPER_WIN95UPGRADE;
|
|
}
|
|
if(Upgrade) {
|
|
InternalSetupData.OperationFlags |= SETUPOPER_NTUPGRADE;
|
|
}
|
|
if(Unattended) {
|
|
InternalSetupData.OperationFlags |= SETUPOPER_BATCH;
|
|
InternalSetupData.UnattendFile = AnswerFile;
|
|
}
|
|
|
|
//
|
|
// Tell the net guys the source path.
|
|
//
|
|
InternalSetupData.SourcePath = SourcePath;
|
|
InternalSetupData.LegacySourcePath = LegacySourcePath;
|
|
|
|
//
|
|
// If we are installing from CD then assume all platforms
|
|
// are available.
|
|
//
|
|
if(SourcePath[0] && (SourcePath[1] == L':') && (SourcePath[2] == L'\\')) {
|
|
|
|
lstrcpyn(str,SourcePath,4);
|
|
if(GetDriveType(str) == DRIVE_CDROM) {
|
|
|
|
InternalSetupData.OperationFlags |= SETUPOPER_ALLPLATFORM_AVAIL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Tell the net guys the wizard title they should use.
|
|
//
|
|
if(!InternalSetupData.WizardTitle) {
|
|
p = NULL;
|
|
if(LoadString(MyModuleHandle,SetupTitleStringId,str,sizeof(str)/sizeof(str[0]))) {
|
|
p = DuplicateString(str);
|
|
}
|
|
InternalSetupData.WizardTitle = p ? p : L"";
|
|
}
|
|
|
|
//
|
|
// Reset the two call-specific data fields.
|
|
//
|
|
InternalSetupData.CallSpecificData1 = InternalSetupData.CallSpecificData2 = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
InstallWindowsNt(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main entry point for syssetup.dll. Responsible for installing
|
|
NT on system by calling the required components in the proper
|
|
order.
|
|
|
|
Arguments:
|
|
|
|
Dummy argc/argv. Not used.
|
|
|
|
Returns:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(argc);
|
|
UNREFERENCED_PARAMETER(argv);
|
|
|
|
//
|
|
// Indicate that we're running in Setup, not in appwiz.
|
|
//
|
|
IsSetup = TRUE;
|
|
|
|
//
|
|
// Initialization phase. Common to initial install and upgrade.
|
|
//
|
|
CommonInitialization();
|
|
|
|
if(Upgrade) {
|
|
|
|
InitializePidVariables();
|
|
|
|
} else {
|
|
if(!InitializePidVariables()) {
|
|
FatalError(MSG_SETUP_CANT_READ_PID);
|
|
}
|
|
//
|
|
// Do the wizard. Time how long it takes, to later help further randomize
|
|
// the account domain sid we're going to generate later.
|
|
//
|
|
PreWizardTickCount = GetTickCount();
|
|
}
|
|
|
|
SetUpDataBlock();
|
|
InternalSetupData.CallSpecificData1 = (DWORD)PnPInitThreadHandle;
|
|
Wizard();
|
|
|
|
//
|
|
// After the wizard the net stuff is done. Re-read the product type
|
|
// which might have been changed by them (such as changing PDC/BDC).
|
|
//
|
|
ProductType = InternalSetupData.ProductType;
|
|
|
|
//
|
|
// Perform tasks that occur after the wizard and net setup are done.
|
|
//
|
|
if(Upgrade) {
|
|
FinishUpgrade();
|
|
} else {
|
|
FinishSetup();
|
|
}
|
|
|
|
//
|
|
// Termination phase. Common to initial install and upgrade.
|
|
//
|
|
FinishUp();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Lame global variable used for subclassing.
|
|
//
|
|
WNDPROC OldEditProc;
|
|
|
|
LONG
|
|
CALLBACK
|
|
EulaEditSubProc(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Edit control subclass routine, to avoid highlighting text when user
|
|
tabs to the edit control.
|
|
|
|
Arguments:
|
|
|
|
Standard window proc arguments.
|
|
|
|
Returns:
|
|
|
|
Message-dependent value.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// For setsel messages, make start and end the same.
|
|
//
|
|
if((msg == EM_SETSEL) && ((LPARAM)wParam != lParam)) {
|
|
lParam = wParam;
|
|
}
|
|
|
|
return(CallWindowProc(OldEditProc,hwnd,msg,wParam,lParam));
|
|
}
|
|
|
|
|
|
BOOL
|
|
CALLBACK
|
|
EulaDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
HWND EditControl;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
EditControl = GetDlgItem(hdlg,IDT_EDIT1);
|
|
OldEditProc = (WNDPROC)GetWindowLong(EditControl,GWL_WNDPROC);
|
|
SetWindowLong(EditControl,GWL_WNDPROC,(LONG)EulaEditSubProc);
|
|
|
|
SetWindowText(EditControl,(PCWSTR)lParam);
|
|
|
|
CenterWindowRelativeToParent(hdlg);
|
|
return(TRUE);
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch(LOWORD(wParam)) {
|
|
|
|
case IDYES:
|
|
EndDialog(hdlg,TRUE);
|
|
break;
|
|
|
|
case IDNO:
|
|
EndDialog(hdlg,FALSE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayEula(
|
|
IN OUT HWND *Billboard
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the end-user licensing agreement.
|
|
|
|
Arguments:
|
|
|
|
Billboard - on input supplies window handle of "Setup is Initializing"
|
|
billboard. On ouput receives new window handle if we had to
|
|
display ui (in which case we would have killed and then
|
|
redisplayed the billboard).
|
|
|
|
Returns:
|
|
|
|
None. Does not return if the user elects not to accept the agreement.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR EulaPath[MAX_PATH];
|
|
HANDLE hFile, hFileMapping;
|
|
DWORD FileSize;
|
|
BYTE *pbFile;
|
|
PWSTR EulaText;
|
|
DWORD d;
|
|
|
|
//
|
|
// If not preinstall then this was displayed at start of text mode
|
|
// and we don't do it here.
|
|
//
|
|
if(!Preinstall || OemSkipEula) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Map the file containing the licensing agreement.
|
|
//
|
|
|
|
lstrcpy (EulaPath, LegacySourcePath);
|
|
ConcatenatePaths (EulaPath, L"eula.txt", MAX_PATH, NULL);
|
|
|
|
hFile = CreateFile (
|
|
EulaPath,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if(hFile == INVALID_HANDLE_VALUE) {
|
|
KillBillboard(*Billboard);
|
|
FatalError(MSG_EULA_ERROR);
|
|
}
|
|
|
|
hFileMapping = CreateFileMapping (
|
|
hFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0, 0,
|
|
NULL
|
|
);
|
|
if(hFileMapping == NULL) {
|
|
KillBillboard(*Billboard);
|
|
FatalError(MSG_EULA_ERROR);
|
|
}
|
|
|
|
pbFile = MapViewOfFile (
|
|
hFileMapping,
|
|
FILE_MAP_READ,
|
|
0, 0,
|
|
0
|
|
);
|
|
if(pbFile == NULL) {
|
|
KillBillboard(*Billboard);
|
|
FatalError(MSG_EULA_ERROR);
|
|
}
|
|
|
|
//
|
|
// Translate the text from ANSI to Unicode.
|
|
//
|
|
FileSize = GetFileSize (hFile, NULL);
|
|
if(FileSize == 0xFFFFFFFF) {
|
|
FatalError(MSG_EULA_ERROR);
|
|
}
|
|
|
|
EulaText = MyMalloc ((FileSize+1) * sizeof(WCHAR));
|
|
if(EulaText == NULL) {
|
|
KillBillboard(*Billboard);
|
|
FatalError(MSG_EULA_ERROR);
|
|
}
|
|
|
|
MultiByteToWideChar (
|
|
CP_ACP,
|
|
0,
|
|
pbFile,
|
|
FileSize,
|
|
EulaText,
|
|
(FileSize+1) * sizeof(WCHAR)
|
|
);
|
|
|
|
EulaText[FileSize] = 0;
|
|
|
|
//
|
|
// Display the text
|
|
//
|
|
KillBillboard(*Billboard);
|
|
|
|
d = (DWORD)DialogBoxParam(
|
|
MyModuleHandle,
|
|
MAKEINTRESOURCE(IDD_EULA),
|
|
MainWindowHandle,
|
|
EulaDlgProc,
|
|
(LPARAM)EulaText
|
|
);
|
|
if(!d) {
|
|
FatalError(MSG_NOT_ACCEPT_EULA);
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
*Billboard = DisplayBillboard(MainWindowHandle,MSG_INITIALIZING);
|
|
|
|
MyFree (EulaText);
|
|
UnmapViewOfFile (pbFile);
|
|
CloseHandle (hFileMapping);
|
|
CloseHandle (hFile);
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveMSKeyboardPtrPropSheet (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fixes problem with IntelliType Manager under NT 4.0 by disabling it.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hkeyDir; // handle of the key containing the directories
|
|
TCHAR szKbdCpPath[MAX_PATH]; // buffer for the fully-qualified path to INI file
|
|
LONG lRet; // return value from RegQueryValueEx
|
|
DWORD dwDataType; // data-type returned from call to RegQueryValueEx
|
|
DWORD BufferSize;
|
|
PCWSTR sz_off = L"OFF";
|
|
|
|
//
|
|
// open the key that contains the directories of all the software for all the MS Input Devices
|
|
//
|
|
RegOpenKey ( HKEY_CURRENT_USER,
|
|
L"Control Panel\\Microsoft Input Devices\\Directories", &hkeyDir );
|
|
|
|
//
|
|
// get the path to the MS Keyboard software
|
|
//
|
|
BufferSize = sizeof (szKbdCpPath);
|
|
lRet = RegQueryValueEx ( hkeyDir, L"Keyboard", 0, &dwDataType,
|
|
(LPBYTE)szKbdCpPath, &BufferSize);
|
|
|
|
//
|
|
// close the directories key now
|
|
//
|
|
RegCloseKey ( hkeyDir );
|
|
|
|
// check if we were able to get the directory of the keyboard software; if not, then
|
|
// there may be no keyboard software installed or at least we don't know where
|
|
// to find it; if we got it OK, then use it
|
|
if ( lRet == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// we have the path to the INI file, so build the fully qualified path to the INI file
|
|
//
|
|
lstrcat ( szKbdCpPath, L"\\KBDCP.INI" );
|
|
|
|
//
|
|
// remove the KBDPTR32.DLL entry from the list of 32-bit property sheet DLLs now,
|
|
// because we don't want it loading on Windows NT 4.0 or later
|
|
WritePrivateProfileString ( L"Property Sheets 32", L"KBDPTR32.DLL",
|
|
NULL, szKbdCpPath );
|
|
|
|
lRet = RegOpenKey (HKEY_CURRENT_USER,
|
|
L"Control Panel\\Microsoft Input Devices\\WindowsPointer",
|
|
&hkeyDir);
|
|
|
|
if (lRet == ERROR_SUCCESS) {
|
|
|
|
RegSetValueEx (
|
|
hkeyDir,
|
|
L"MouseKey",
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)sz_off,
|
|
(lstrlen(sz_off)+1) * sizeof(WCHAR)
|
|
);
|
|
|
|
RegCloseKey (hkeyDir);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FixWordPadReg (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fixes problem with registry entry that associates .doc files with WordPad.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCWSTR SearchString = L"WordPad.Document";
|
|
PCWSTR ReplaceString = L"WordPad.Document.1";
|
|
LONG Ret;
|
|
HKEY Key;
|
|
DWORD Type;
|
|
BYTE Data[MAX_PATH];
|
|
DWORD Size = MAX_PATH;
|
|
|
|
Ret = RegOpenKeyEx (
|
|
HKEY_CLASSES_ROOT,
|
|
L".doc",
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&Key
|
|
);
|
|
if (Ret != ERROR_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
Ret = RegQueryValueEx (
|
|
Key,
|
|
L"",
|
|
NULL,
|
|
&Type,
|
|
Data,
|
|
&Size
|
|
);
|
|
if (Ret != ERROR_SUCCESS ||
|
|
lstrcmp ((PCWSTR)Data, SearchString)) {
|
|
|
|
return;
|
|
}
|
|
|
|
RegSetValueEx (
|
|
Key,
|
|
L"",
|
|
0,
|
|
Type,
|
|
(PBYTE)ReplaceString,
|
|
(lstrlen (ReplaceString) + 1) * sizeof (WCHAR)
|
|
);
|
|
}
|