#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' switch may be specified to force a shutdown after // 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 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]] - 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: allows override of filename for list. /u[][:] - unattended mode operation is an integer specifying a forced shutdown after seconds have expired. is optional script file to use /#:sharename - pull a build from the build servers, /r[x]: - install optional directory x present means don't copy to target tree (but to local src only) /e: - 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 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; uOptionalHeader; // // 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; } }