/*++ Copyright (c) 1996 Microsoft Corporation Module Name: Params.c Abstract: Routines to write parameters file for use by text mode setup. Author: Ted Miller (tedm) 4 Nov 1996 Revision History: --*/ #include "precomp.h" #pragma hdrstop #define DEF_INF_BUFFER_SIZE (1<<15) //32KB #define EMPTY_STRING TEXT("") // Global used in WriteParamsFile and AddExternalParams TCHAR ActualParamFile[MAX_PATH] = {'\0'}; // // boot loader timeout value, in string form // TCHAR Timeout[32]; #ifdef PRERELEASE // // if we're in PRERELEASE mode, we will make a /debug entry // in the OSLOADOPTIONSVARAPPEND entry. // BOOL AppendDebugDataToBoot = TRUE; #endif #if defined(UNICODE) && defined(_X86_) extern TCHAR g_MigDllAnswerFilePath[MAX_PATH]; #endif DWORD PatchWinntSifFile( IN LPCTSTR Filename ); BOOL AppendParamsFile( IN HWND ParentWindow, IN LPCTSTR ParametersFileIn, IN LPCTSTR ParametersFileOut ); BOOL WriteCompatibilityData( IN LPCTSTR FileName ); VOID WriteGUIModeInfOperations( IN LPCTSTR FileName ); BOOL AddGUIModeCompatibilityInfsToCopyList(); BOOL WriteTextmodeClobberData ( IN LPCTSTR FileName ); VOID SaveProxyForOobe( IN LPCTSTR FileName ); #if defined(_X86_) VOID SaveDriveLetterInformation ( IN LPCTSTR FileName ); #endif PCTSTR pGetPfPath ( IN HKEY hKey, IN PCTSTR ValueName ) { DWORD Size; LONG rc; PBYTE Data; DWORD Type; UINT DriveType; TCHAR RootPath[] = TEXT("?:\\"); PTSTR QuotedData; rc = RegQueryValueEx ( hKey, ValueName, NULL, // lpReserved &Type, NULL, &Size ); if (rc != ERROR_SUCCESS) { return NULL; } if (Type != REG_SZ && Type != REG_EXPAND_SZ) { return NULL; } Data = MALLOC(Size + sizeof (TCHAR)); if (!Data) { return NULL; } rc = RegQueryValueEx ( hKey, ValueName, NULL, // lpReserved NULL, // type Data, &Size ); if (rc != ERROR_SUCCESS) { FREE(Data); return NULL; } *((PTSTR) (Data + Size)) = 0; // // Verify data is to a local path // RootPath[0] = *((PCTSTR) Data); if (RootPath[0] == TEXT('\\')) { DriveType = DRIVE_NO_ROOT_DIR; } else { DriveType = GetDriveType (RootPath); } if (DriveType != DRIVE_FIXED) { FREE(Data); return NULL; } QuotedData = (PTSTR) MALLOC(Size + sizeof (TCHAR) * 3); if (!QuotedData) { FREE(Data); return NULL; } *QuotedData = TEXT('\"'); lstrcpy (QuotedData + 1, (PCTSTR) Data); lstrcat (QuotedData, TEXT("\"")); FREE(Data); return (PCTSTR) QuotedData; } BOOL WriteHeadlessParameters( IN LPCTSTR FileName ) /*++ Routine Description: This routine writes the headless-specific parameters into the file that is used to pass information to text mode setup. Arguments: FileName - specifies the full Win32 filename to use for the file. Return Value: Boolean value indicating whether the file was written successfully. If not, the user will have been informed about why. --*/ { BOOL ReturnVal = TRUE; // // ISSUE - why MAX_PATH*2 ? // TCHAR Text[MAX_PATH*2]; // // Check the global and see if anyone has set any headless parameters. // if( HeadlessSelection[0] != TEXT('\0') ) { // // Write the settings into the unattend file so textmode will // fire up through up a headless port. // if( !WritePrivateProfileString(WINNT_DATA,WINNT_U_HEADLESS_REDIRECT,HeadlessSelection,FileName)) { ReturnVal = FALSE; } if( HeadlessBaudRate == 0 ) { wsprintf( Text, TEXT("%d"), 9600 ); } else { wsprintf( Text, TEXT("%d"), HeadlessBaudRate ); } if( !WritePrivateProfileString(WINNT_DATA,WINNT_U_HEADLESS_REDIRECTBAUDRATE,Text,FileName)) { ReturnVal = FALSE; } } return( ReturnVal ); } BOOL WritePidToParametersFile(LPCTSTR Section, LPCTSTR Key, LPCTSTR FileName) { BOOL b = FALSE; LPTSTR Line = NULL; LPTSTR pid; if (g_EncryptedPID) { pid = g_EncryptedPID; } else { pid = ProductId; } Line = GlobalAlloc(GPTR, (lstrlen(pid) + 3) * sizeof(TCHAR)); if (Line) { *Line = TEXT('\"'); lstrcpy(&Line[1], pid); lstrcat(Line,TEXT("\"")); b = WritePrivateProfileString(Section,Key,Line,FileName); GlobalFree(Line); } return b; } BOOL MigrateUnattendDataEntries( IN LPCTSTR FileName, IN LPTSTR UnattendedScriptFile ) /*++ Routine Description: This routine writes out the keys under [Data] section of an unattend file in to the winnt.sif file. This routine is specific to the following keys AutoPartition and UseBIOSToBoot Arguments: FileName - specifies the full Win32 filename to use for the file. UnattendedScriptFile - Unattend Script File. Return Value: TRUE/FALSE --*/ { BOOL ReturnVal = FALSE; // // If Unattend file exists then migrate the keys under [Data] section. // if (UnattendedScriptFile){ CONST ULONG BufSize = 256; PTSTR TmpString = (PTSTR)MALLOC(BufSize * sizeof (TCHAR)); ReturnVal = TRUE; if( NULL != TmpString){ // // Array of keys to be checked // LPCTSTR KeysToBeMigrated[] = { WINNT_D_AUTO_PART, WINNT_D_BIOSTOBOOT }; LPCTSTR WinntDataSection = WINNT_DATA; ULONG i = 0; for(i=0; i < ARRAYSIZE(KeysToBeMigrated); i++){ if(GetPrivateProfileString(WinntDataSection, KeysToBeMigrated[i], EMPTY_STRING, TmpString, BufSize, UnattendedScriptFile)){ if (!WritePrivateProfileString( WinntDataSection, KeysToBeMigrated[i], TmpString, FileName)) { DWORD LastError = GetLastError(); DebugLog ( Winnt32LogError, TEXT("MigrateUnattendDatEntries : Error writing to file %1, Section: %2, Key: %3"), 0, FileName, WinntDataSection, KeysToBeMigrated[i]); ReturnVal = FALSE; SetLastError(LastError); } } } FREE(TmpString); }else{ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ReturnVal = FALSE; } } SetLastError(ERROR_INVALID_PARAMETER); return ReturnVal; } BOOL DoWriteParametersFile( IN HWND ParentWindow, IN LPCTSTR FileName ) /*++ Routine Description: This routine generates a parameters file that is used to pass information to text mode setup. Arguments: ParentWindow - supplies window handle of window to be used as the parent/owner in case this routine puts up UI. FileName - specifies the full Win32 filename to use for the file. Return Value: Boolean value indicating whether the file was written successfully. If not, the user will have been informed about why. --*/ { TCHAR FullPath[MAX_PATH], *t; TCHAR Text[MAX_PATH*2]; LPTSTR OptionalDirString,OptDir; UINT OptionalDirLength; DWORD d=NO_ERROR; PVOID p; BOOL b; LONG l; HKEY hKey; PCTSTR PfPath; LONG rc; LPCTSTR WinntDataSection = WINNT_DATA; LPCTSTR WinntSetupSection = WINNT_SETUPPARAMS; LPCTSTR WinntAccessSection = WINNT_ACCESSIBILITY; LPCTSTR WinntSetupDataSection = TEXT("SetupData"); #if defined(REMOTE_BOOT) LPCTSTR WinntUserDataSection = TEXT("UserData"); #endif // defined(REMOTE_BOOT) LPCTSTR WinntUniqueId = WINNT_D_UNIQUEID; LPCTSTR WinntNull = WINNT_A_NULL; LPCTSTR WinntUserSection = WINNT_USERDATA; if( !FileName ) d=ERROR_INVALID_PARAMETER; // // Make sure path for file is present, and form its fully qualified name. // if(d == NO_ERROR){ StringCchCopy(FullPath, ARRAYSIZE(FullPath), FileName); if((t=_tcsrchr(FullPath,TEXT('\\')))) { *t= 0; d = CreateMultiLevelDirectory(FullPath); }else d=ERROR_INVALID_PARAMETER; } if(d != NO_ERROR) { MessageBoxFromMessageAndSystemError( ParentWindow, MSG_DIR_CREATE_FAILED, d, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, FullPath ); return(FALSE); } // // Get rid of any existing parameters file. // DeleteFile(FileName); #ifdef _X86_ if (!ISNT()) { // // If this is a 9x machine, we need to preserve the drive letters, even // if it is an NT clean install. // SaveDriveLetterInformation (FileName); } #endif // // Value indicating that this is winnt/winnt32-based installation, // and on amd64/x86, value to indicate that this is a floppyless operation // as apropriate. // b = WritePrivateProfileString(WinntDataSection,WINNT_D_MSDOS,TEXT("1"),FileName); if (b && HideWinDir) { b = WritePrivateProfileString(WinntDataSection,TEXT("HideWinDir"),TEXT("1"),FileName); } if (!IsArc()) { #if defined(_AMD64_) || defined(_X86_) if(b && Floppyless) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_FLOPPY,TEXT("1"),FileName); } if (b && BuildCmdcons) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_CMDCONS,TEXT("1"),FileName); } #endif // defined(_AMD64_) || defined(_X86_) } // if (!IsArc()) if(b && RunFromCD && !MakeLocalSource) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_LOCALSRC_CD,TEXT("1"),FileName); } if (b) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_AUTO_PART,ChoosePartition?TEXT("0"):TEXT("1"),FileName); } if (b && UseSignatures) { b = WritePrivateProfileString(WinntDataSection,TEXT("UseSignatures"),WINNT_A_YES,FileName); } if (b && InstallDir[0] && (ISNT() || !Upgrade)) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_INSTALLDIR,InstallDir,FileName); } if (b && EulaComplete) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_EULADONE,TEXT("1"),FileName); } if (b && NoLs && !MakeLocalSource) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_NOLS,TEXT("1"),FileName); } if (b && UseBIOSToBoot) { b = WritePrivateProfileString(WinntDataSection,TEXT("UseBIOSToBoot"),TEXT("1"),FileName); } if (b && WriteAcpiHalValue && Upgrade) { if (AcpiHalValue) { b = WritePrivateProfileString(WinntDataSection,TEXT("AcpiHAL"),TEXT("1"),FileName); } else { b = WritePrivateProfileString(WinntDataSection,TEXT("AcpiHAL"),TEXT("0"),FileName); } } if (b && IgnoreExceptionPackages) { b = WritePrivateProfileString(WinntDataSection,TEXT("IgnoreExceptionPackages"),TEXT("1"),FileName); } #ifdef PRERELEASE if (b && AppendDebugDataToBoot) { if (!AsrQuickTest) { b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVarAppend"),TEXT("/Debug"),FileName); } else { b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVarAppend"),TEXT("/Debug /Baudrate=115200"),FileName); } } #endif if (b && AsrQuickTest) { wsprintf(Text, TEXT("%d"), AsrQuickTest); b = WritePrivateProfileString(WinntDataSection,TEXT("AsrMode"),Text,FileName); } if (b && (RunningBVTs || AsrQuickTest)) { if (lDebugBaudRate == 1394) { // kd via 1394 lstrcpy(Text, TEXT("/debug /debugport=1394")); } else if (lDebugComPort == 0) { wsprintf(Text, TEXT("/debug /baudrate=%d"), lDebugBaudRate); } else { wsprintf(Text, TEXT("/debug /baudrate=%d /debugport=com%d"), lDebugBaudRate, lDebugComPort); } // write the string to OsLoadOptions so "textmode" setup to run under the debugger b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptions"),Text,FileName); if (b) { // write the string to OsLoadOptionsVar so guimode setup to run under the debugger b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVar"),Text,FileName); if (b) { // also run guimode's setup.exe under NTSD. The -isd switch is needed to ensure that setup.exe starts // without a global system manifest since winlogon spawns it with the CREATE_IGNORE_SYSTEM_DEFAULT flag, // and ntsd normall calls CreateProcess which would undo the above flag. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("SetupCmdlinePrepend"),TEXT("ntsd -isd -odgGx"),FileName); } } } if (b && Timeout[0]) { b = WritePrivateProfileString(WinntSetupDataSection,WINNT_S_OSLOADTIMEOUT,Timeout,FileName); } if(b) { // // Write upgrade stuff. WinntUpgrade and Win95Upgrade will both be set, // and at most one of them will be set to yes. // if(b = WritePrivateProfileString(WinntDataSection,WINNT_D_NTUPGRADE,WINNT_A_NO,FileName)) { b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN95UPGRADE,WINNT_A_NO,FileName); } if(b) { wsprintf(Text,TEXT("%x"),GetVersion()); b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_VER,Text,FileName); if(b && Upgrade) { b = WritePrivateProfileString( WinntDataSection, ISNT() ? WINNT_D_NTUPGRADE : WINNT_D_WIN95UPGRADE, WINNT_A_YES, FileName ); MyGetWindowsDirectory(Text,MAX_PATH); Text[2] = 0; b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_DRIVE,Text,FileName); if(b) { Text[2] = TEXT('\\'); b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_PATH,Text+2,FileName); } } } } // // Flags for Accessible Setup // AccessibleSetup = FALSE; if(!Upgrade) { if(b && AccessibleMagnifier) { b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_MAGNIFIER, TEXT("1"),FileName); AccessibleSetup = TRUE; } if(b && AccessibleReader) { b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_READER, TEXT("1"),FileName); AccessibleSetup = TRUE; } if(b && AccessibleKeyboard) { b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_KEYBOARD, TEXT("1"),FileName); AccessibleSetup = TRUE; } } if(b && AccessibleSetup && !UnattendedOperation) { UnattendedOperation = TRUE; UnattendedShutdownTimeout = 0; UnattendedScriptFile = MALLOC(MAX_PATH * sizeof(TCHAR)); b = (UnattendedScriptFile != NULL); if(b) { lstrcpy(UnattendedScriptFile,NativeSourcePaths[0]); ConcatenatePaths(UnattendedScriptFile,AccessibleScriptFile,MAX_PATH); } } if(!b) { goto c1; } // // Value indicating we're automatically and quietly skipping missing files. // if(AutoSkipMissingFiles) { b = WritePrivateProfileString(WinntSetupSection,WINNT_S_SKIPMISSING,TEXT("1"),FileName); if(!b) { goto c1; } } // // Command to be executed at end of GUI setup, if any. // if(CmdToExecuteAtEndOfGui) { b = WritePrivateProfileString( WinntSetupSection, WINNT_S_USEREXECUTE, CmdToExecuteAtEndOfGui, FileName ); if(!b) { goto c1; } } // // Ensure that Plug and Play state in upgraded os will be the same as the // original. Enables per-device settings to be preserved in the NT5+ // upgrade scenario. // if (ISNT() && (BuildNumber > NT40) && Upgrade) { LPTSTR buffer = NULL; if (MigrateDeviceInstanceData(&buffer)) { WritePrivateProfileSection(WINNT_DEVICEINSTANCES, buffer, FileName); // // Free the allocated buffer that was returned // LocalFree(buffer); buffer = NULL; } if (MigrateClassKeys(&buffer)) { WritePrivateProfileSection(WINNT_CLASSKEYS, buffer, FileName); // // Free the allocated buffer that was returned // LocalFree(buffer); buffer = NULL; } if (MigrateHashValues(&buffer)) { WritePrivateProfileSection(WINNT_DEVICEHASHVALUES, buffer, FileName); // // Free the allocated buffer that was returned // LocalFree(buffer); buffer = NULL; } } // // Remember udf info. If there's a database file, stick a * on the end // of the ID before writing it. // if(UniquenessId) { d = lstrlen(UniquenessId); if(d >= (MAX_PATH-1)) { d--; } lstrcpyn(Text,UniquenessId,MAX_PATH-1); if(UniquenessDatabaseFile) { Text[d] = TEXT('*'); Text[d+1] = 0; } b = WritePrivateProfileString(WinntDataSection,WINNT_D_UNIQUENESS,Text,FileName); if(!b) { goto c1; } if(UniquenessDatabaseFile) { if ('\0' == LocalSourceDirectory[0]) { MessageBoxFromMessage( ParentWindow, MSG_UDF_INVALID_USAGE, FALSE, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, UniquenessDatabaseFile ); goto c0; } lstrcpyn(Text,LocalSourceDirectory,MAX_PATH); ConcatenatePaths(Text,WINNT_UNIQUENESS_DB,MAX_PATH); CreateMultiLevelDirectory(LocalSourceDirectory); b = CopyFile(UniquenessDatabaseFile,Text,FALSE); if(!b) { MessageBoxFromMessageAndSystemError( ParentWindow, MSG_UDF_FILE_INVALID, GetLastError(), AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, UniquenessDatabaseFile ); goto c0; } } } // // If any optional dirs are present then we want to generate // an entry in the sif file that contains a line that specifies them // in the form dir1*dir2*...*dirn // OptionalDirLength = 0; OptionalDirString = NULL; for(d=0; d MAX_PATH) { d = MAX_PATH - 5; } Text[d++] = TEXT('\\'); Text[d++] = (TCHAR)(((GetTickCount() & 0x00f) >> 0) + 'A'); Text[d++] = (TCHAR)(((GetTickCount() & 0x0f0) >> 4) + 'A'); Text[d++] = (TCHAR)(((GetTickCount() & 0xf00) >> 8) + 'A'); Text[d++] = 0; // // Set the value in the registry. // l = RegSetValueEx(hKey,WinntUniqueId,0,REG_SZ,(CONST BYTE *)Text,d*sizeof(TCHAR)); if(l == NO_ERROR) { l = RegFlushKey (hKey); } RegCloseKey(hKey); if(l != NO_ERROR) { SetLastError(l); goto c2; } // // Stick the value in winnt.sif so we can correlate // later when we go to upgrade. // b = WritePrivateProfileString(WinntDataSection,WinntUniqueId,Text,FileName); if(!b) { goto c1; } // // Now write information about the source path(s) we used. // Use SourcePath[0]. // // 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((SourcePaths[0][0] == TEXT('\\')) && (SourcePaths[0][1] == TEXT('\\'))) { d = DRIVE_REMOTE; lstrcpy(Text,SourcePaths[0]); } else { if(GetFullPathName(SourcePaths[0],MAX_PATH,FullPath,(LPTSTR *)&p)) { if(FullPath[0] == TEXT('\\')) { // // Assume UNC, since a full path should normally start // with a drive letter. // d = DRIVE_REMOTE; lstrcpy(Text,FullPath); } else { d = MyGetDriveType(FullPath[0]); if((d == DRIVE_REMOTE) && (FullPath[1] == TEXT(':')) && (FullPath[2] == TEXT('\\'))) { // // Get actual UNC path. // FullPath[2] = 0; l = MAX_PATH; if(WNetGetConnection(FullPath,Text,(LPDWORD)&l) == NO_ERROR) { l = lstrlen(Text); if(l && (Text[l-1] != TEXT('\\')) && FullPath[3]) { Text[l] = TEXT('\\'); Text[l+1] = 0; } StringCchCat(Text, ARRAYSIZE(Text), FullPath+3); } else { // // Strange case. // FullPath[2] = TEXT('\\'); lstrcpy(Text,FullPath); d = DRIVE_UNKNOWN; } } else { // // Use as-is. // if(d == DRIVE_REMOTE) { d = DRIVE_UNKNOWN; } lstrcpy(Text,FullPath); } } } else { // // Type is unknown. Just use as-is. // d = DRIVE_UNKNOWN; lstrcpy(Text,SourcePaths[0]); } } // // 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) { // // marcw (7-22-97) - Changed to fix alpha build break. // FirstFloppyDriveLetter is defined on amd64/X86s only. // if (!IsArc()) { #if defined(_AMD64_) || defined(_X86_) Text[0] = FirstFloppyDriveLetter; Text[1] = TEXT(':'); Text[2] = TEXT('\\'); Text[3] = 0; #endif // defined(_AMD64_) || defined(_X86_) } else { #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade lstrcpy(Text,TEXT("A:\\")); #endif // UNICODE } // if (!IsArc()) if (LocalSourceWithPlatform[0]) { ConcatenatePaths( Text, &LocalSourceWithPlatform[lstrlen(LocalSourceDirectory)], MAX_PATH ); } d = DRIVE_CDROM; } b = WritePrivateProfileString(WinntDataSection,WINNT_D_ORI_SRCPATH,Text,FileName); if(!b) { goto c1; } #if defined(REMOTE_BOOT) // // If this is a remote boot upgrade, write the source path to SetupSourceDevice // under [SetupData]. We do NOT want the platform path here. Also write the // path to the machine directory to TargetNtPartition under [SetupData]. This // is just whatever \DosDevices\C: translates to. Finally, write the computer // name to ComputerName under [UserData]. // if (RemoteBoot) { DWORD len; MYASSERT(d == DRIVE_REMOTE); MYASSERT((*Text == TEXT('\\')) && (*(Text + 1) == TEXT('\\'))); lstrcpy(FullPath, TEXT("\\Device\\LanmanRedirector")); ConcatenatePaths(FullPath, Text+1, MAX_PATH); p = _tcsrchr(FullPath,TEXT('\\')); MYASSERT(p != NULL); *(LPTSTR)p = 0; b = WritePrivateProfileString( WinntSetupDataSection, TEXT("SetupSourceDevice"), FullPath, FileName); if(!b) { goto c1; } MyGetWindowsDirectory(Text, MAX_PATH); Text[2] = 0; len = QueryDosDevice(Text, Text, MAX_PATH); if (len == 0) { goto c1; } b = WritePrivateProfileString( WinntSetupDataSection, TEXT("TargetNtPartition"), Text, FileName); if(!b) { goto c1; } len = MAX_PATH; b = GetComputerName(Text, &len); if(!b) { goto c1; } b = WritePrivateProfileString( WinntUserDataSection, WINNT_US_COMPNAME, Text, FileName); if(!b) { goto c1; } } #endif // defined(REMOTE_BOOT) wsprintf(Text,TEXT("%u"),d); WritePrivateProfileString(WinntDataSection,WINNT_D_ORI_SRCTYPE,Text,FileName); if(!b) { goto c1; } #ifdef _X86_ // // NT 4 and Win95 for NEC98 have 2 types Drive assing. // - NEC DOS Type(A: HD, B:HD,...X:FD) // - PC-AT Type(A:FD, B:FD, C:HD, D:HD, ....) // // Upgrade setup should be keep above drive assign and All setup should // be keep FT information. // Because some Applications have drive letter in own data file or registry. // NT5 setup for NEC98 have Drive assign type in winnt.sif section[data]. // And this key is "DriveAssign_Nec98". // Value is "yes", It means NEC DOS Type assign. // Value is "no", It means PC-AT Type. // Now, This Key defined this place, but near future, this key move into // \nt\public\sdk\inc\setupbat.h, I hope. // // \textmode\kernel\spsetup.c has same defines. // #define WINNT_D_DRIVEASSIGN_NEC98_W L"DriveAssign_Nec98" #define WINNT_D_DRIVEASSIGN_NEC98_A "DriveAssign_Nec98" #ifdef UNICODE #define WINNT_D_DRIVEASSIGN_NEC98 WINNT_D_DRIVEASSIGN_NEC98_W #else #define WINNT_D_DRIVEASSIGN_NEC98 WINNT_D_DRIVEASSIGN_NEC98_A #endif if (IsNEC98()){ if (IsDriveAssignNEC98() == TRUE){ WritePrivateProfileString(WinntDataSection, WINNT_D_DRIVEASSIGN_NEC98, WINNT_A_YES, FileName); } else { WritePrivateProfileString(WinntDataSection, WINNT_D_DRIVEASSIGN_NEC98, WINNT_A_NO, FileName); } } #endif // // 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. // WritePrivateProfileString(NULL,NULL,NULL,FileName); d = PatchWinntSifFile(FileName); if(d != NO_ERROR) { SetLastError(d); goto c1; } // // Language options // Note: we don't want these values surrounded by double-quotes. // if( SaveLanguageParams( FileName ) ) { FreeLanguageData(); } else { goto c1; } // // Append unattend script file if necessary. // if(UnattendedOperation && UnattendedScriptFile) { if (!MigrateUnattendDataEntries(FileName, UnattendedScriptFile)){ goto c1; } if(!AppendParamsFile(ParentWindow,UnattendedScriptFile,FileName)) { return(FALSE); } } #if defined(UNICODE) && defined(_X86_) // // Append any migdll info. // if (Upgrade && ISNT() && *g_MigDllAnswerFilePath && FileExists (g_MigDllAnswerFilePath, NULL)) { AppendParamsFile (ParentWindow, g_MigDllAnswerFilePath, FileName); } #endif // // append DynamicUpdate data // if (!DynamicUpdateWriteParams (FileName)) { goto c1; } // // If we're explicitly in unattended mode then it's possible that // there is no [Unattended] section in winnt.sif yet, such as if // the user used the /unattend switch without specifying a file, // or if the file he did specify didn't have an [Unattended] section // for some reason. // // Also, make all upgrades unattended. // // Text mode setup kicks into unattended mode based on the presence // of the [Unattended] section. // if(UnattendedOperation || Upgrade) { if(!WritePrivateProfileString(WINNT_UNATTENDED,TEXT("unused"),TEXT("unused"),FileName)) { goto c1; } } // // Since several conditions can turn on UnattendedOperation, we keep track // of whether the user actually specified the "/unattend" switch separately. // if( UnattendSwitchSpecified ) { if(!WritePrivateProfileString(WinntDataSection,WINNT_D_UNATTEND_SWITCH,WINNT_A_YES,FileName)) { goto c1; } } // // set the NTFS conversion flag // GetPrivateProfileString(WINNT_UNATTENDED,TEXT("FileSystem"),TEXT(""),Text,sizeof(Text)/sizeof(TCHAR),FileName); if (_tcslen(Text) == 0) { if (ForceNTFSConversion) { if(!WritePrivateProfileString(WinntDataSection,TEXT("FileSystem"),TEXT("ConvertNTFS"),FileName)) { goto c1; } } } // // Headless Stuff. // if( !WriteHeadlessParameters( FileName ) ) { goto c1; } if ( (Upgrade) && !(ISNT() && (BuildNumber <= NT351)) ) { // // Save current Program Files directory // rc = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), 0, //ulOptions (reserved) KEY_READ, &hKey ); if (rc != ERROR_SUCCESS) { goto c1; } PfPath = pGetPfPath (hKey, TEXT("ProgramFilesDir")); if (PfPath) { if (!WritePrivateProfileString ( WINNT_UNATTENDED, WINNT_U_PROGRAMFILESDIR, PfPath, FileName )) { goto c3; } FREE((PVOID) PfPath); } PfPath = pGetPfPath (hKey, TEXT("CommonFilesDir")); if (PfPath) { if (!WritePrivateProfileString ( WINNT_UNATTENDED, WINNT_U_COMMONPROGRAMFILESDIR, PfPath, FileName )) { goto c3; } FREE((PVOID) PfPath); } #ifdef WX86 PfPath = pGetPfPath (hKey, TEXT("ProgramFilesDir (x86)")); if (PfPath) { if (!WritePrivateProfileString ( WINNT_UNATTENDED, WINNT_U_PROGRAMFILESDIR_X86, PfPath, FileName )) { goto c3; } FREE((PVOID) PfPath); } PfPath = pGetPfPath (hKey, TEXT("CommonFilesDir (x86)")); if (PfPath) { if (!WritePrivateProfileString ( WINNT_UNATTENDED, WINNT_U_COMMONPROGRAMFILESDIR_X86, PfPath, FileName )) { goto c3; } FREE((PVOID) PfPath); } #endif RegCloseKey(hKey); } // // value indicating the product ID // we need to write this in after appending the unattend file data, since the // product ID in the unattend file may have been incorrect, but this product ID // has already been verified as valid. we need to make sure we surround the product ID with quotes // if (b ) { // This will overwrite any existing "ProductID" entry. Which may have been added // by merging the unattend file. // If we don't do this. GUI mode overwrites the "ProductKey" with the entry // under "ProductID". b = WritePidToParametersFile(WinntUserSection,WINNT_US_PRODUCTID,FileName); if (!b) { goto c1; } b = WritePidToParametersFile(WinntUserSection,WINNT_US_PRODUCTKEY,FileName); if (!b) { goto c1; } } // // Do not save the proxy settings if we are running under WINPE. // if (!IsWinPEMode()){ SaveProxyForOobe(FileName); } return(TRUE); c3: FREE((PVOID) PfPath); RegCloseKey(hKey); c2: MessageBoxFromMessageAndSystemError( ParentWindow, MSG_REGISTRY_ACCESS_ERROR, GetLastError(), AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, NULL ); goto c0; c1: MessageBoxFromMessageAndSystemError( ParentWindow, MSG_BOOT_FILE_ERROR, GetLastError(), AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, FileName ); c0: return(FALSE); } DWORD PatchWinntSifFile( IN LPCTSTR Filename ) /*++ Routine Description: This function works around the problems in the setupldr parser, which cannot handle unquoted strings. Each line in the given file is enclosed within quotation marks. Arguments: Filename - Name of the WINNT.SIF file Return Value: Boolean value indicating outcome. If FALSE the user is NOT informed about why; the caller must do that. --*/ { PVOID Base; HANDLE hMap,hFile; DWORD Size; DWORD d; PCHAR End; PCHAR p,q; PCHAR o,a; PCHAR Buffer; int l1,l2; int tryagain=0; // // Open the file. // d = MapFileForRead(Filename,&Size,&hFile,&hMap,&Base); if(d != NO_ERROR) { return(FALSE); } // // Allocate the output buffer; the original size + extra space for quotes // Buffer = MALLOC(Size + Size / 4); if(!Buffer) { UnmapFile(hMap,Base); CloseHandle(hFile); return(ERROR_NOT_ENOUGH_MEMORY); } 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 0) { int i; Unicode = (LPWSTR) GlobalAlloc(GPTR, Length * sizeof(WCHAR)); if (!Unicode) { return NULL; } i = MultiByteToWideChar( CP_ACP, 0, Ansi, -1, Unicode, Length); if (i == 0) { GlobalFree(Unicode); Unicode = NULL; } } return Unicode; } #else LPSTR AnsiToText( LPCSTR Ansi ) /*++ Note: Can't use DupString because the caller assume memory obtained from GlobalAlloc. --*/ { LPSTR CopyOfAnsi = NULL; if (Ansi != NULL) { CopyOfAnsi = GlobalAlloc(GPTR, (strlen(Ansi)+1) * sizeof(CHAR)); if (CopyOfAnsi) { strcpy(CopyOfAnsi, Ansi); } } return CopyOfAnsi; } #endif BOOL QuoteString( IN OUT LPTSTR* StringPointer ) /*++ Routine Description: Replace the input string with a double quoted one. Arguments: StringPointer - pointer to a string allocated by GlobalAlloc. The input string is always free. If it is successful the new string, allocated by GlobalAlloc, is returned; otherwise, NULL is returned. Return: TRUE - successfully quote a string FALSE - otherwise --*/ { LPTSTR StringValue = *StringPointer; LPTSTR QuotedString; QuotedString = GlobalAlloc(GPTR, (lstrlen(StringValue) + 3) * sizeof(TCHAR)); if (QuotedString) { wsprintf(QuotedString, TEXT("\"%s\""), StringValue); *StringPointer = QuotedString; } else { *StringPointer = NULL; } GlobalFree(StringValue); return (*StringPointer != NULL); } VOID SaveProxyForOobe( IN LPCTSTR FileName ) /*++ Routine Description: Save the LAN http and https proxy settings, if any, for OOBE to use while it is running in 'SYSTEM' context. Arguments: FileName - specifies the full Win32 filename for saving Setup settings. --*/ { typedef BOOL (WINAPI* PINTERNETQUERYOPTION)( IN HINTERNET hInternet OPTIONAL, IN DWORD dwOption, OUT LPVOID lpBuffer OPTIONAL, IN OUT LPDWORD lpdwBufferLength ); HMODULE WinInetLib; LPTSTR ProxyList = NULL; LPTSTR ProxyOverride = NULL; LPTSTR AutoConfigUrl = NULL; LPTSTR AutoConfigUrl2 = NULL; DWORD ProxyFlags = 0; DWORD AutoDiscoveryFlags = 0; TCHAR NumberStr[25]; BOOL Captured = FALSE; WinInetLib = LoadLibrary(TEXT("WININET.DLL")); // // We prefer the INTERNET_OPTION_PER_CONNECTION_OPTION because we just // want to save the LAN proxy settings and we want to know the auto proxy // setting, but this option is not supported until IE 5.0 // if (WinInetLib != NULL) { PINTERNETQUERYOPTION pInternetQueryOption; pInternetQueryOption = (PINTERNETQUERYOPTION) GetProcAddress( WinInetLib, #ifdef UNICODE "InternetQueryOptionW" #else "InternetQueryOptionA" #endif ); if (pInternetQueryOption) { INTERNET_PER_CONN_OPTION_LIST OptionList; INTERNET_PER_CONN_OPTION Option[6]; DWORD BufferLength = sizeof(OptionList); OptionList.dwSize = sizeof(OptionList); OptionList.pszConnection = NULL; OptionList.dwOptionCount = 6; ZeroMemory(&Option, sizeof(Option)); Option[0].dwOption = INTERNET_PER_CONN_FLAGS; Option[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER; Option[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; Option[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; Option[4].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; Option[5].dwOption = INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL; OptionList.pOptions = Option; if (pInternetQueryOption( NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &OptionList, &BufferLength ) == TRUE) { ProxyFlags = Option[0].Value.dwValue; ProxyList = Option[1].Value.pszValue; ProxyOverride = Option[2].Value.pszValue; AutoConfigUrl = Option[3].Value.pszValue; AutoDiscoveryFlags = Option[4].Value.dwValue; AutoConfigUrl2 = Option[5].Value.pszValue; Captured = TRUE; } else { INTERNET_PROXY_INFO* ProxyInfo = NULL; DWORD BufferLength = 0; // // We obtain the ANSI string for INTERNET_OPTION_PROXY, // even if we call InternetQueryOptionW. // // Proxy list returned from INTERNET_OPTION_PER_CONNECTION are // delimited by ';', while that returned from INTERNET_OPTION_PROXY // are delimited by ' '. // if (pInternetQueryOption( NULL, INTERNET_OPTION_PROXY, ProxyInfo, &BufferLength ) == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { ProxyInfo = (INTERNET_PROXY_INFO*) GlobalAlloc(GPTR, BufferLength); if (ProxyInfo) { if (pInternetQueryOption( NULL, INTERNET_OPTION_PROXY, ProxyInfo, &BufferLength ) == TRUE) { // // Map the values to INTERNET_OPTION_PER_CONN_OPTION // We enable the auto proxy settings even though // INTERNET_OPTION_PROXY doesn't have value relevant // to auto proxy, because IE5 default to use auto proxy. // // PROXY_TYPE_DIRECT is always set because wininet // return this flags whether inetcpl.cpl is set // to use proxy or not. // ProxyFlags = PROXY_TYPE_DIRECT | PROXY_TYPE_AUTO_DETECT; if (ProxyInfo->dwAccessType != INTERNET_OPEN_TYPE_DIRECT) { ProxyFlags |= PROXY_TYPE_PROXY; } ProxyList = AnsiToText((LPCSTR)ProxyInfo->lpszProxy); FixWininetList(ProxyList); ProxyOverride = AnsiToText((LPCSTR)ProxyInfo->lpszProxyBypass); FixWininetList(ProxyOverride); AutoDiscoveryFlags = 0; Captured = TRUE; } GlobalFree(ProxyInfo); } } } } FreeLibrary(WinInetLib); } if (Captured) { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_ENABLE_OOBEPROXY, TEXT("1"), FileName ); if (ProxyList && QuoteString(&ProxyList)) { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_PROXY_SERVER, ProxyList, FileName ); GlobalFree(ProxyList); } // // Fix the ProxyOverride to not have any "\r\n"s // if (ProxyOverride) { ReplaceSubStr(ProxyOverride, TEXT("\r\n"), TEXT(";")); } if (ProxyOverride && QuoteString(&ProxyOverride)) { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_PROXY_BYPASS, ProxyOverride, FileName ); GlobalFree(ProxyOverride); } if (AutoConfigUrl && QuoteString(&AutoConfigUrl)) { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_AUTOCONFIG_URL, AutoConfigUrl, FileName ); GlobalFree(AutoConfigUrl); } if (AutoConfigUrl2 && QuoteString(&AutoConfigUrl2)) { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_AUTOCONFIG_SECONDARY_URL, AutoConfigUrl2, FileName ); GlobalFree(AutoConfigUrl2); } wsprintf(NumberStr, TEXT("%u"), ProxyFlags); WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_FLAGS, NumberStr, FileName ); wsprintf(NumberStr, TEXT("%u"), AutoDiscoveryFlags); WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_AUTODISCOVERY_FLAGS, NumberStr, FileName ); } else { WritePrivateProfileString( WINNT_OOBEPROXY, WINNT_O_ENABLE_OOBEPROXY, TEXT("0"), FileName ); } } #ifdef _X86_ BOOL IsDriveAssignNEC98( VOID ) { TCHAR sz95KeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); TCHAR sz95ValueName[] = TEXT("ATboot"); TCHAR szNTKeyName[] = TEXT("System\\setup"); TCHAR szNTValueName[] = TEXT("DriveLetter"); HKEY hKey; DWORD type95 = REG_BINARY; DWORD typeNT = REG_SZ; TCHAR szData[5]; DWORD dwSize = 5; DWORD rc; if(ISNT()){ rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szNTKeyName, 0, //ulOptions (reserved) KEY_READ, &hKey); if (ERROR_SUCCESS != rc) { return TRUE; } // // Query key to get the subkey count and max string lengths // rc = RegQueryValueEx (hKey, szNTValueName, NULL, // lpReserved &typeNT, (LPBYTE) szData, &dwSize); if (ERROR_SUCCESS != rc) { RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); if (szData[0] != L'C'){ // NEC DOS Type. return TRUE; } } else { // It will be Win9x rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, sz95KeyName, 0, //ulOptions (reserved) KEY_READ, &hKey); if (ERROR_SUCCESS != rc) { return TRUE; } // // Query key to get the subkey count and max string lengths // rc = RegQueryValueEx (hKey, sz95ValueName, NULL, // lpReserved &type95, (LPBYTE) szData, &dwSize); if (ERROR_SUCCESS != rc) { RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); if (szData[0] == 0){ // NEC DOS Type. return TRUE; } } return FALSE; } #endif