windows-nt/Source/XPSP1/NT/base/ntsetup/winnt32/dll/params.c
2020-09-26 16:20:57 +08:00

2591 lines
67 KiB
C

/*++
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 ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#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
);
#ifdef _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;
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
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){
lstrcpy(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 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()) {
#ifdef _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 // _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
b = WritePrivateProfileString(WinntSetupDataSection,TEXT("SetupCmdlinePrepend"),TEXT("ntsd -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<OptionalDirectoryCount; d++) {
//
// Ignore temp-only and oem directories here.
//
if(OptionalDirectoryFlags[d] & (OPTDIR_OEMSYS | OPTDIR_TEMPONLY | OPTDIR_OVERLAY)) {
continue;
}
if (OptionalDirectoryFlags[d] & (OPTDIR_DEBUGGEREXT)) {
// hardcode the dest dir to "system32\pri"
OptDir = TEXT("system32\\pri");
} else {
if (OptionalDirectoryFlags[d] & OPTDIR_USE_TAIL_FOLDER_NAME) {
//
// create all copydir: directories in a subdirectory under target %windir%
//
OptDir = _tcsrchr (OptionalDirectories[d], TEXT('\\'));
if (OptDir) {
OptDir++;
} else {
OptDir = OptionalDirectories[d];
}
} else {
OptDir = OptionalDirectories[d];
}
}
//
// support ".." syntax
//
while (_tcsstr(OptDir,TEXT("..\\"))) {
OptDir += 3;
}
if(OptionalDirString) {
p = REALLOC(
OptionalDirString,
(lstrlen(OptDir) + 2 + OptionalDirLength) * sizeof(TCHAR)
);
} else {
p = MALLOC((lstrlen(OptDir)+2)*sizeof(TCHAR));
}
if(!p) {
if(OptionalDirString) {
FREE(OptionalDirString);
}
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto c1;
}
OptionalDirString = p;
if(OptionalDirLength) {
lstrcat(OptionalDirString,OptDir);
} else {
lstrcpy(OptionalDirString,OptDir);
}
lstrcat(OptionalDirString,TEXT("*"));
OptionalDirLength = lstrlen(OptionalDirString);
}
if(OptionalDirString) {
//
// Remove trailing * if any
//
d = lstrlen(OptionalDirString);
if(d && (OptionalDirString[d-1] == TEXT('*'))) {
OptionalDirString[d-1] = 0;
}
b = WritePrivateProfileString(
WinntSetupSection,
WINNT_S_OPTIONALDIRS,
OptionalDirString,
FileName
);
d = GetLastError();
FREE(OptionalDirString);
if(!b) {
SetLastError(d);
goto c1;
}
}
//
// Slap a unique identifier into the registry.
// We'll use this in unattended upgrade during text mode
// to find this build.
//
// Pretty simple: we'll use a string that derives
// from the sysroot, and some unique value based on
// the current tick count.
//
l = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\Setup"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
&hKey,
&d
);
if(l != NO_ERROR) {
SetLastError(l);
goto c2;
}
d = MyGetWindowsDirectory(Text,MAX_PATH);
if((d + 5) > 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));
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;
}
lstrcat(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 X86s only.
//
if (!IsArc()) {
#ifdef _X86_
Text[0] = FirstFloppyDriveLetter;
Text[1] = TEXT(':');
Text[2] = TEXT('\\');
Text[3] = 0;
#endif // _X86_
} else {
#ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
lstrcpy(Text,TEXT("A:\\"));
#endif // UNICODE
} // if (!IsArc())
MYASSERT (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(!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<q; a++) {
if(*a == '=') {
break;
}
}
if(a >= q) {
a = NULL;
}
if(a) {
a++;
l1 = (int)(a - p);
l2 = (int)(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 = (int)(q-p);
CopyMemory(o,p,l1);
o += l1;
*o++ = '\n';
}
//
// Skip to start of next line
//
p=q+1;
}
UnmapFile(hMap,Base);
CloseHandle(hFile);
SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
//
// We try opening the file thrice to get around the problem of anti-virus software
// that monitor files on the root of the system partition. The problem is that usually these
// s/w examine the files we touch and in somecases open it with exclusive access.
// We just need to wait for them to be done.
//
while( tryagain++ < 3 ){
hFile = CreateFile(
Filename,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(hFile != INVALID_HANDLE_VALUE)
break;
Sleep(500);
}
if(hFile == INVALID_HANDLE_VALUE) {
d = GetLastError();
FREE(Buffer);
return(d);
}
d = WriteFile(hFile,Buffer,(DWORD)(o-Buffer),&Size,NULL) ? NO_ERROR : GetLastError();
CloseHandle(hFile);
FREE(Buffer);
return(d);
}
BOOL
AppendParamsFile(
IN HWND ParentWindow,
IN LPCTSTR ParametersFileIn,
IN LPCTSTR ParametersFileOut
)
/*++
Routine Description:
Read an external file (such as an unattended script file)
and copy it section by section into the winnt.sif parameters
file. (The [Data] and [OemBootFiles] sections of the unattend file
are ignored.)
Arguments:
ParentWindow - supplies window handle of window to act as owner/parent
if this routine has to put up ui, such as when the script file
is bogus.
ParametersFileIn - supplies win32 filename of the file, such as
unattend.txt, being appended to winnt.sif.
ParametersFileOut - supplies win32 filename of the winnt.sif file
being generated.
Return Value:
Boolean value indicating outcome. If FALSE, the user will have been
informed of why.
--*/
{
TCHAR *SectionNames;
TCHAR *SectionData;
TCHAR *SectionName;
DWORD SectionNamesSize;
DWORD SectionDataSize;
DWORD d;
TCHAR TempFile[MAX_PATH] = TEXT("");
PCTSTR RealInputFile = NULL;
BOOL b;
PVOID p;
#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));
if(!SectionNames || !SectionData) {
MessageBoxFromMessage(
ParentWindow,
MSG_OUT_OF_MEMORY,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL
);
b = FALSE;
goto c0;
}
*TempFile = 0;
RealInputFile = ParametersFileIn;
//
// There is a bug in Win9x's GetPrivateProfileSection() Such that if the file
// being queried exists on a read only share, it will not return the section strings.
// This is bad.
//
// To work around this, on win9x, we are going to make a temporary copy of the inf
// merge it in and then delete it.
//
#ifdef _X86_
if (!ISNT() && ParametersFileIn && FileExists (ParametersFileIn, NULL)) {
GetSystemDirectory (TempFile, MAX_PATH);
GetTempFileName (TempFile, TEXT("USF"), 0, TempFile);
CopyFile (ParametersFileIn, TempFile, FALSE);
RealInputFile = TempFile;
}
#endif
SectionNamesSize = PROFILE_BUFSIZE;
SectionDataSize = PROFILE_BUFSIZE;
//
// Retreive a list of section names in the unattend script file.
//
do {
d = GetPrivateProfileString(
NULL,
NULL,
TEXT(""),
SectionNames,
SectionNamesSize,
RealInputFile
);
if(!d) {
//
// No section names. Bogus file.
//
MessageBoxFromMessage(
ParentWindow,
MSG_UNATTEND_FILE_INVALID,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ParametersFileIn
);
b = FALSE;
goto c0;
}
if(d == (SectionNamesSize-2)) {
//
// Buffer was too small. Reallocate it and try again.
//
p = REALLOC(
SectionNames,
(SectionNamesSize+PROFILE_BUFGROW)*sizeof(TCHAR)
);
if(!p) {
MessageBoxFromMessage(
ParentWindow,
MSG_OUT_OF_MEMORY,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL
);
b = FALSE;
goto c0;
}
SectionNames = p;
SectionNamesSize += PROFILE_BUFGROW;
}
} while(d == (SectionNamesSize-2));
for(SectionName=SectionNames; *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,WINNT_DATA) && lstrcmpi(SectionName,WINNT_OEMBOOTFILES)) {
//
// 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,
RealInputFile
) == (SectionDataSize-2)) {
//
// Reallocate the buffer and try again.
//
p = REALLOC(
SectionData,
(SectionDataSize+PROFILE_BUFGROW)*sizeof(TCHAR)
);
if(!p) {
MessageBoxFromMessage(
ParentWindow,
MSG_OUT_OF_MEMORY,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL
);
b = FALSE;
goto c0;
}
SectionData = 0;
SectionDataSize += PROFILE_BUFGROW;
}
//
// Write the entire section to the output file.
//
if(!WritePrivateProfileSection(SectionName,SectionData,ParametersFileOut)) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_BOOT_FILE_ERROR,
GetLastError(),
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ParametersFileOut
);
b = FALSE;
goto c0;
}
}
}
b = TRUE;
c0:
if(SectionNames) {
FREE(SectionNames);
}
if(SectionData) {
FREE(SectionData);
}
if (*TempFile) {
DeleteFile (TempFile);
}
return(b);
}
BOOL
WriteParametersFile(
IN HWND ParentWindow
)
{
TCHAR SysPartFile[MAX_PATH];
DWORD d;
BOOL b;
//
// Write the file out onto the root of the system partition drive
// and then move the file into place where it actually belongs.
//
#if defined(REMOTE_BOOT)
if (RemoteBoot) {
//
// For remote boot, put the file in the root of the machine directory
// and leave it there.
//
lstrcpy(SysPartFile, MachineDirectory);
lstrcat(SysPartFile, TEXT("\\"));
lstrcat(SysPartFile,WINNT_SIF_FILE);
lstrcpy(ActualParamFile,SysPartFile);
} else
#endif // defined(REMOTE_BOOT)
{
if (!BuildSystemPartitionPathToFile (WINNT_SIF_FILE, SysPartFile, MAX_PATH)) {
return(FALSE); // this should never happen.
}
}
if(!DoWriteParametersFile(ParentWindow,SysPartFile)) {
return(FALSE);
}
#if defined(REMOTE_BOOT)
//
// For remote boot, leave the file in the root of the machine directory.
//
if (!RemoteBoot)
#endif // defined(REMOTE_BOOT)
{
if (!IsArc()) {
#ifdef _X86_
//
// In the x86 case this file belongs on the boot media
// somewhere. If we're generating floppyless boot media
// then move the file into place. Otherwise there's no point.
//
// In the non-floppyless case we keep the file around until later
// when the floppy-generation code gets to run.
//
if(MakeBootMedia) {
if(Floppyless) {
BuildSystemPartitionPathToFile (LOCAL_BOOT_DIR, ActualParamFile, MAX_PATH);
d = CreateMultiLevelDirectory(ActualParamFile);
if(d != NO_ERROR) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_DIR_CREATE_FAILED,
d,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ActualParamFile
);
DeleteFile(SysPartFile);
return(FALSE);
}
ConcatenatePaths(ActualParamFile,WINNT_SIF_FILE,MAX_PATH);
//
// Move the file into its real location.
//
DeleteFile(ActualParamFile);
//
// On Windows 95, MoveFile fails in strange ways
// when the profile APIs have the file open (for instance,
// it will leave the src file and the dest file will be
// filled with garbage).
//
// Flush that bastard
//
WritePrivateProfileString(NULL,NULL,NULL,SysPartFile);
if (SysPartFile[0] == ActualParamFile[0]) {
b = MoveFile(SysPartFile,ActualParamFile);
} else {
b = CopyFile (SysPartFile, ActualParamFile, FALSE);
if (b) {
DeleteFile (SysPartFile);
}
}
if (!b) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_BOOT_FILE_ERROR,
GetLastError(),
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ActualParamFile
);
DeleteFile(SysPartFile);
return(FALSE);
}
}
} else {
DeleteFile(SysPartFile);
}
#endif // _X86_
} else {
#ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
//
// If we're making a local source, move the file there.
// Otherwise just leave it on the root of the system partition.
//
if(MakeLocalSource) {
d = CreateMultiLevelDirectory(LocalSourceWithPlatform);
if(d != NO_ERROR) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_DIR_CREATE_FAILED,
d,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
LocalSourceWithPlatform
);
DeleteFile(SysPartFile);
return(FALSE);
}
//
// Move the file into its real location.
//
wsprintf(ActualParamFile,TEXT("%s\\%s"),LocalSourceWithPlatform,WINNT_SIF_FILE);
DeleteFile(ActualParamFile);
if(!MoveFile(SysPartFile,ActualParamFile)) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_BOOT_FILE_ERROR,
GetLastError(),
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ActualParamFile
);
DeleteFile(SysPartFile);
return(FALSE);
}
}
#endif // UNICODE
} // if (!IsArc())
}
return(TRUE);
}
//#ifdef _X86_
#define MULTI_SZ_NEXT_STRING(x) ((x) + _tcslen(x) + 1)
BOOL
MergeINFFiles(
IN PCTSTR SourceFileName,
IN PCTSTR DestFileName
)
{
DWORD dwAttributes;
PTSTR pSectionsBuffer = NULL;
PTSTR pKeysBuffer = NULL;
PTSTR pString = NULL;
PTSTR pSection;
PTSTR pKey;
UINT sizeOfBuffer;
UINT sizeOfSectionBuffer;
BOOL bResult = FALSE;
MYASSERT (SourceFileName && DestFileName);
if(-1 == GetFileAttributes(SourceFileName)){
return TRUE;
}
__try{
//
// Allocate buffer for sections names.
//
sizeOfBuffer = 0;
do{
if(pSectionsBuffer){
FREE(pSectionsBuffer);
}
sizeOfBuffer += DEF_INF_BUFFER_SIZE;
pSectionsBuffer = (PTSTR)MALLOC(sizeOfBuffer * sizeof (TCHAR));
if(!pSectionsBuffer){
__leave;
}
}while((sizeOfBuffer - 2) ==
GetPrivateProfileSectionNames(pSectionsBuffer,
sizeOfBuffer,
SourceFileName));
sizeOfSectionBuffer = DEF_INF_BUFFER_SIZE;
pKeysBuffer = (PTSTR)MALLOC(sizeOfSectionBuffer * sizeof (TCHAR));
if(!pKeysBuffer){
__leave;
}
sizeOfBuffer = DEF_INF_BUFFER_SIZE;
pString = (PTSTR)MALLOC(sizeOfBuffer * sizeof (TCHAR));
if(!pString){
__leave;
}
for(pSection = pSectionsBuffer; pSection[0]; pSection = MULTI_SZ_NEXT_STRING(pSection)){
//
// Allocate buffer for entries names;
//
while((sizeOfSectionBuffer - 2) ==
GetPrivateProfileString(pSection,
NULL,
EMPTY_STRING,
pKeysBuffer,
sizeOfSectionBuffer,
SourceFileName)){
if(pKeysBuffer){
FREE(pKeysBuffer);
}
sizeOfSectionBuffer += DEF_INF_BUFFER_SIZE;
pKeysBuffer = (PTSTR)MALLOC(sizeOfSectionBuffer * sizeof (TCHAR));
if(!pKeysBuffer){
__leave;
}
};
for(pKey = pKeysBuffer; pKey[0]; pKey = MULTI_SZ_NEXT_STRING(pKey))
{
//
// Allocate buffer for value string;
//
GetPrivateProfileString(pSection,
pKey,
EMPTY_STRING,
pString,
sizeOfBuffer,
SourceFileName);
if (!WritePrivateProfileString(pSection, pKey, pString, DestFileName)) {
__leave;
}
}
}
bResult = TRUE;
}
__finally{
DWORD rc = GetLastError ();
if(pSectionsBuffer){
FREE(pSectionsBuffer);
}
if(pKeysBuffer){
FREE(pKeysBuffer);
}
if(pString){
FREE(pString);
}
SetLastError (rc);
}
return bResult;
}
BOOL
AddExternalParams (
IN HWND ParentWindow
)
{
DWORD rc = ERROR_SUCCESS;
static BOOL Done = FALSE;
if(Done) {
return(TRUE);
}
//
// Append external parameters if necessary.
//
if(Upgrade && UpgradeSupport.WriteParamsRoutine) {
rc = UpgradeSupport.WriteParamsRoutine(ActualParamFile);
if (rc != ERROR_SUCCESS) {
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_BOOT_FILE_ERROR,
GetLastError(),
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
ActualParamFile
);
}
}
#if defined(UNICODE) && defined(_X86_)
//
// Merge NT migration unattented inf file with winnt.sif
//
if(Upgrade && !MergeINFFiles(g_MigDllAnswerFilePath, ActualParamFile)){
MessageBoxFromMessageAndSystemError(
ParentWindow,
MSG_BOOT_FILE_ERROR,
GetLastError(),
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
g_MigDllAnswerFilePath
);
}
#endif
//
// write the compatibility stuff in these cases
//
// 1. upgrade from downlevel NT platform
// 2. clean install
// 3. upgrade from current NT platform and we have NT5 compatibility items
//
// note that win9x has it's own upgrade code path.
//
if( (ISNT() && (BuildNumber <= NT40) && Upgrade)
|| !Upgrade
|| (ISNT() && Upgrade && AnyNt5CompatDlls) ){
//
// Disable stuff for <= NT4 case, clean install (unsupported arch. etc.)
// and NT5 upgrade with NT5 upgrade components set
//
WriteCompatibilityData( ActualParamFile );
WriteGUIModeInfOperations( ActualParamFile );
AddGUIModeCompatibilityInfsToCopyList();
}
if (ISNT() && Upgrade) {
if (!WriteTextmodeClobberData (ActualParamFile)) {
rc = GetLastError ();
}
}
Done = TRUE;
return rc == ERROR_SUCCESS;
}
//#endif "
BOOL
MyWritePrivateProfileString(
LPCTSTR lpAppName, // pointer to section name
LPCTSTR lpKeyName, // pointer to key name
LPCTSTR lpString, // pointer to string to add
LPCTSTR lpFileName // pointer to initialization filename
)
/*
Wrapper for WritePrivateProfileString to try more than once on instances
where we can't write to the winnt.sif file. This commonly occurs when
virus software monitors the root of C drive.
The problem is that usually these s/w examine the files we touch and in somecases open it
with exclusive access. We just need to wait for them to be done.
*/
{
int i = 0;
BOOL ret = FALSE;
DWORD Err;
while(i++ < 3){
#ifdef UNICODE
#ifdef WritePrivateProfileStringW
#undef WritePrivateProfileStringW
if( !lpAppName && !lpKeyName && !lpString ){
WritePrivateProfileStringW( lpAppName, lpKeyName, lpString, lpFileName);
return FALSE;
}
if( ret = WritePrivateProfileStringW( lpAppName, lpKeyName, lpString, lpFileName) )
break;
#endif
#else
#ifdef WritePrivateProfileStringA
#undef WritePrivateProfileStringA
if( !lpAppName && !lpKeyName && !lpString ){
WritePrivateProfileStringA( lpAppName, lpKeyName, lpString, lpFileName);
return FALSE;
}
if( ret = WritePrivateProfileStringA( lpAppName, lpKeyName, lpString, lpFileName) )
break;
#endif
#endif
Sleep( 500 );
}
return ret;
}
VOID
FixWininetList(
LPTSTR List
)
{
PTCHAR t = List;
if (t != NULL)
{
while (*t)
{
if (*t == (TCHAR)' ')
{
*t = (TCHAR)';';
}
t++;
}
}
}
#ifdef UNICODE
LPWSTR
AnsiToText(
LPCSTR Ansi
)
{
int Length;
LPWSTR Unicode = NULL;
if (Ansi == NULL)
{
return NULL;
}
Length = MultiByteToWideChar(
CP_ACP,
0,
Ansi,
-1,
NULL,
0
);
if (Length > 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