Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2181 lines
59 KiB

#include "precomp.h"
#pragma hdrstop
#include "msg.h"
#define DEFAULT_INF_NAME TEXT("DOSNET.INF")
#define LOCAL_SOURCE_DIRECTORY_ROOT TEXT("\\$WIN_NT$.~LS")
#define LINELENGTH 2048
#define OUTBUFLENGTH 65536
//
// Module instance.
//
HANDLE hInst;
//
// Execution paramaters.
//
PTSTR InfName;
PTSTR Sources[MAX_SOURCES];
UINT SourceCount;
PTSTR OptionalDirs[MAX_OPTIONALDIRS];
UINT OptionalDirCount;
UINT OptionalDirFlags[MAX_OPTIONALDIRS];
BOOL ServerProduct = FALSE;
BOOL CreateLocalSource = TRUE;
//
// Flag that indicates that we are running OEM preinstall
//
BOOLEAN OemPreInstall = FALSE;
PTSTR OemSystemDirectory = WINNT_OEM_DIR;
PTSTR OemOptionalDirectory = WINNT_OEM_OPTIONAL_DIR;
//
// Keep track of any OEM boot file specified on [OemBootFiles]
// in the script file
//
ULONG OemBootFilesCount;
PTSTR OemBootFiles[MAX_OEMBOOTFILES];
//
// String ID of the application title and OSLOADOPTIONS value
//
DWORD AppTitleStringId = IDS_LOADID;
DWORD AppIniStringId;
DWORD TlsIndex;
//
// Drive letter of system partition we will use.
//
TCHAR SystemPartitionDrive;
//
// We have to use GetProcAddress because GetVersionEx doesn't exist on NT 3.1
//
#ifdef UNICODE
CHAR GetVersionExName[] = "GetVersionExW";
typedef BOOL (WINAPI* GETVEREXPROC)(LPOSVERSIONINFOW);
#else
CHAR GetVersionExName[] = "GetVersionExA";
typedef BOOL (WINAPI* GETVEREXPROC)(LPOSVERSIONINFOA);
#endif
#ifdef _X86_
//
// Values that control how we deal with/make boot floppies.
//
BOOL CreateFloppies = TRUE;
BOOL FloppylessOperation = FALSE;
FLOPPY_OPTION FloppyOption = StandardInstall;
BOOL AColonIsAcceptable = TRUE;
//
// Minimum space (in bytes) we'd like to see on the system partition
//
#define MIN_SYSPART_SPACE (512*1024)
TCHAR FloppylessBootDirectory[] = TEXT("\\$WIN_NT$.~BT");
CHAR FloppylessBootImageFile[] = "?:\\$WIN_NT$.~BT\\BOOTSECT.DAT";
TCHAR BootIniName[] = TEXT("?:\\BOOT.INI");
TCHAR BootIniBackUpName[] = TEXT("?:\\BOOT.BAK");
BOOL BootIniModified = FALSE;
#else
//
// Minimum space (in bytes) we'd like to see on the system partition
//
#define MIN_SYSPART_SPACE (1024*1024)
#endif
//
// Unattended operation, meaning that we get things going on our own
// using given parameters, without waiting for the user to click
// any buttons, etc.
//
// The '/u<x>' switch may be specified to force a shutdown after <x>
// seconds expire.
//
// The user can also specify a script file, which will be used
// during text mode setup to automate operation.
//
BOOL UnattendedOperation;
PTSTR UnattendedScriptFile;
unsigned long UnattendedShutdownTimeout;
//
// Drive, Pathname part, and full path of the local source directory.
//
TCHAR LocalSourceDrive;
PTSTR LocalSourceDirectory = LOCAL_SOURCE_DIRECTORY_ROOT;
PTSTR LocalSourcePath;
PTSTR LocalSourceSubPath;
//
// Local source drive specified on command line with /t.
//
TCHAR CmdLineLocalSourceDrive;
BOOL SkipNotPresentFiles;
BOOL SpecialNotPresentFilesMode;
PCWSTR MissingFileListName;
PTSTR CmdToExecuteAtEndOfGui;
PTSTR NumberOfLicensedProcessors;
//
// UDF stuff
//
PWSTR UniquenessId;
PWSTR UniquenessDatabaseFile;
//
// Icon handle of main icon.
//
HICON MainIcon;
//
// Help filename.
//
PTSTR szHELPFILE = TEXT("winnt32.hlp");
//
// Platform-specific subdirectories.
//
#if defined(_ALPHA_)
PWSTR PlatformSpecificDir = L"alpha";
PTSTR LocalSourceSubDirectory = LOCAL_SOURCE_DIRECTORY_ROOT L"\\alpha";
#elif defined(_MIPS_)
PWSTR PlatformSpecificDir = L"mips";
PTSTR LocalSourceSubDirectory = LOCAL_SOURCE_DIRECTORY_ROOT L"\\mips";
#elif defined(_PPC_)
PWSTR PlatformSpecificDir = L"ppc";
PTSTR LocalSourceSubDirectory = LOCAL_SOURCE_DIRECTORY_ROOT L"\\ppc";
#elif defined(_X86_)
LPTSTR PlatformSpecificDir = TEXT("i386");
PTSTR LocalSourceSubDirectory = LOCAL_SOURCE_DIRECTORY_ROOT TEXT("\\i386");
#endif
VOID
LockApplicationInMemory(
VOID
);
BOOL
DnPatchWinntSifFile(
IN PTSTR Filename
)
/*++
Routine Description:
This function works around the problems in the
setupldr parser which cannot handle unquoted strings.
Each line in the WINNT.SIF file is enclosed within
quotation marks
Arguments:
FileName - Name of the WINNT.SIF file
Return Value:
TRUE - if successful
FALSE - if failure
--*/
{
PVOID Base;
HANDLE hMap,hFile;
DWORD Size;
DWORD d;
PCHAR End;
PCHAR p,q;
PCHAR o,a;
PCHAR Buffer;
int l1,l2;
//
// Open the file.
//
d = DnMapFile(Filename,&Size,&hFile,&hMap,&Base);
if(d != NO_ERROR) {
return(FALSE);
}
//
// Allocate and zero out the output buffer
//
Buffer = MALLOC(OUTBUFLENGTH);
o = Buffer;
p = Base;
End = p+Size;
while(p < End) {
//
// Find end of line.
//
for(q=p; (q < End) && (*q != '\n'); q++) {
NOTHING;
}
//
// Find equals sign, if present
//
for(a=p; a<=q; a++) {
if(*a == '=') {
break;
}
}
if(a > q) {
a = NULL;
}
if(a) {
a++;
l1 = a - p;
l2 = q - a;
CopyMemory(o,p,l1);
o += l1;
*o++ = '\"';
CopyMemory(o,a,l2);
o += l2;
if(*(o-1) == '\r') {
o--;
}
*o++ = '\"';
*o++ = '\r';
*o++ = '\n';
} else {
l1 = q-p;
CopyMemory(o,p,l1);
o += l1;
*o++ = '\n';
}
//
// Skip to start of next line
//
p=q+1;
}
DnUnmapFile(hMap,Base);
CloseHandle(hFile);
SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
hFile = CreateFile(
Filename,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(hFile == INVALID_HANDLE_VALUE) {
FREE(Buffer);
return(FALSE);
}
d = WriteFile(hFile,Buffer,o-Buffer,&Size,NULL);
CloseHandle(hFile);
FREE(Buffer);
return(d);
}
BOOL
DnIndicateWinnt(
IN HWND hdlg,
IN PTSTR Path,
IN PTSTR OriginalAutoload,
IN PTSTR OriginalCountdown
)
/*++
Routine Description:
Write a small ini file on the given path to indicate to
text setup that it is in the middle of a winnt setup.
Arguments:
Return Value:
Boolean value indicating whether the file was written successfully.
--*/
{
PTSTR WinntData = WINNT_DATA;
PTSTR WinntSetup = WINNT_SETUPPARAMS;
PTSTR WinntNull = WINNT_A_NULL;
PTSTR WinntUniqueId = WINNT_D_UNIQUEID;
TCHAR Str[MAX_PATH];
TCHAR FullPath[MAX_PATH];
TCHAR FileName[MAX_PATH];
TCHAR UdfPath[MAX_PATH];
PTSTR OptionalDirString;
PTSTR p;
ULONG OptionalDirLength = 0;
BOOL b;
DWORD Disposition;
DWORD ec;
HKEY hKey;
LONG l;
#ifndef _X86_
CHAR AutoloadLine[128];
CHAR CountdownLine[128];
#endif
lstrcpy(FileName,Path);
DnConcatenatePaths(FileName,WINNT_SIF_FILE,MAX_PATH);
b = WritePrivateProfileString(WinntData,WINNT_D_MSDOS,TEXT("1"),FileName);
#ifndef _X86_
if(b) {
//
// Ignore errors -- this part is just not that critical.
//
if(OriginalAutoload) {
WritePrivateProfileString(WinntData,WINNT_D_ORI_LOAD,OriginalAutoload,FileName);
}
if(OriginalCountdown) {
WritePrivateProfileString(WinntData,WINNT_D_ORI_COUNT,OriginalCountdown,FileName);
}
}
#endif // ndef _X86_
if(b && SpecialNotPresentFilesMode) {
b = WritePrivateProfileString(WinntSetup,WINNT_S_SKIPMISSING,TEXT("1"),FileName);
}
if(b && OptionalDirCount) {
//
// If an optional dir string is present then we want to generate
// an entry in the sif file that contains a line with the dir
// string in the form of dir1*dir2*...*dirn
//
OptionalDirString = NULL;
for(ec=0; ec<OptionalDirCount; ec++) {
if( ( OptionalDirFlags[ec] & OPTDIR_OEMOPT ) ||
( OptionalDirFlags[ec] & OPTDIR_OEMSYS ) ) {
continue;
}
if(!(OptionalDirFlags[ec] & OPTDIR_TEMPONLY)) {
p = OptionalDirs[ec];
if(OptionalDirLength == 0) {
OptionalDirString = MALLOC((lstrlen(p)+2)*sizeof(TCHAR));
lstrcpy(OptionalDirString,p);
} else {
OptionalDirString = REALLOC(
OptionalDirString,
(lstrlen(p) + 2 + OptionalDirLength) * sizeof(TCHAR)
);
lstrcat(OptionalDirString,p);
}
lstrcat(OptionalDirString,TEXT("*"));
OptionalDirLength = lstrlen(OptionalDirString);
}
}
if(OptionalDirString) {
//
// Remove trailing * if any
//
l = lstrlen(OptionalDirString);
if(l && (OptionalDirString[l-1] == TEXT('*'))) {
OptionalDirString[l-1] = 0;
}
b = WritePrivateProfileString(
WinntSetup,
WINNT_S_OPTIONALDIRS,
OptionalDirString,
FileName
);
FREE(OptionalDirString);
}
OptionalDirLength = 0;
}
if(b && CmdToExecuteAtEndOfGui) {
b = WritePrivateProfileString(WinntSetup,WINNT_S_USEREXECUTE,CmdToExecuteAtEndOfGui,FileName);
}
#ifdef _X86_
if(b && FloppylessOperation) {
b = WritePrivateProfileString(WinntData,WINNT_D_FLOPPY,TEXT("1"),FileName);
}
#endif
//
// Slap a unique identifier into the registry.
// We'll use this in unattended upgrade during text mode
// to find this build.
//
if(b) {
//
// Form a string we think is unique enough
// to indentify this installation.
//
// Pretty simple: we'll use a string that derives
// from the sysroot, and some unique value based on
// the current tick count.
//
ec = GetWindowsDirectory(Str,MAX_PATH);
if((ec + 5) > MAX_PATH) {
ec = MAX_PATH - 5;
}
Str[ec++] = TEXT('\\');
Str[ec++] = (TCHAR)(((GetTickCount() & 0x00f) >> 0) + 'A');
Str[ec++] = (TCHAR)(((GetTickCount() & 0x0f0) >> 4) + 'A');
Str[ec++] = (TCHAR)(((GetTickCount() & 0xf00) >> 8) + 'A');
Str[ec++] = 0;
//
// Set the value in the registry.
//
l = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\Setup"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
&hKey,
&Disposition
);
if(l == NO_ERROR) {
l = RegSetValueEx(
hKey,
WinntUniqueId,
0,
REG_SZ,
(CONST BYTE *)Str,
ec * sizeof(TCHAR)
);
if(l != NO_ERROR) {
b = FALSE;
}
RegCloseKey(hKey);
} else {
b = FALSE;
}
//
// Stick the value in winnt.sif so we can correlate
// later when we go to upgrade.
//
if(b) {
b = WritePrivateProfileString(WinntData,WinntUniqueId,Str,FileName);
}
}
//
// Remember udf info
//
if(b && UniquenessId) {
b = WritePrivateProfileString(WinntData,WINNT_D_UNIQUENESS,UniquenessId,FileName);
if (b && UniquenessDatabaseFile) {
lstrcpy(UdfPath, LocalSourcePath);
DnConcatenatePaths(UdfPath, WINNT_UNIQUENESS_DB, MAX_PATH);
b = CopyFile (UniquenessDatabaseFile, UdfPath, FALSE);
}
}
//
// Now write information about the source path(s) we used.
// Use Source[0].
//
if(b) {
//
// If the name starts with \\ then we assume it's UNC and
// just use it directly. Otherwise we call MyGetDriveType on it
// and if it's a network drive we get the UNC path.
// Otherwise we just go ahead and save as-is.
// Also save the type.
//
if((Sources[0][0] == TEXT('\\')) && (Sources[0][1] == TEXT('\\'))) {
Disposition = DRIVE_REMOTE;
_lstrcpyn(Str,Sources[0],MAX_PATH);
} else {
if(GetFullPathName(Sources[0],MAX_PATH,FullPath,&p)) {
if(FullPath[0] == TEXT('\\')) {
//
// Assume UNC, since a full path should normally start
// with a drive letter.
//
Disposition = DRIVE_REMOTE;
_lstrcpyn(Str,FullPath,MAX_PATH);
} else {
Disposition = MyGetDriveType(FullPath[0]);
if((Disposition == DRIVE_REMOTE) && (FullPath[1] == TEXT(':')) && (FullPath[2] == TEXT('\\'))) {
//
// Get actual UNC path.
//
FullPath[2] = 0;
l = MAX_PATH;
if(WNetGetConnection(FullPath,Str,(LPDWORD)&l) == NO_ERROR) {
l = lstrlen(Str);
if(Str[l-1] != TEXT('\\') && FullPath[3]) {
Str[l] = TEXT('\\');
Str[l+1] = 0;
}
lstrcat(Str,FullPath+3);
} else {
//
// Strange case.
//
FullPath[2] = TEXT('\\');
_lstrcpyn(Str,FullPath,MAX_PATH);
Disposition = DRIVE_UNKNOWN;
}
} else {
//
// Use as-is.
//
if(Disposition == DRIVE_REMOTE) {
Disposition = DRIVE_UNKNOWN;
}
_lstrcpyn(Str,FullPath,MAX_PATH);
}
}
} else {
//
// Type is unknown. Just use as-is.
//
Disposition = DRIVE_UNKNOWN;
_lstrcpyn(Str,Sources[0],MAX_PATH);
}
}
//
// In the preinstall case ignore all the above and
// force gui setup to search for a CD.
// This particular combination of values will do it.
//
if(OemPreInstall) {
lstrcpy(Str,L"A:\\");
DnConcatenatePaths(Str,PlatformSpecificDir,MAX_PATH);
Disposition = DRIVE_CDROM;
}
WritePrivateProfileString(WinntData,WINNT_D_ORI_SRCPATH,Str,FileName);
wsprintf(Str,TEXT("%u"),Disposition);
WritePrivateProfileString(WinntData,WINNT_D_ORI_SRCTYPE,Str,FileName);
}
//
// At this point we process the file, and surround all values with
// double-quotes. This gets around certain problems in the various
// inf parsers used in later stages of setup. Do this BEFORE appending
// the unattend stript file, because some of the stuff in there expects
// to be treated as multiple values, which double quotes ruin.
//
if(b) {
b = DnPatchWinntSifFile(FileName);
}
//
// Append script file if necessary.
//
if(b && UnattendedOperation) {
if(UnattendedScriptFile) {
TCHAR *SectionNames;
TCHAR *SectionData;
DWORD SectionNamesSize;
DWORD SectionDataSize;
TCHAR *SectionName;
#define PROFILE_BUFSIZE 16384
#define PROFILE_BUFGROW 4096
//
// Allocate some memory for the required buffers
//
SectionNames = MALLOC(PROFILE_BUFSIZE * sizeof(TCHAR));
SectionData = MALLOC(PROFILE_BUFSIZE * sizeof(TCHAR));
SectionNamesSize = PROFILE_BUFSIZE;
SectionDataSize = PROFILE_BUFSIZE;
//
// Retreive a list of section names in the unattend script file.
//
while(GetPrivateProfileString(
NULL,
NULL,
TEXT(""),
SectionNames,
SectionNamesSize,
UnattendedScriptFile
) == (SectionNamesSize-2)) {
//
// Realloc the buffer and try again.
//
SectionNames = REALLOC(
SectionNames,
(SectionNamesSize+PROFILE_BUFGROW)*sizeof(TCHAR)
);
SectionNamesSize += PROFILE_BUFGROW;
}
for(SectionName=SectionNames; b && *SectionName; SectionName+=lstrlen(SectionName)+1) {
//
// Ignore the [data] section in the source, as we do not
// want copy it into the target, because this would overwrite
// our internal settings.
// Ignore also [OemBootFiles]
//
if((lstrcmpi(SectionName,WinntData)!=0) &&
(lstrcmpi(SectionName,WINNT_OEMBOOTFILES) != 0)) {
//
// Fetch the entire section and write it to the target file.
// Note that the section-based API call will leave double-quotes
// intact when we retrieve the data, which is what we want.
// Key-based API calls will strip quotes, which screws us.
//
while(GetPrivateProfileSection(
SectionName,
SectionData,
SectionDataSize,
UnattendedScriptFile
) == (SectionDataSize-2)) {
//
// Realloc the buffer and try again.
//
SectionData = REALLOC(
SectionData,
(SectionDataSize+PROFILE_BUFGROW)*sizeof(TCHAR)
);
SectionDataSize += PROFILE_BUFGROW;
}
//
// Write the entire section to the output file.
//
if(!WritePrivateProfileSection(SectionName,SectionData,FileName)) {
b = FALSE;
}
}
}
FREE(SectionNames);
FREE(SectionData);
} else {
//
// No script file. Create a dummy [Unattended] section
// so text setup knows it's an unattended setup.
// Also, since this is being run from within NT, we assume the
// user wants to do an upgrade, so we add "NtUpgrade = yes".
//
b = WritePrivateProfileString(
WINNT_UNATTENDED,
WINNT_U_NTUPGRADE,
WINNT_A_YES,
FileName
);
}
}
return(b);
}
VOID
MyWinHelp(
IN HWND hdlg,
IN DWORD ContextId
)
{
TCHAR Buffer[2*MAX_PATH];
PTSTR p;
HANDLE FindHandle;
BOOL b;
WIN32_FIND_DATA FindData;
//
// The likely scenario is that a user invokes winnt32 from
// a network share. We'll expect the help file to be there too.
//
b = FALSE;
if(GetModuleFileName(NULL,Buffer,SIZECHARS(Buffer))
&& (p = StringRevChar(Buffer,TEXT('\\'))))
{
lstrcpy(p+1,szHELPFILE);
//
// See whether the help file is there. If so, use it.
//
FindHandle = FindFirstFile(Buffer,&FindData);
if(FindHandle != INVALID_HANDLE_VALUE) {
FindClose(FindHandle);
b = WinHelp(hdlg,Buffer,HELP_CONTEXT,ContextId);
}
}
if(!b) {
//
// Try just the base help file name.
//
b = WinHelp(hdlg,szHELPFILE,HELP_CONTEXT,ContextId);
}
if(!b) {
//
// Tell user.
//
MessageBoxFromMessage(
hdlg,
MSG_CANT_OPEN_HELP_FILE,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION,
szHELPFILE
);
}
}
BOOL
DlgProcSimpleBillboard(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
switch(msg) {
case WM_INITDIALOG:
{
HANDLE hThread;
DWORD idThread;
PSIMPLE_BILLBOARD Params;
TCHAR CaptionText[128];
Params = (PSIMPLE_BILLBOARD)lParam;
//
// Set the caption text.
//
LoadString(hInst,Params->CaptionStringId,CaptionText,SIZECHARS(CaptionText));
SetWindowText(hdlg,CaptionText);
//
// Center the (entire) dialog on the screen and
// save this position and size.
//
CenterDialog(hdlg);
//
// Fire up a thread that will perform the real work.
//
hThread = CreateThread(
NULL,
0,
Params->AssociatedAction,
hdlg,
0,
&idThread
);
if(hThread) {
CloseHandle(hThread);
}
}
return(TRUE);
case WMX_BILLBOARD_STATUS:
//
// lParam = status text.
//
SetDlgItemText(hdlg,IDC_TEXT1,(PTSTR)lParam);
break;
case WMX_BILLBOARD_DONE:
//
// lParam is a flag indicating whether we should continue.
//
EndDialog(hdlg,lParam);
break;
default:
return(FALSE);
}
return(TRUE);
}
int
ActionWithBillboard(
IN PTHREAD_START_ROUTINE Action,
IN DWORD BillboardCaptionStringId,
IN HWND hwndOwner
)
{
SIMPLE_BILLBOARD BillboardParams;
int i;
BillboardParams.AssociatedAction = Action;
BillboardParams.CaptionStringId = BillboardCaptionStringId;
i = DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_SIMPLE_BILLBOARD),
hwndOwner,
DlgProcSimpleBillboard,
(LPARAM)&BillboardParams
);
return(i);
}
BOOL
DlgProcMain(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
int i;
UINT res;
PTSTR p;
switch(msg) {
case WM_INITDIALOG:
//
// Center the (entire) dialog on the screen and
// save this position and size.
//
CenterDialog(hdlg);
SendMessage(hdlg,WMX_INITCTLS,0,0);
PostMessage(hdlg,WMX_MAIN_DIALOG_UP,0,0);
return(FALSE);
case WMX_INITCTLS:
//
// Set and select the edit text and set focus to the control.
//
if(SourceCount > 1) {
p = MyLoadString(IDS_MULTISRC1);
SetDlgItemText(hdlg,IDC_EDIT1,p);
FREE(p);
SetFocus(GetDlgItem(hdlg,IDOK));
EnableWindow(GetDlgItem(hdlg,IDC_EDIT1),FALSE);
} else {
if(!SetDlgItemText(hdlg,IDC_EDIT1,Sources[0])) {
OutOfMemory();
}
EnableWindow(GetDlgItem(hdlg,IDC_EDIT1),TRUE);
SendDlgItemMessage(hdlg,IDC_EDIT1,EM_SETSEL,0,-1);
SetFocus(GetDlgItem(hdlg,IDC_EDIT1));
}
break;
case WMX_MAIN_DIALOG_UP:
//
// If the CreateLocalSource option is FALSE at this point,
// it means that the user must have specified /O or /OX.
// Therefore, we can skip the inspection phase.
//
if(CreateLocalSource) {
//
// Inspect hard disks, etc.
// Return code tells us whether to continue.
//
if(ActionWithBillboard(ThreadInspectComputer,IDS_INSPECTING_COMPUTER,hdlg)) {
//
// We're ok so far. If the user specified unattended operation,
// post ourselves a message that causes us to behave as if the user
// clicked OK.
//
if(UnattendedOperation) {
PostMessage(
hdlg,
WM_COMMAND,
(WPARAM)MAKELONG(IDOK,BN_CLICKED),
(LPARAM)GetDlgItem(hdlg,IDOK)
);
}
} else {
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
}
}
break;
case WMX_INF_LOADED:
//
// The inf file is loaded. Now determine the local source
// drive/directory (if we are supposed to copy to a local
// source directory).
//
if(!CreateLocalSource) {
PostMessage(hdlg, WMX_I_AM_DONE, 0, 1);
} else {
if(CmdLineLocalSourceDrive) {
//
// See whether the specified drive has enough space on it.
//
if(DriveFreeSpace[CmdLineLocalSourceDrive-TEXT('C')] < (ULONGLONG)RequiredSpace) {
MessageBoxFromMessage(
hdlg,
MSG_BAD_CMD_LINE_LOCAL_SOURCE,
IDS_ERROR,
MB_OK | MB_ICONSTOP,
CmdLineLocalSourceDrive,
(RequiredSpace / (1024*1024)) + 1
);
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
break;
} else {
LocalSourceDrive = CmdLineLocalSourceDrive;
}
} else {
LocalSourceDrive = GetFirstDriveWithSpace(RequiredSpace);
if(!LocalSourceDrive) {
//
// No drive with enough free space.
//
MessageBoxFromMessage(
hdlg,
MSG_NO_DRIVES_FOR_LOCAL_SOURCE,
IDS_ERROR,
MB_OK | MB_ICONSTOP,
(RequiredSpace / (1024*1024)) + 1
);
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
break;
}
}
//
// Form full path.
//
LocalSourcePath = MALLOC((lstrlen(LocalSourceDirectory) + 3) * sizeof(TCHAR));
LocalSourcePath[0] = LocalSourceDrive;
LocalSourcePath[1] = TEXT(':');
lstrcpy(LocalSourcePath+2,LocalSourceDirectory);
LocalSourceSubPath = MALLOC((lstrlen(LocalSourcePath)+lstrlen(PlatformSpecificDir)+2)*sizeof(TCHAR));
lstrcpy(LocalSourceSubPath,LocalSourcePath);
DnConcatenatePaths(LocalSourceSubPath,PlatformSpecificDir,(DWORD)(-1));
if(DnCreateLocalSourceDirectories(hdlg)) {
PostMessage(hdlg,WMX_I_AM_DONE,0,1);
} else {
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
}
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDOK:
#ifdef _X86_
if(CreateFloppies && !FloppylessOperation && !AColonIsAcceptable) {
MessageBoxFromMessage(
hdlg,
MSG_BOGUS_A_COLON_DRIVE,
IDS_ERROR,
MB_OK | MB_ICONSTOP
);
PostMessage(hdlg, WMX_I_AM_DONE, 0, 0);
break;
}
#endif
//
// Check the local source drive (if applicable).
//
if(CreateLocalSource) {
//
// We first check to see if the system partition is an FT set (ie,
// mirrored partition). If so, then we tell the user that they
// must first break the mirror before installing.
//
if(!IsDriveNotNTFT(SystemPartitionDrive)) {
#ifdef _X86_
i = 1;
#else
PWSTR p;
for(i=0, p=SystemPartitionDriveLetters; *p; i++, p++);
#endif
if(i < 2) {
//
// Then the user has no choice at this point but
// to exit and break the mirror.
//
MessageBoxFromMessage(hdlg,
MSG_SYSPART_NTFT_SINGLE,
IDS_ERROR,
MB_OK | MB_ICONSTOP
);
PostMessage(hdlg, WMX_I_AM_DONE, 0, 0);
break;
}
#ifndef _X86_
else {
//
// (only possible on ARC machines) Since the
// user has several system partitions to choose from,
// give them the option to change at this point.
//
res = DialogBox(
hInst,
MAKEINTRESOURCE(IDD_SYSPART_NTFT),
NULL,
DlgProcSysPartNtftWarn
);
PostMessage(hdlg, WM_COMMAND, res, 0);
break;
}
#endif
}
//
// Check to see that we have the defined minimum amount of space on the
// system partition, and warn the user if we don't
//
if(DriveFreeSpace[SystemPartitionDrive-TEXT('C')] < MIN_SYSPART_SPACE) {
#ifdef _X86_
res = DialogBox(
hInst,
MAKEINTRESOURCE(IDD_SYSPART_LOW_X86),
NULL,
DlgProcSysPartSpaceWarn,
);
if(res != IDOK) {
PostMessage(hdlg, WM_COMMAND, res, 0);
break;
}
#else
PWSTR p;
for(i=0, p=SystemPartitionDriveLetters; *p; i++, p++);
res = DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_SYSPART_LOW),
NULL,
DlgProcSysPartSpaceWarn,
(LPARAM)i
);
if(res != IDC_CONTINUE) {
PostMessage(hdlg, WM_COMMAND, res, 0);
break;
}
#endif
}
}
if(SourceCount == 1) {
TCHAR Buffer[MAX_PATH];
GetDlgItemText(hdlg,IDC_EDIT1,Buffer,SIZECHARS(Buffer));
FREE(Sources[0]);
Sources[0] = DupString(Buffer);
}
//
// Try to load the inf file.
//
if((i = ActionWithBillboard(ThreadLoadInf,IDS_LOADING_INF,hdlg)) == -1) {
//
// We hit an exception, so terminate the app
//
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
} else if(i) {
//
// The inf file loaded successfully.
// Change dialog caption to product-specific version
// and post ourselves a message to continue.
//
PTSTR p = MyLoadString(AppTitleStringId);
SetWindowText(hdlg,p);
FREE(p);
PostMessage(hdlg,WMX_INF_LOADED,0,0);
} else {
SendMessage(hdlg,WMX_INITCTLS,0,0);
}
break;
case IDCANCEL:
PostMessage(hdlg,WMX_I_AM_DONE,0,0);
break;
case ID_HELP:
MyWinHelp(hdlg,IDD_START);
break;
case IDC_OPTIONS:
DialogBoxParam(
hInst,
#ifdef _X86_
MAKEINTRESOURCE(IDD_OPTIONS_1),
#else
MAKEINTRESOURCE(IDD_OPTIONS_2),
#endif
hdlg,
DlgProcOptions,
0
);
break;
default:
return(FALSE);
}
break;
case WM_PAINT:
{
HBITMAP hbm;
HDC hdc,hdcMem;
PAINTSTRUCT ps;
hdc = BeginPaint(hdlg,&ps);
if(hdcMem = CreateCompatibleDC(hdc)) {
if(hbm = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_WIN_BITMAP))) {
hbm = SelectObject(hdcMem,hbm);
BitBlt(hdc,35,15,98,83,hdcMem,0,0,SRCCOPY);
//StretchBlt(hdc,5,10,3*68/2,3*78/2,hdcMem,0,0,68,78,SRCCOPY);
DeleteObject(SelectObject(hdcMem,hbm));
DeleteDC(hdcMem);
}
}
EndPaint(hdlg, &ps);
}
break;
case WM_QUERYDRAGICON:
return((BOOL)MainIcon);
case WMX_I_AM_DONE:
WinHelp(hdlg,NULL,HELP_QUIT,0);
EndDialog(hdlg,lParam);
break;
default:
return(FALSE);
}
return(TRUE);
}
VOID
RememberSource(
IN PWSTR Source
)
{
PWSTR source;
UINT u;
source = DupString(Source);
//
// If the source is already in the list, nothing to do.
//
for(u=0; u<SourceCount; u++) {
if(!lstrcmpi(source,Sources[u])) {
FREE(source);
return;
}
}
//
// Not already in there -- add it.
//
if(SourceCount < MAX_SOURCES) {
Sources[SourceCount++] = source;
}
}
BOOL
RememberOptionalDir(
IN PWSTR Dir,
IN UINT Flags
)
{
UINT u;
for(u=0; u<OptionalDirCount; u++) {
if(!lstrcmpi(OptionalDirs[u],Dir)) {
OptionalDirFlags[OptionalDirCount] = Flags;
return(TRUE);
}
}
//
// Not already in there.
//
if(OptionalDirCount < MAX_OPTIONALDIRS) {
OptionalDirs[OptionalDirCount] = Dir;
OptionalDirFlags[OptionalDirCount] = Flags;
OptionalDirCount++;
return(TRUE);
}
return(FALSE);
}
BOOLEAN
RememberOemBootFile(
IN PTSTR File
)
{
ULONG u;
for (u = 0; u < OemBootFilesCount; u++) {
if(!lstrcmpi(OemBootFiles[u],File)) {
return (TRUE);
}
}
//
// Not already in there
//
if (OemBootFilesCount < MAX_OEMBOOTFILES) {
OemBootFiles[OemBootFilesCount] = File;
OemBootFilesCount++;
return (TRUE);
}
return (FALSE);
}
BOOL
DnFetchArguments(
VOID
)
{
PTSTR WinntSetupP = WINNT_SETUPPARAMS;
PTSTR WinntYes = WINNT_A_YES;
PTSTR WinntNo = WINNT_A_NO;
PTSTR WinntUnattended = WINNT_UNATTENDED;
PTSTR WinntOemPreinstall = WINNT_OEMPREINSTALL;
TCHAR Buffer[MAX_PATH];
BOOL b = TRUE;
WIN32_FIND_DATA FindData;
HANDLE FindHandle;
//
// Validate presence of file.
//
FindHandle = FindFirstFile(UnattendedScriptFile,&FindData);
if(FindHandle == INVALID_HANDLE_VALUE) {
MessageBoxFromMessage(NULL,MSG_INF_READ_ERR,IDS_ERROR,MB_OK|MB_ICONSTOP,UnattendedScriptFile);
return(FALSE);
}
FindClose(FindHandle);
//
// Find out if this is an OEM preinstall
//
if( GetPrivateProfileString( WinntUnattended,
WinntOemPreinstall,
WinntNo,
Buffer,
sizeof(Buffer)/sizeof(TCHAR),
UnattendedScriptFile ) == 0 ) {
lstrcpy( Buffer, WinntNo );
}
if( lstrcmpi( Buffer,WinntYes) == 0 ){
//
// This is an OEM pre-install
//
OemPreInstall = TRUE;
} else {
//
// Assume this is not an OEM pre-install
//
OemPreInstall = FALSE;
}
if( OemPreInstall ) {
#ifdef _X86_
TCHAR *p;
DWORD ec;
PVOID UnattendedInfHandle;
ULONG i;
#endif // _X86_
//
// Always add to the list of optional directories the directory
// $OEM$
//
RememberOptionalDir(OemSystemDirectory, OPTDIR_OEMSYS);
#ifdef _X86_
switch(ec = DnInitINFBuffer(UnattendedScriptFile,&UnattendedInfHandle)) {
case NO_ERROR:
b = TRUE;
break;
case ERROR_READ_FAULT:
b = FALSE;
MessageBoxFromMessage(NULL,MSG_INF_READ_ERR,IDS_ERROR,MB_OK|MB_ICONSTOP,UnattendedScriptFile);
break;
case ERROR_INVALID_DATA:
b = FALSE;
MessageBoxFromMessage(NULL,MSG_INF_LOAD_ERR,IDS_ERROR,MB_OK|MB_ICONSTOP,UnattendedScriptFile);
break;
case ERROR_FILE_NOT_FOUND:
default:
b = FALSE;
MessageBoxFromMessage(NULL,MSG_INF_NOT_THERE,IDS_ERROR,MB_OK|MB_ICONSTOP);
break;
}
if( b ) {
for(i=0;
p = DnGetSectionLineIndex(UnattendedInfHandle,
WINNT_OEMBOOTFILES,
i,
0);
i++) {
RememberOemBootFile(p);
}
}
#endif // _X86_
}
return(b);
}
BOOL
DnpParseArguments(
VOID
)
/*++
Routine Description:
Parse arguments passed to the program. Perform syntactic validation
and fill in defaults where necessary.
Valid arguments:
/s:sharepoint[path] - specify source sharepoint and path on it
/i:filename - specify name of inf file
/t:driveletter - specify local source drive
If _X86_ flag is set:
/x - suppress creation of the floppies altogether
/b - floppyless operation
/o[x] - only create the boot floppies (if 'ox', then
make retail boot floppies (i.e., minus
winnt.sif on disk #2)
Undocumented arguments:
/n[x[:<filename>]] - don't give error popup for each missing file
/nx tells text setup to ignore missing files also,
and causes list of missing files to be written
to c:\missingf.lst. /nx:<filename> allows override
of filename for list.
/u[<x>][:<scriptname>] - unattended mode operation
<x> is an integer specifying a forced shutdown
after <x> seconds have expired.
<scriptname> is optional script file to use
/#:sharename - pull a build from the build servers,
/r[x]:<dir> - install optional directory <dir>
x present means don't copy to target tree
(but to local src only)
/e:<cmdline> - execute specified command at end of gui setup
Arguments:
None. Arguments are retreived via GetCommandLine().
Return Value:
None.
--*/
{
WCHAR **argv;
int argc;
PWCHAR arg;
WCHAR swit;
PWCHAR restofswit;
PWCHAR numend;
PWCHAR ArgSwitches[] = { L"E",L"I",L"LP",L"RX",L"R",L"S",L"T",L"#",NULL };
unsigned i,l;
PWSTR p;
//
// Parse our own command line.
//
argv = CommandLineToArgvW(GetCommandLine(),&argc);
if(!argv) {
return(FALSE);
}
//
// Skip program name
//
argv++;
while(--argc) {
if((**argv == L'-') || (**argv == L'/')) {
swit = (WCHAR)CharUpper((PWSTR)argv[0][1]);
//
// Process switches that take no arguments here.
//
switch(swit) {
case L'?':
return(FALSE); // force usage
#ifdef _X86_
case L'B':
argv++;
FloppylessOperation = TRUE;
FloppyOption = StandardInstall;
continue;
case L'O':
FloppyOption = OnlyWinntFloppies;
if((argv[0][2] == L'x') || (argv[0][2] == L'X')) {
FloppyOption = OnlyRetailFloppies;
} else {
//
// Don't allow /o by itself any more. /O* is a hidden
// switch that replaces that functionality.
//
if(argv[0][2] != L'*') {
return(FALSE);
}
}
CreateFloppies = TRUE;
FloppylessOperation = FALSE;
CreateLocalSource = FALSE;
continue;
case L'X':
argv++;
CreateFloppies = FALSE;
FloppyOption = StandardInstall;
continue;
#endif
case L'N':
switch(argv[0][2]) {
case 0:
break;
case L'x':
case L'X':
SpecialNotPresentFilesMode = TRUE;
if((argv[0][3] == L':') && argv[0][4]) {
MissingFileListName = &argv[0][4];
}
break;
default:
return(FALSE);
}
argv++;
SkipNotPresentFiles = TRUE;
continue;
case L'U':
if(((WCHAR)CharUpper((PWSTR)argv[0][2]) == L'D') && ((WCHAR)CharUpper((PWSTR)argv[0][3]) == L'F')) {
if((argv[0][4] == L':') && argv[0][5]) {
if((p = wcschr(&argv[0][5],L',')) == NULL) {
p = wcschr(&argv[0][5],0);
}
l = p - &argv[0][5];
UniquenessId = MALLOC((l + 2) * sizeof(WCHAR));
CopyMemory(UniquenessId,&argv[0][5],l*sizeof(WCHAR));
UniquenessId[l] = 0;
if(*p++) {
if(*p) {
//
// Now the rest of the param is the filename of the uniqueness database.
//
UniquenessDatabaseFile = DupString(p);
UniquenessId[l] = L'*';
UniquenessId[l+1] = 0;
} else {
return(FALSE);
}
}
} else {
return(FALSE);
}
} else {
UnattendedOperation = TRUE;
//
// check for <x> seconds modifier
//
UnattendedShutdownTimeout = StringToDwordX(&argv[0][2],&numend);
if(UnattendedShutdownTimeout == (unsigned long)(-1)) {
UnattendedShutdownTimeout = 0;
}
//
// User can also specify script file
//
if(*numend == L':') {
numend++;
if(*numend == 0) {
return(FALSE);
}
//
// Check if user specified a path to the unattended
// script file, or just the name of the file.
// If the user specified just the name of the file
// then we need to prepend the path to the current
// directory. Otherwise, GetPrivateProfile APIs will
// look for the unattended script file in the Windows
// directory, instead of the current directory.
//
if( (wcschr( numend, (WCHAR)':' ) != NULL) ||
(wcschr( numend, (WCHAR)'\\') != NULL) ) {
//
// An absolute or relative path was specified.
// Save whatever the user provided.
//
UnattendedScriptFile = DupString(numend);
} else {
//
// Only a filename was provided.
// Prepend to the filename, the path to the
// current directory, and save the full path.
//
WCHAR AuxBuffer[ MAX_PATH + 1 ];
GetCurrentDirectory( sizeof(AuxBuffer)/sizeof(WCHAR),
AuxBuffer );
DnConcatenatePaths( AuxBuffer,
numend,
sizeof(AuxBuffer)/sizeof(WCHAR) );
UnattendedScriptFile = DupString(AuxBuffer);
}
}
}
argv++;
continue;
}
//
// Process switches that take arguments here.
// First validate the switch and figure out where the
// argument part starts.
//
for(i=0; ArgSwitches[i]; i++) {
l = lstrlen(ArgSwitches[i]);
p = DupString(&argv[0][1]);
p[l] = 0;
CharUpper(p);
if(!memcmp(ArgSwitches[i],p,l*sizeof(WCHAR))) {
//
// Next char of arg must be either : or nul
// If it's : then arg immediately follows.
// If it's nul then arg is next argument
//
if(argv[0][1+l] == L':') {
arg = &argv[0][2+l];
if(*arg == 0) {
FREE(p);
return(FALSE);
}
restofswit = &argv[0][2];
break;
} else {
if(argv[0][1+l] == 0) {
if(argc <= 1) {
FREE(p);
return(FALSE);
}
restofswit = &argv[0][2];
argc--;
arg = argv[1];
argv++;
break;
} else {
NOTHING;
}
}
}
FREE(p);
}
//
// Check termination condition.
//
if(!ArgSwitches[i]) {
return(FALSE);
}
switch(swit) {
case L'E':
if(CmdToExecuteAtEndOfGui) {
return(FALSE);
} else {
CmdToExecuteAtEndOfGui = DupString(arg);
}
break;
case L'I':
if(InfName) {
return(FALSE);
} else {
InfName = DupString(arg);
}
break;
case L'L':
NumberOfLicensedProcessors = DupString(arg);
break;
case L'R':
RememberOptionalDir(
DupString(arg),
((WCHAR)CharUpper((PWSTR)restofswit[0]) == L'X') ? OPTDIR_TEMPONLY : 0
);
break;
case L'S':
//
// Remember the source.
//
RememberSource(arg);
break;
case L'T':
if(CmdLineLocalSourceDrive) {
return(FALSE);
} else {
CmdLineLocalSourceDrive = (WCHAR)CharUpper((PWSTR)*arg);
}
break;
case L'#':
//
// arg is the name of the sharepoint on the build servers,
// such as ntcdfree.1042. Append it to each server name
// to form the set of sources.
//
{
WCHAR ShareName[MAX_PATH];
UINT u;
for(u=0; u<BuildServerCount; u++) {
wsprintf(ShareName,L"%s\\%s",BuildServerList[u],arg);
RememberSource(ShareName);
}
}
break;
default:
return(FALSE);
}
} else {
return(FALSE);
}
argv++;
}
#ifdef _X86_
//
// Turn on floppyless oepration if unattended operation was specified.
//
if(UnattendedOperation) {
FloppylessOperation = TRUE;
FloppyOption = StandardInstall;
CreateLocalSource = TRUE;
}
if(FloppylessOperation) {
CreateFloppies = FALSE;
}
#endif
return(TRUE);
}
int
_stdcall
ModuleEntry(
VOID
)
{
int i;
BOOL b;
HMODULE hKernel32DLL;
GETVEREXPROC pGetVersionExProc;
HANDLE mutex;
TlsIndex = TlsAlloc();
hInst = GetModuleHandle(NULL);
//
// Only let one of this guy run.
//
mutex = CreateMutex(NULL,FALSE,TEXT("Winnt32 Is Running"));
if(mutex == NULL) {
//
// An error (like out of memory) has occurred.
// Bail now.
//
ExitProcess(0);
}
//
// Make sure we are the only process with a handle to our named mutex.
//
if(GetLastError() == ERROR_ALREADY_EXISTS) {
CloseHandle(mutex);
MessageBoxFromMessage(
NULL,
MSG_ALREADY_RUNNING,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION
);
ExitProcess(0);
}
//
// This code has multiple returns from within the try body.
// This is usually not a good idea but here we only return
// in the error case so we won't worry about it.
//
try {
try {
hKernel32DLL = GetModuleHandle(TEXT("KERNEL32"));
if(!hKernel32DLL) {
return(0);
}
//
// Lock the application in memory.
// This is necessary, so that winnnt32 will be to display an error message
// when the network connection is lost, and winnt32 was run from across
// the net. If winnt32 is not locked in memory and such error occurs, winnnt32
// will silently terminate, and the user might think that winnt32 completed
// successfully.
//
LockApplicationInMemory();
//
// Do not run on Chicago. Those guys have not implemented
// proper DASD volume support so there's no way we can write
// an NT boot sector on Chicago either on C: or on floppy.
//
if(pGetVersionExProc = (GETVEREXPROC)GetProcAddress(hKernel32DLL, GetVersionExName)) {
OSVERSIONINFO OsVersionInfo;
OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
if(!pGetVersionExProc(&OsVersionInfo) ||
(OsVersionInfo.dwPlatformId < VER_PLATFORM_WIN32_NT)) {
MessageBoxFromMessage(
NULL,
MSG_NOT_WINDOWS_NT,
AppTitleStringId,
MB_OK | MB_ICONSTOP
);
return(0);
}
}
//
// Ensure that the user has privilege/access to run this app.
//
if(!IsUserAdmin()
|| !DoesUserHavePrivilege(SE_SHUTDOWN_NAME)
|| !DoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) {
MessageBoxFromMessage(
NULL,
MSG_NOT_ADMIN,
AppTitleStringId,
MB_OK | MB_ICONSTOP
);
return(0);
}
//
// Check arguments.
//
if(!DnpParseArguments()) {
MyWinHelp(NULL,400);
return(0);
} else {
if(UnattendedOperation) {
if( UnattendedScriptFile ) {
if( !DnFetchArguments() ) {
return(0);
}
}
}
}
#ifdef _X86_
//
// Disallow installing/upgrading on a 386.
//
{
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
if(SysInfo.dwProcessorType == PROCESSOR_INTEL_386) {
MessageBoxFromMessage(
NULL,
MSG_REQUIRES_486,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION
);
return(0);
}
}
#endif
//
// If the user didn't specify a remote source, default to the
// path from which we were run.
//
if(!SourceCount) {
TCHAR Buffer[MAX_PATH];
PTSTR p;
if(GetModuleFileName(NULL,Buffer,SIZECHARS(Buffer))) {
if(p = StringRevChar(Buffer,TEXT('\\'))) {
*p = 0;
}
} else {
GetCurrentDirectory(SIZECHARS(Buffer),Buffer);
}
Sources[0] = DupString(Buffer);
SourceCount = 1;
}
//
// If the user didn't specify an inf name, use the default.
//
if(!InfName) {
InfName = DupString(DEFAULT_INF_NAME);
}
//
// Load the main icon.
//
MainIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_MAIN_ICON));
SetErrorMode(SEM_FAILCRITICALERRORS);
//
// Create the main dialog and off we go.
//
i = DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_START),
NULL,
DlgProcMain,
0
);
if(i) {
//
// Directories have been created. Start file copy.
//
//
// Register Status Gauge window class
//
i = InitStatGaugeCtl(hInst);
if(i) {
i = DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_COPYING),
NULL,
DlgProcCopyingFiles,
0
);
}
}
if(i) {
//
// We're done. Put up a dialog indicating such, and
// let the user either restart or return to NT.
//
if(!CreateLocalSource) {
//
// If we didn't create a local source directory, then simply
// exit at this point.
//
b = FALSE;
} else {
if (NumberOfLicensedProcessors != NULL) {
WCHAR SourceName[ MAX_PATH ];
WCHAR DestinationName[ MAX_PATH ];
wsprintf(SourceName, L"%s\\idw\\setup\\setup%sp.hiv", Sources[0], NumberOfLicensedProcessors);
lstrcpy(DestinationName, LocalSourceSubPath);
lstrcat(DestinationName, L"\\setupreg.hiv");
CopyFile(SourceName, DestinationName, FALSE);
#ifdef _X86_
wsprintf(DestinationName, TEXT("%c:%s\\setupreg.hiv"), SystemPartitionDrive, FloppylessBootDirectory );
CopyFile(SourceName, DestinationName, FALSE);
#endif
}
if(UnattendedOperation) {
b = TRUE;
} else {
b = DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_ASKREBOOT),
NULL,
DlgProcAskReboot,
0
);
}
}
if(b) {
VOID StopNwcWorkstation(VOID);
PTSTR p = RetreiveAndFormatMessage(MSG_REBOOTING);
//
// Initiate system shutdown.
//
StopNwcWorkstation();
if(!EnablePrivilege(SE_SHUTDOWN_NAME, TRUE) ||
!InitiateSystemShutdown(
NULL,
p,
UnattendedShutdownTimeout,
(BOOL)UnattendedShutdownTimeout,
TRUE
)
)
{
MessageBoxFromMessage(
NULL,
MSG_REBOOT_FAIL,
AppTitleStringId,
MB_OK | MB_ICONSTOP
);
}
FREE(p);
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
MessageBoxFromMessage(
NULL,
MSG_GENERIC_EXCEPTION,
AppTitleStringId,
MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND,
GetExceptionCode()
);
}
} finally {
//
// Destroy the mutex.
//
CloseHandle(mutex);
}
ExitProcess(0);
}
VOID
LockApplicationInMemory(
VOID
)
/*++
Routine Description:
This app is an extremely likely candidate for being run over the net.
If a net burp occurs this can result in the system not being able
to page in parts of the apps's code or other read only sections such
as resources. So this routine locks down the .text and .rsrc sections
(more exactly, it locks down the range specified in the image header
as the code base/size, and the range specified as the resource directory).
Arguments:
None.
Return Value:
None. Errors are ignored since there's not much the user can do about it
and things will probably work OK anyway.
--*/
{
PIMAGE_OPTIONAL_HEADER ImageOptionalHeader;
PVOID Base;
DWORD Size;
try {
ImageOptionalHeader = &RtlImageNtHeader(hInst)->OptionalHeader;
//
// Determine the base address and size of the code.
// This assumes that there is only one code section.
// Lock it down.
//
Base = (PUCHAR)hInst + ImageOptionalHeader->BaseOfCode;
Size = ImageOptionalHeader->SizeOfCode;
VirtualLock(Base,Size);
//
// Determine the base address and size of the resource section.
// Lock it down.
//
Base = (PUCHAR)hInst + ImageOptionalHeader->DataDirectory[2].VirtualAddress;
Size = ImageOptionalHeader->DataDirectory[2].Size;
VirtualLock(Base,Size);
} except(EXCEPTION_EXECUTE_HANDLER) {
NOTHING;
}
}