1878 lines
54 KiB
C
1878 lines
54 KiB
C
/*++
|
|
|
|
Microsoft Confidential
|
|
Copyright (c) 1992-1997 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
strtlst.c
|
|
|
|
Abstract:
|
|
|
|
Implements the controls in the "Startup" group on the
|
|
Startup/Recovery dialog of the System Control Panel Applet
|
|
|
|
Revision History:
|
|
|
|
23-Jan-1996 JonPa
|
|
ported from NT3.51's system.cpl
|
|
|
|
--*/
|
|
#include "sysdm.h"
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Persistant vars
|
|
///////////////////////////////////////////////////////////////
|
|
static TCHAR *pszBoot = NULL;
|
|
static int nOriginalSelection;
|
|
static int nOriginalTimeout;
|
|
|
|
HANDLE hBootStatusData = NULL;
|
|
|
|
/*
|
|
* These functions in SETUPDLL.DLL are ANSI only!!!!
|
|
*
|
|
* Therefore any functions working with this DLL MUST remain ANSI only.
|
|
* The functions are GetRGSZEnvVar and UpdateNVRAM.
|
|
* The structure CPEnvBuf MUST also remain ANSI only.
|
|
*/
|
|
typedef int (WINAPI *GETNVRAMPROC)(CHAR **, USHORT, CHAR *, USHORT);
|
|
typedef int (WINAPI *WRITENVRAMPROC)(DWORD, PSZ *, PSZ *);
|
|
|
|
#ifdef _X86_
|
|
|
|
char szBootIniA[] = "c:\\boot.ini";
|
|
TCHAR szBootIni[] = TEXT( "c:\\boot.ini" );
|
|
TCHAR szBootLdr[] = TEXT( "boot loader" );
|
|
TCHAR szFlexBoot[] = TEXT( "flexboot" );
|
|
TCHAR szMultiBoot[] = TEXT( "multiboot" );
|
|
TCHAR szTimeout[] = TEXT( "timeout" );
|
|
TCHAR szDefault[] = TEXT( "default" );
|
|
char szOSA[] = "operating systems";
|
|
|
|
#define BUFZ 4096
|
|
|
|
//
|
|
// For NEC PC98. Following definition comes from user\inc\kbd.h.
|
|
// The value must be the same as value in kbd.h.
|
|
//
|
|
#define NLSKBD_OEM_NEC 0x0D
|
|
|
|
TCHAR x86DetermineSystemPartition( IN HWND hdlg );
|
|
|
|
#endif
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
|
|
//
|
|
// IsEfi() is always true on IA64 machines. Therefore this determination can
|
|
// be made at compile time. When x86 EFI machines are supported, the check
|
|
// will need to be made at run time on x86.
|
|
//
|
|
|
|
#if defined(_IA64_)
|
|
#define IsEfi() TRUE
|
|
#else
|
|
BOOLEAN
|
|
IsEfi(
|
|
VOID
|
|
);
|
|
#endif
|
|
|
|
typedef struct _MY_BOOT_ENTRY {
|
|
LIST_ENTRY ListEntry;
|
|
PWSTR FriendlyName;
|
|
int Index;
|
|
LOGICAL Show;
|
|
LOGICAL Ordered;
|
|
PBOOT_ENTRY NtBootEntry;
|
|
} MY_BOOT_ENTRY, *PMY_BOOT_ENTRY;
|
|
|
|
LIST_ENTRY BootEntries;
|
|
PBOOT_ENTRY_LIST BootEntryList = NULL;
|
|
PBOOT_OPTIONS BootOptions;
|
|
|
|
#define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
|
|
|
|
#endif // defined(EFI_NVRAM_ENABLED)
|
|
|
|
// v-pshuan: since the Silicon Graphics visual workstations boot
|
|
// ARC style, this code needs to be compiled for _X86_ as well.
|
|
|
|
static HMODULE hmodSetupDll; // hmod for setup - has api we need
|
|
static GETNVRAMPROC fpGetNVRAMvar; // address of function for getting nvram vars
|
|
BOOL fCanUpdateNVRAM;
|
|
|
|
#define MAX_BOOT_ENTRIES 10
|
|
|
|
typedef struct tagEnvBuf
|
|
{
|
|
int cEntries;
|
|
CHAR * pszVars[MAX_BOOT_ENTRIES];
|
|
// v-pshuan: this implies a maximum of 10 boot entries are supported
|
|
// although no error checking is performed in the existing parsing code
|
|
// to make sure there aren't more than 10 boot entries.
|
|
} CPEnvBuf;
|
|
|
|
//*************************************************************
|
|
//
|
|
// StringToIntA
|
|
//
|
|
// Purpose: atoi
|
|
//
|
|
// Parameters: LPSTR sz - pointer of string to convert
|
|
//
|
|
// Return: void
|
|
//
|
|
// WARNING: Unlike StringToInt, this one does not skip leading
|
|
// white space
|
|
//
|
|
//*************************************************************
|
|
int StringToIntA( LPSTR sz ) {
|
|
int i = 0;
|
|
|
|
while( IsDigit( *sz ) ) {
|
|
i = i * 10 + (*sz - '0');
|
|
sz++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// IntToStringA
|
|
//
|
|
// Purpose: itoa
|
|
//
|
|
// Parameters: INT i - integer to convert
|
|
// LPSTR sz - pointer where to put the result
|
|
//
|
|
// Return: void
|
|
//
|
|
//*************************************************************
|
|
#define CCH_MAX_DEC 12 // Number of chars needed to hold 2^32
|
|
|
|
void IntToStringA( INT i, LPSTR sz) {
|
|
CHAR szTemp[CCH_MAX_DEC];
|
|
int iChr;
|
|
|
|
|
|
iChr = 0;
|
|
|
|
do {
|
|
szTemp[iChr++] = '0' + (i % 10);
|
|
i = i / 10;
|
|
} while (i != 0);
|
|
|
|
do {
|
|
iChr--;
|
|
*sz++ = szTemp[iChr];
|
|
} while (iChr != 0);
|
|
|
|
*sz++ = '\0';
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// CP_MAX_ENV assumes entire env. var. value < maxpath +
|
|
// add 20 for various quotes
|
|
// and 10 more for commas (see list description below)
|
|
////////////////////////////////////////////////////////////////////////////
|
|
#define CP_MAX_ENV (MAX_PATH + 30)
|
|
|
|
CPEnvBuf CPEBOSLoadIdentifier;
|
|
BOOL fAutoLoad;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Identify whether we are running on an x86 system which nevertheless
|
|
// boots using the ARC path (no c:\boot.ini)
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Is_ARCx86(void)
|
|
{
|
|
TCHAR identifier[256];
|
|
ULONG identifierSize = sizeof(identifier);
|
|
HKEY hSystemKey = NULL;
|
|
BOOL rval = FALSE;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("HARDWARE\\DESCRIPTION\\System"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hSystemKey) == ERROR_SUCCESS) {
|
|
if ((RegQueryValueEx(hSystemKey,
|
|
TEXT("Identifier"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) identifier,
|
|
&identifierSize) == ERROR_SUCCESS) &&
|
|
(wcsstr(identifier, TEXT("ARCx86")) != NULL)) {
|
|
rval = TRUE;
|
|
}
|
|
RegCloseKey(hSystemKey);
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine will query the ARC NVRAM for an option passed
|
|
// in szName and fill in the argv style pointer passed in.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL GetRGSZEnvVar(CPEnvBuf * pEnvBuf, PCHAR pszName)
|
|
{
|
|
CHAR *pszCur, *p;
|
|
int cb, i;
|
|
CHAR *rgtmp[1];
|
|
CHAR rgchOut[CP_MAX_ENV*MAX_BOOT_ENTRIES];
|
|
|
|
// GetNVRAMVar takes an argv[] style paramater as input, so crock
|
|
// one up.
|
|
rgtmp[0] = pszName;
|
|
|
|
// GetNVRAMVar returns a 'list' of the form
|
|
// open-curly"string1","string2","string3"close-curly
|
|
//
|
|
// an empty environment string will be 5 bytes:
|
|
// open-curly""close-curly[null-terminator]
|
|
|
|
cb = fpGetNVRAMvar (rgtmp, (USHORT)1,
|
|
rgchOut, (USHORT) CP_MAX_ENV*MAX_BOOT_ENTRIES);
|
|
|
|
pEnvBuf->cEntries = 0;
|
|
|
|
// if cb was equal to 5, the string was empty (see above comment)
|
|
if (cb > 5)
|
|
{
|
|
// break the string up into array of separate strings that
|
|
// can be put into a listbox.
|
|
pszCur = rgchOut;
|
|
|
|
// skip first open-curly brace
|
|
pszCur++;
|
|
|
|
// counter for array of strings
|
|
i = 0;
|
|
while (*pszCur != '}')
|
|
{
|
|
p = pEnvBuf->pszVars[i] = MemAlloc (LPTR, MAX_PATH);
|
|
|
|
// PREFIX change to prevent a potential NULL dereference
|
|
if (!p)
|
|
{
|
|
pEnvBuf->cEntries = i;
|
|
return FALSE;
|
|
}
|
|
|
|
// skip first quote
|
|
pszCur++;
|
|
while (*pszCur != '"')
|
|
*p++ = *pszCur++;
|
|
|
|
// skip the close quote
|
|
pszCur++;
|
|
|
|
// null terminate destination
|
|
*p = '\0';
|
|
|
|
// skip the comma if not at end of string
|
|
if (*pszCur == ',')
|
|
{
|
|
pszCur++;
|
|
// and go to next string
|
|
}
|
|
i++;
|
|
}
|
|
pEnvBuf->cEntries = i;
|
|
}
|
|
|
|
return pEnvBuf->cEntries;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine will free the memory allocated by GetRGSZEnvVar
|
|
//
|
|
// History:
|
|
// 22-Apr-1996 JonPa Created it.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void FreeRGSZEnvVar(CPEnvBuf * pEnvBuf) {
|
|
int i;
|
|
|
|
for( i = 0; i < pEnvBuf->cEntries; i++ ) {
|
|
MemFree( pEnvBuf->pszVars[i] );
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// The user has made a choice among the entries.
|
|
// Now we have to arrange all the strings stored in NVRAM so
|
|
// that they have the same ordering. The selection is passed in,
|
|
// so what this function does is if selection is M, it makes the Mth item
|
|
// appear first in each of the 5 environment strings and the other items
|
|
// follow it in the list.
|
|
//
|
|
// Then if the timeout button is checked, it updates the AUTOLOAD variable
|
|
// to "yes" and set the COUNTDOWN variable to the number of seconds in the
|
|
// edit control.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL UpdateNVRAM(HWND hdlg, int selection, int timeout)
|
|
{
|
|
CHAR *rgszVRAM[5] = { "SYSTEMPARTITION",
|
|
"OSLOADER",
|
|
"OSLOADPARTITION",
|
|
"OSLOADFILENAME",
|
|
"OSLOADOPTIONS"
|
|
};
|
|
CPEnvBuf rgcpeb[5];
|
|
|
|
|
|
WRITENVRAMPROC fpWriteNVRAMVar;
|
|
int iTemp, jTemp;
|
|
CHAR *pszSwap;
|
|
CHAR szTemp[10];
|
|
HMODULE hmodSetupDLL;
|
|
BOOL bChecked;
|
|
|
|
// args and charray are needed for call to SetNVRamVar() in SETUP
|
|
PSZ args[2];
|
|
CHAR chArray[CP_MAX_ENV*MAX_BOOT_ENTRIES];
|
|
PSZ pszReturn;
|
|
|
|
if ((hmodSetupDll = LoadLibrary (TEXT("setupdll"))) == NULL)
|
|
return(FALSE);
|
|
|
|
fpWriteNVRAMVar = (WRITENVRAMPROC) GetProcAddress(hmodSetupDll, "SetNVRAMVar");
|
|
if (fpWriteNVRAMVar == NULL)
|
|
return(FALSE);
|
|
|
|
// 0 is always the selection when the dialog is brought up,
|
|
// so as an optimization don't update the nvram if it's
|
|
// not necessary.
|
|
if (selection != 0)
|
|
{
|
|
// read in the strings from NVRAM. the number of strings (other than
|
|
// LOADIDENTIFIER is 5)
|
|
for (iTemp = 0; iTemp < 5; iTemp++)
|
|
{
|
|
GetRGSZEnvVar (&rgcpeb[iTemp], rgszVRAM[iTemp]);
|
|
// now re-order the strings to swap the 'selection-th' item
|
|
// string with the first string.
|
|
pszSwap = rgcpeb[iTemp].pszVars[0];
|
|
rgcpeb[iTemp].pszVars[0] = rgcpeb[iTemp].pszVars[selection];
|
|
rgcpeb[iTemp].pszVars[selection] = pszSwap;
|
|
}
|
|
// now do the same for the LOADIDENTIFIER, (this was set up earlier
|
|
// in the processing the INITDIALOG message).
|
|
pszSwap = CPEBOSLoadIdentifier.pszVars[0];
|
|
CPEBOSLoadIdentifier.pszVars[0] = CPEBOSLoadIdentifier.pszVars[selection];
|
|
CPEBOSLoadIdentifier.pszVars[selection] = pszSwap;
|
|
|
|
// now write to NVRAM: first write LOADIDENTIFIER, then the other 5
|
|
// variables.
|
|
args[0] = (PSZ)"LOADIDENTIFIER";
|
|
args[1] = chArray;
|
|
|
|
chArray[0] = '\0';
|
|
for (iTemp = 0; iTemp < CPEBOSLoadIdentifier.cEntries; iTemp++)
|
|
{
|
|
lstrcatA (chArray, CPEBOSLoadIdentifier.pszVars[iTemp]);
|
|
lstrcatA (chArray, ";");
|
|
}
|
|
// remove the last semi-colon:
|
|
chArray[lstrlenA(chArray)-1] = '\0';
|
|
|
|
fpWriteNVRAMVar ((DWORD)2, args, &pszReturn);
|
|
|
|
for (iTemp = 0; iTemp < 5; iTemp++)
|
|
{
|
|
args[0] = rgszVRAM[iTemp];
|
|
args[1] = chArray;
|
|
chArray[0] = '\0';
|
|
for (jTemp = 0; jTemp < rgcpeb[iTemp].cEntries; jTemp++)
|
|
{
|
|
lstrcatA (chArray, rgcpeb[iTemp].pszVars[jTemp]);
|
|
lstrcatA (chArray, ";");
|
|
}
|
|
chArray[lstrlenA(chArray)-1] = '\0';
|
|
|
|
fpWriteNVRAMVar ((DWORD)2, args, &pszReturn);
|
|
|
|
// We are done with this variable... Free the resources it consumes
|
|
FreeRGSZEnvVar( &rgcpeb[iTemp] );
|
|
}
|
|
|
|
}
|
|
args[0] = "AUTOLOAD";
|
|
if (bChecked = IsDlgButtonChecked (hdlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN))
|
|
args[1] = "YES";
|
|
else
|
|
args[1] = "";
|
|
|
|
fpWriteNVRAMVar ((DWORD)2, args, &pszReturn);
|
|
// This is a temporary hack workaround for the fact that the
|
|
// AUTOLOAD variable seems to be broken on Alpha
|
|
// if (bChecked)
|
|
// {
|
|
args[0] = "COUNTDOWN";
|
|
IntToStringA(timeout, szTemp);
|
|
args[1] = szTemp;
|
|
fpWriteNVRAMVar ((DWORD)2, args, &pszReturn);
|
|
// }
|
|
FreeLibrary (hmodSetupDll);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine frees allocations related to EFI Boot Manager information
|
|
// from NVRAM.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
FreeEfiBootEntries (
|
|
VOID
|
|
)
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
PMY_BOOT_ENTRY myBootEntry;
|
|
|
|
while (!IsListEmpty(&BootEntries)) {
|
|
listEntry = RemoveHeadList(&BootEntries);
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
MemFree(myBootEntry);
|
|
}
|
|
if (BootEntryList != NULL) {
|
|
MemFree(BootEntryList);
|
|
BootEntryList = NULL;
|
|
}
|
|
if (BootOptions != NULL) {
|
|
MemFree(BootOptions);
|
|
BootOptions = NULL;
|
|
}
|
|
|
|
return;
|
|
|
|
} // FreeEfiBootEntries
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine reads EFI Boot Manager information from NVRAM.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
ReadEfiBootEntries (
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG length;
|
|
ULONG count;
|
|
PULONG order = NULL;
|
|
PBOOT_ENTRY_LIST bootEntryList;
|
|
PBOOT_ENTRY bootEntry;
|
|
PMY_BOOT_ENTRY myBootEntry;
|
|
PLIST_ENTRY listEntry;
|
|
LONG i;
|
|
BOOLEAN wasEnabled;
|
|
BOOL retval = FALSE;
|
|
|
|
InitializeListHead(&BootEntries);
|
|
|
|
//
|
|
// Enable the privilege that is necessary to query NVRAM.
|
|
//
|
|
|
|
status = RtlAdjustPrivilege(
|
|
SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&wasEnabled
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the global system boot options.
|
|
//
|
|
length = 0;
|
|
status = NtQueryBootOptions(NULL, &length);
|
|
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
BootOptions = MemAlloc(LPTR, length);
|
|
if (BootOptions == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
status = NtQueryBootOptions(BootOptions, &length);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the system boot order list.
|
|
//
|
|
count = 0;
|
|
status = NtQueryBootEntryOrder(NULL, &count);
|
|
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// There are no entries in the boot order list. Strange but
|
|
// possible.
|
|
//
|
|
count = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// An unexpected error occurred.
|
|
//
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
if (count != 0) {
|
|
|
|
order = MemAlloc(LPTR, count * sizeof(ULONG));
|
|
if (order == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
status = NtQueryBootEntryOrder(order, &count);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
|
|
//
|
|
// An unexpected error occurred.
|
|
//
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get all existing boot entries.
|
|
//
|
|
length = 0;
|
|
status = NtEnumerateBootEntries(NULL, &length);
|
|
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Somehow there are no boot entries in NVRAM.
|
|
//
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
//
|
|
// An unexpected error occurred.
|
|
//
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ASSERT(length != 0);
|
|
|
|
BootEntryList = MemAlloc(LPTR, length);
|
|
if (BootEntryList == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
status = NtEnumerateBootEntries(BootEntryList, &length);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
ASSERT(FALSE);
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// Convert the boot entries into our internal representation.
|
|
//
|
|
bootEntryList = BootEntryList;
|
|
|
|
while (TRUE) {
|
|
|
|
bootEntry = &bootEntryList->BootEntry;
|
|
|
|
//
|
|
// Allocate an internal structure for the boot entry.
|
|
//
|
|
myBootEntry = MemAlloc(LPTR, sizeof(MY_BOOT_ENTRY));
|
|
if (myBootEntry == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
RtlZeroMemory(myBootEntry, sizeof(MY_BOOT_ENTRY));
|
|
|
|
//
|
|
// Save the address of the NT boot entry.
|
|
//
|
|
myBootEntry->NtBootEntry = bootEntry;
|
|
|
|
//
|
|
// Save the address of the entry's friendly name.
|
|
//
|
|
myBootEntry->FriendlyName = ADD_OFFSET(bootEntry, FriendlyNameOffset);
|
|
|
|
//
|
|
// Link the new entry into the list.
|
|
//
|
|
InsertTailList(&BootEntries, &myBootEntry->ListEntry);
|
|
|
|
//
|
|
// Move to the next entry in the enumeration list, if any.
|
|
//
|
|
if (bootEntryList->NextEntryOffset == 0) {
|
|
break;
|
|
}
|
|
bootEntryList = ADD_OFFSET(bootEntryList, NextEntryOffset);
|
|
}
|
|
|
|
//
|
|
// Boot entries are returned in an unspecified order. They are currently
|
|
// in the SpBootEntries list in the order in which they were returned.
|
|
// Sort the boot entry list based on the boot order. Do this by walking
|
|
// the boot order array backwards, reinserting the entry corresponding to
|
|
// each element of the array at the head of the list.
|
|
//
|
|
|
|
for (i = (LONG)count - 1; i >= 0; i--) {
|
|
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
|
|
if (myBootEntry->NtBootEntry->Id == order[i] ) {
|
|
|
|
//
|
|
// We found the boot entry with this ID. Move it to the
|
|
// front of the list.
|
|
//
|
|
|
|
myBootEntry->Ordered = TRUE;
|
|
|
|
RemoveEntryList(&myBootEntry->ListEntry);
|
|
InsertHeadList(&BootEntries, &myBootEntry->ListEntry);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the boot order list.
|
|
//
|
|
if (count != 0) {
|
|
MemFree(order);
|
|
order = NULL;
|
|
}
|
|
|
|
//
|
|
// We don't want to show entries that are not in the boot order list.
|
|
// We don't want to show removable media entries (for floppy or CD).
|
|
// We do show non-NT entries.
|
|
//
|
|
count = 0;
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
|
|
if (myBootEntry->Ordered &&
|
|
((myBootEntry->NtBootEntry->Attributes & BOOT_ENTRY_ATTRIBUTE_REMOVABLE_MEDIA) == 0)) {
|
|
myBootEntry->Show = TRUE;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we don't have any entries to show, disable the dialog box entirely.
|
|
//
|
|
if (count == 0) {
|
|
goto error;
|
|
}
|
|
|
|
retval = TRUE;
|
|
|
|
done:
|
|
|
|
if (!wasEnabled) {
|
|
status = RtlAdjustPrivilege(
|
|
SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
|
|
FALSE,
|
|
FALSE,
|
|
&wasEnabled
|
|
);
|
|
}
|
|
|
|
return retval;
|
|
|
|
error:
|
|
|
|
//
|
|
// An error occurred. Clean up all allocations.
|
|
//
|
|
if (order != NULL) {
|
|
MemFree(order);
|
|
}
|
|
FreeEfiBootEntries();
|
|
|
|
goto done;
|
|
|
|
} // ReadEfiBootEntries
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EFI version of UpdateNVRAM.
|
|
//
|
|
// The user has made a choice among the entries. Rewrite the boot order
|
|
// list to put the user's selection at the front. Also update the Timeout
|
|
// variable.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
WriteEfiBootEntries (
|
|
HWND hdlg,
|
|
int selection,
|
|
int timeout
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN wasEnabled;
|
|
BOOL retval = FALSE;
|
|
|
|
//
|
|
// Enable the privilege that is necessary to query NVRAM.
|
|
//
|
|
|
|
status = RtlAdjustPrivilege(
|
|
SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&wasEnabled
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 0 is always the selection when the dialog is brought up,
|
|
// so as an optimization don't update the nvram if it's
|
|
// not necessary.
|
|
//
|
|
if (selection != 0) {
|
|
|
|
//
|
|
// Walk the boot entry list, looking for (a) the entry with combo box
|
|
// index 0, and (b) the selected entry. We want to swap these two
|
|
// entries.
|
|
//
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PMY_BOOT_ENTRY myBootEntry;
|
|
PMY_BOOT_ENTRY firstEntry = NULL;
|
|
PMY_BOOT_ENTRY selectedEntry = NULL;
|
|
PLIST_ENTRY previousEntry;
|
|
ULONG count;
|
|
PULONG order;
|
|
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
|
|
if (myBootEntry->Show) {
|
|
if (myBootEntry->Index == 0) {
|
|
firstEntry = myBootEntry;
|
|
} else if (myBootEntry->Index == selection) {
|
|
selectedEntry = myBootEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(firstEntry != NULL);
|
|
ASSERT(selectedEntry != NULL);
|
|
ASSERT(selectedEntry != firstEntry);
|
|
|
|
//
|
|
// Swap the entries. Capture the address of the entry before the first
|
|
// entry (which might be the list head). Remove the first entry from
|
|
// the list and insert it after the selected entry. Remove the selected
|
|
// entry from the list and insert it after the captured entry.
|
|
//
|
|
|
|
previousEntry = firstEntry->ListEntry.Blink;
|
|
RemoveEntryList(&firstEntry->ListEntry);
|
|
InsertHeadList(&selectedEntry->ListEntry, &firstEntry->ListEntry);
|
|
RemoveEntryList(&selectedEntry->ListEntry);
|
|
InsertHeadList(previousEntry, &selectedEntry->ListEntry);
|
|
|
|
//
|
|
// Build the new boot order list. Insert all ordered boot entries
|
|
// into the list.
|
|
//
|
|
count = 0;
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
if (myBootEntry->Ordered) {
|
|
count++;
|
|
}
|
|
}
|
|
order = MemAlloc(LPTR, count * sizeof(ULONG));
|
|
if (order == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
count = 0;
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
myBootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
if (myBootEntry->Ordered) {
|
|
order[count++] = myBootEntry->NtBootEntry->Id;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write the new boot entry order list to NVRAM.
|
|
//
|
|
status = NtSetBootEntryOrder(order, count);
|
|
MemFree(order);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write the new timeout value to NVRAM.
|
|
//
|
|
if (!IsDlgButtonChecked(hdlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN)) {
|
|
timeout = 0xffffffff;
|
|
}
|
|
|
|
if (timeout != BootOptions->Timeout) {
|
|
|
|
BootOptions->Timeout = timeout;
|
|
|
|
status = NtSetBootOptions(BootOptions, BOOT_OPTIONS_FIELD_TIMEOUT);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
retval = TRUE;
|
|
|
|
done:
|
|
|
|
if (!wasEnabled) {
|
|
status = RtlAdjustPrivilege(
|
|
SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
|
|
FALSE,
|
|
FALSE,
|
|
&wasEnabled
|
|
);
|
|
}
|
|
|
|
return retval;
|
|
|
|
} // WriteEfiBootEntries
|
|
|
|
#endif // defined(EFI_NVRAM_ENABLED)
|
|
|
|
#ifdef _X86_
|
|
BOOL WriteableBootIni( LPTSTR szBootIni, HWND hDlg ) {
|
|
BOOL bOK;
|
|
DWORD dwFileAttr;
|
|
HANDLE hFile;
|
|
|
|
bOK = TRUE;
|
|
|
|
// Change Read-only file attrs on Boot.ini file if necessary
|
|
if ((dwFileAttr = GetFileAttributes (szBootIni)) != 0xFFFFFFFF) {
|
|
if (dwFileAttr & FILE_ATTRIBUTE_READONLY) {
|
|
if (!SetFileAttributes (szBootIni, dwFileAttr & ~FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bOK)
|
|
{
|
|
|
|
hFile = CreateFile( szBootIni, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFile);
|
|
} else {
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND) {
|
|
MsgBoxParam (hDlg, IDS_SYSDM_CANNOTOPENFILE, IDS_SYSDM_TITLE, MB_OK | MB_ICONEXCLAMATION, szBootIni);
|
|
}
|
|
bOK = FALSE;
|
|
}
|
|
|
|
// Restore read-only attr, if necessary, after writes
|
|
if (dwFileAttr != 0xFFFFFFFF && (dwFileAttr & FILE_ATTRIBUTE_READONLY)) {
|
|
SetFileAttributes (szBootIni, dwFileAttr);
|
|
}
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
#endif
|
|
|
|
void StartListInit( HWND hDlg, WPARAM wParam, LPARAM lParam ) {
|
|
HWND hwndTemp;
|
|
HMODULE hmodSetupDll;
|
|
int iTemp;
|
|
int n;
|
|
#ifdef _X86_
|
|
int i, timeout;
|
|
TCHAR szTemp2[MAX_PATH];
|
|
int selection;
|
|
TCHAR *pszKeyName;
|
|
LPTSTR pszLine;
|
|
TCHAR *pszValue;
|
|
TCHAR *pszTemp;
|
|
LPTSTR lpKey = NULL;
|
|
|
|
// ANSI string pointers
|
|
|
|
LPSTR pszSectionA;
|
|
#endif
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
|
|
if (IsEfi()) {
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_SYS_EDIT_BUTTION), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_STARTUP_SYS_EDIT_LABEL), FALSE);
|
|
|
|
hwndTemp = GetDlgItem (hDlg, IDC_STARTUP_SYS_OS);
|
|
|
|
fCanUpdateNVRAM = ReadEfiBootEntries();
|
|
|
|
if (fCanUpdateNVRAM) {
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PMY_BOOT_ENTRY bootEntry;
|
|
|
|
for (listEntry = BootEntries.Flink;
|
|
listEntry != &BootEntries;
|
|
listEntry = listEntry->Flink) {
|
|
bootEntry = CONTAINING_RECORD(listEntry, MY_BOOT_ENTRY, ListEntry);
|
|
if (bootEntry->Show) {
|
|
bootEntry->Index = (int)SendMessage (hwndTemp, CB_ADDSTRING, 0,
|
|
(LPARAM)bootEntry->FriendlyName);
|
|
}
|
|
}
|
|
|
|
// the first one is the selection we want (offset 0)
|
|
SendMessage (hwndTemp, CB_SETCURSEL, 0, 0L);
|
|
nOriginalSelection = 0;
|
|
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECONDS,
|
|
EM_LIMITTEXT, 3, 0L);
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECSCROLL,
|
|
UDM_SETRANGE, 0, (LPARAM)MAKELONG(999,0));
|
|
|
|
if (BootOptions->Timeout != 0xffffffff) {
|
|
|
|
if (BootOptions->Timeout > 999) {
|
|
BootOptions->Timeout = 999;
|
|
}
|
|
|
|
SetDlgItemInt(
|
|
hDlg,
|
|
IDC_STARTUP_SYS_SECONDS,
|
|
BootOptions->Timeout,
|
|
FALSE
|
|
);
|
|
CheckDlgButton (hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN, TRUE);
|
|
|
|
} else {
|
|
|
|
SetDlgItemInt(
|
|
hDlg,
|
|
IDC_STARTUP_SYS_SECONDS,
|
|
0,
|
|
FALSE
|
|
);
|
|
CheckDlgButton (hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN, FALSE);
|
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_SYS_SECONDS), FALSE);
|
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE);
|
|
}
|
|
|
|
} else {
|
|
|
|
// if can't set variables (no privilege), disable controls
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS_LABEL), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE);
|
|
EnableWindow (hwndTemp, FALSE);
|
|
}
|
|
|
|
} else
|
|
|
|
#endif // defined(EFI_NVRAM_ENABLED)
|
|
|
|
#ifdef _X86_
|
|
if (Is_ARCx86())
|
|
#endif
|
|
{
|
|
////////////////////////////////////////////////////////////////////
|
|
// Read info from NVRAM environment variables
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Init to 0 so we won't try to free garbage if we cant load setup.dll
|
|
CPEBOSLoadIdentifier.cEntries = 0;
|
|
|
|
fCanUpdateNVRAM = FALSE;
|
|
fAutoLoad = FALSE;
|
|
hwndTemp = GetDlgItem (hDlg, IDC_STARTUP_SYS_OS);
|
|
if (hmodSetupDll = LoadLibrary(TEXT("setupdll")))
|
|
{
|
|
if (fpGetNVRAMvar = (GETNVRAMPROC)GetProcAddress(hmodSetupDll, "GetNVRAMVar"))
|
|
{
|
|
if (fCanUpdateNVRAM = GetRGSZEnvVar (&CPEBOSLoadIdentifier, "LOADIDENTIFIER"))
|
|
{
|
|
for (iTemp = 0; iTemp < CPEBOSLoadIdentifier.cEntries; iTemp++)
|
|
n = (int)SendMessageA (hwndTemp, CB_ADDSTRING, 0,
|
|
(LPARAM)CPEBOSLoadIdentifier.pszVars[iTemp]);
|
|
// the first one is the selection we want (offset 0)
|
|
SendMessage (hwndTemp, CB_SETCURSEL, 0, 0L);
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECONDS,
|
|
EM_LIMITTEXT, 3, 0L);
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECSCROLL,
|
|
UDM_SETRANGE, 0, (LPARAM)MAKELONG(999,0));
|
|
|
|
}
|
|
// fCanUpdateNVRAM is a global that gets set up above
|
|
if (fCanUpdateNVRAM)
|
|
{
|
|
// This is a temporary hack workaround for the
|
|
// fact that the AUTOLOAD variable seems to
|
|
// be broken on Alpha
|
|
CPEnvBuf cpebTimeout;
|
|
int timeout;
|
|
|
|
if (GetRGSZEnvVar(&cpebTimeout, "COUNTDOWN")) {
|
|
timeout = StringToIntA(cpebTimeout.pszVars[0]);
|
|
fAutoLoad = (BOOL) timeout;
|
|
SetDlgItemInt(
|
|
hDlg,
|
|
IDC_STARTUP_SYS_SECONDS,
|
|
timeout,
|
|
FALSE
|
|
);
|
|
FreeRGSZEnvVar(&cpebTimeout);
|
|
} // if
|
|
#if 0
|
|
CPEnvBuf cpebAutoLoad, cpebTimeout;
|
|
// is Autoload == YES? if so, check the checkbox
|
|
// and read setting for timeouts
|
|
// autoload == NO? disable edit control.
|
|
if (GetRGSZEnvVar (&cpebAutoLoad, "AUTOLOAD"))
|
|
{
|
|
if (!lstrcmpiA (cpebAutoLoad.pszVars[0], "yes"))
|
|
{
|
|
fAutoLoad = TRUE;
|
|
if (GetRGSZEnvVar (&cpebTimeout, "COUNTDOWN")) {
|
|
SetDlgItemInt (hDlg, IDC_STARTUP_SYS_SECONDS,
|
|
StringToIntA (cpebTimeout.pszVars[0]), FALSE);
|
|
|
|
// We are done with cpebTimeout... Free the resources it consumes
|
|
FreeRGSZEnvVar(&cpebTimeout);
|
|
}
|
|
|
|
}
|
|
|
|
// We are done with cpebTimeout... Free the resources it consumes
|
|
FreeRGSZEnvVar(&cpebAutoLoad);
|
|
}
|
|
#endif //0
|
|
CheckDlgButton (hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN, fAutoLoad);
|
|
if (!fAutoLoad)
|
|
{
|
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_SYS_SECONDS), FALSE);
|
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE);
|
|
}
|
|
}
|
|
}
|
|
FreeLibrary (hmodSetupDll);
|
|
}
|
|
if (!fCanUpdateNVRAM) {
|
|
// if can't set variables (no privilege), disable controls
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS_LABEL), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_OS), FALSE);
|
|
}
|
|
|
|
// default to 5 seconds for now.
|
|
}
|
|
#ifdef _X86_
|
|
else
|
|
{
|
|
////////////////////////////////////////////////////////////////////
|
|
// Read info from boot.ini file and initialize OS Group box items
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
InitializeArcStuff();
|
|
|
|
//
|
|
// Get correct Boot Drive - this was added because after someone
|
|
// boots the system, they can ghost or change the drive letter
|
|
// of their boot drive from "c:" to something else.
|
|
//
|
|
|
|
if (IsNEC_98)
|
|
{
|
|
//
|
|
// For NEC PC98.
|
|
// For Install NT to non C: drive.
|
|
// Get drive letter of system directory.
|
|
//
|
|
if ((HIBYTE(LOWORD(GetKeyboardType(1))) & 0xff) == NLSKBD_OEM_NEC) {
|
|
TCHAR szSystemDirectory[MAX_PATH];
|
|
GetSystemDirectory (szSystemDirectory, ARRAYSIZE(szSystemDirectory));
|
|
szBootIni[0] = szSystemDirectory[0];
|
|
} else {
|
|
//
|
|
// PC/AT
|
|
//
|
|
// szBootIni[0] = GetBootDrive();
|
|
szBootIni[0] = x86DetermineSystemPartition (hDlg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// szBootIni[0] = GetBootDrive();
|
|
szBootIni[0] = x86DetermineSystemPartition (hDlg);
|
|
}
|
|
|
|
szBootIniA[0] = (char) szBootIni[0];
|
|
|
|
//
|
|
// Make sure we have access to BOOT.INI
|
|
//
|
|
if (!WriteableBootIni(szBootIni, hDlg)) {
|
|
// if can't set variables (no privilege), disable controls
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS_LABEL), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE);
|
|
EnableWindow (GetDlgItem(hDlg, IDC_STARTUP_SYS_OS), FALSE);
|
|
}
|
|
|
|
//
|
|
// Determine which section [boot loader]
|
|
// [flexboot]
|
|
// or [multiboot] is in file
|
|
//
|
|
n = GetPrivateProfileString (szBootLdr, NULL, NULL, szTemp2,
|
|
ARRAYSIZE(szTemp2), szBootIni);
|
|
if (n != 0)
|
|
pszBoot = szBootLdr;
|
|
else
|
|
{
|
|
n = GetPrivateProfileString (szFlexBoot, NULL, NULL, szTemp2,
|
|
ARRAYSIZE(szTemp2), szBootIni);
|
|
if (n != 0)
|
|
pszBoot = szFlexBoot;
|
|
else
|
|
{
|
|
n = GetPrivateProfileString (szMultiBoot, NULL, NULL, szTemp2,
|
|
ARRAYSIZE(szTemp2), szBootIni);
|
|
if (n != 0)
|
|
{
|
|
pszBoot = szMultiBoot;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This final case is here because I want to DEFAULT
|
|
// to "[boot loader]" as the section name to use in
|
|
// the event that we do not find any section in the
|
|
// boot.ini file.
|
|
//
|
|
|
|
pszBoot = szBootLdr;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Get info under [*pszBoot] section - timeout & default OS path
|
|
|
|
timeout = GetPrivateProfileInt (pszBoot, szTimeout, 0, szBootIni);
|
|
|
|
SetDlgItemInt (hDlg, IDC_STARTUP_SYS_SECONDS, timeout, FALSE);
|
|
|
|
nOriginalTimeout = timeout;
|
|
|
|
//
|
|
// Get the "Default" os selection
|
|
//
|
|
|
|
szTemp2[0] = TEXT('\0');
|
|
|
|
GetPrivateProfileString (pszBoot, szDefault, NULL, szTemp2,
|
|
ARRAYSIZE(szTemp2), szBootIni);
|
|
|
|
//
|
|
// Display all choices under [operating system] in boot.ini file
|
|
// in combobox for selection
|
|
//
|
|
|
|
hwndTemp = GetDlgItem (hDlg, IDC_STARTUP_SYS_OS);
|
|
|
|
selection = -1;
|
|
|
|
//
|
|
// ANSI Buffer!
|
|
//
|
|
|
|
pszSectionA = (LPSTR) MemAlloc (LPTR, BUFZ);
|
|
|
|
|
|
//
|
|
// Get entire section under OS to properly show user choices
|
|
//
|
|
|
|
n = GetPrivateProfileSectionA (szOSA, pszSectionA, BUFZ, szBootIniA);
|
|
|
|
if ((n >= BUFZ-2) || (n == 0))
|
|
{
|
|
ErrorReadingSection:
|
|
// Error reading data
|
|
MemFree ((LPVOID)pszSectionA);
|
|
goto ContinueSystemInit;
|
|
}
|
|
|
|
//
|
|
// Check for api errors and NoOptions
|
|
//
|
|
|
|
if ((pszSectionA == NULL) || ((*pszSectionA == '\0') && (*(pszSectionA+1) == '\0')))
|
|
goto ErrorReadingSection;
|
|
|
|
|
|
lpKey = MemAlloc (LPTR, BUFZ*sizeof(TCHAR));
|
|
pszKeyName = lpKey;
|
|
|
|
//
|
|
// Convert entire buffer from OEM to UNICODE
|
|
//
|
|
|
|
MultiByteToWideChar (CP_OEMCP, MB_PRECOMPOSED, pszSectionA, n+2, pszKeyName, BUFZ);
|
|
|
|
MemFree ((LPVOID)pszSectionA);
|
|
|
|
//
|
|
// Continue until we reach end of buffer, marked by Double '\0'
|
|
//
|
|
|
|
while (*(pszKeyName+1) != TEXT('\0'))
|
|
{
|
|
pszLine = pszKeyName;
|
|
|
|
//
|
|
// Get pointer to next line in buffer.
|
|
//
|
|
|
|
pszKeyName += lstrlen (pszKeyName) + 1;
|
|
|
|
//
|
|
// Find LHS/RHS delimiter to separate strings
|
|
//
|
|
|
|
pszValue = StrStr(pszLine, TEXT("="));
|
|
|
|
if (pszValue && (pszValue != pszLine))
|
|
{
|
|
*pszValue = '\0';
|
|
pszValue++;
|
|
}
|
|
else
|
|
{
|
|
pszValue = pszLine;
|
|
}
|
|
|
|
//
|
|
// Put it into combobox (if no descriptive name, use path)
|
|
//
|
|
|
|
n = (int)SendMessage (hwndTemp, CB_ADDSTRING, 0, (LPARAM) (LPTSTR) pszValue);
|
|
|
|
//
|
|
// Find the first selection that matches the "default" selection
|
|
//
|
|
|
|
if ((selection == -1) && !lstrcmp (pszLine, szTemp2))
|
|
selection = n;
|
|
|
|
//
|
|
// Also attach pointer to KeyName (i.e. boot path) to each item
|
|
//
|
|
|
|
pszTemp = CloneString (pszLine);
|
|
|
|
SendMessage (hwndTemp, CB_SETITEMDATA, n, (LPARAM)pszTemp);
|
|
}
|
|
|
|
// If no selection was found up to this point, choose 0, because
|
|
// that is the default value that loader would choose.
|
|
|
|
if (selection == -1)
|
|
selection = 0;
|
|
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECONDS, EM_LIMITTEXT, 3, 0L);
|
|
SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECSCROLL,
|
|
UDM_SETRANGE, 0, (LPARAM)MAKELONG(999,0));
|
|
|
|
|
|
// Check or uncheck the checkbox based on the timeout value
|
|
SendDlgItemMessage(
|
|
hDlg,
|
|
IDC_STARTUP_SYS_ENABLECOUNTDOWN,
|
|
BM_SETCHECK,
|
|
(WPARAM) (BOOL) timeout,
|
|
(LPARAM) 0L
|
|
);
|
|
EnableWindow(
|
|
GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS),
|
|
(BOOL) timeout
|
|
);
|
|
EnableWindow(
|
|
GetDlgItem(hDlg, IDC_STARTUP_SYS_SECSCROLL),
|
|
(BOOL) timeout
|
|
);
|
|
|
|
// This call should force correct settings for the checkbox
|
|
// and "Showlist for xx seconds" controls
|
|
nOriginalSelection = selection;
|
|
|
|
SendMessage (hwndTemp, CB_SETCURSEL, selection, 0L);
|
|
|
|
ContinueSystemInit:
|
|
|
|
if (lpKey) {
|
|
MemFree (lpKey);
|
|
}
|
|
}
|
|
#endif // _X86_
|
|
}
|
|
|
|
|
|
//
|
|
// IE. We need to handle CANCEL case.
|
|
//
|
|
int StartListExit(HWND hDlg, WPARAM wParam, LPARAM lParam ) {
|
|
HWND hwndTemp;
|
|
int selection, timeout;
|
|
#ifdef _X86_
|
|
DWORD dwFileAttr;
|
|
BOOL bOK;
|
|
HANDLE hKey;
|
|
TCHAR *pszKeyName;
|
|
int i, n;
|
|
DWORD dwBufz;
|
|
LPSTR pszSectionA;
|
|
TCHAR *pszTemp;
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szTemp2[MAX_PATH];
|
|
int iTemp;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Write new info to boot.ini file
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
hwndTemp = GetDlgItem (hDlg, IDC_STARTUP_SYS_OS);
|
|
|
|
selection = (int)SendMessage (hwndTemp, CB_GETCURSEL, 0, 0L);
|
|
|
|
if ((selection == CB_ERR) || (selection == CB_ERRSPACE))
|
|
selection = nOriginalSelection;
|
|
|
|
timeout = GetDlgItemInt (hDlg, IDC_STARTUP_SYS_SECONDS, NULL, FALSE);
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
if (IsEfi()) {
|
|
if (fCanUpdateNVRAM) {
|
|
|
|
TCHAR szTextNew[MAX_PATH];
|
|
TCHAR szTextTop[MAX_PATH];
|
|
|
|
WriteEfiBootEntries(hDlg, selection, timeout);
|
|
|
|
/*
|
|
* Now reorder list to match NVRAM
|
|
*/
|
|
// Get the current text
|
|
SendMessage( hwndTemp, CB_GETLBTEXT, selection, (LPARAM)szTextNew );
|
|
SendMessage( hwndTemp, CB_GETLBTEXT, 0, (LPARAM)szTextTop );
|
|
|
|
// Set the new text to the 0th entry in the list
|
|
SendMessage( hwndTemp, CB_DELETESTRING, 0, 0 );
|
|
SendMessage( hwndTemp, CB_INSERTSTRING, 0, (LPARAM)szTextNew);
|
|
|
|
// Set old top text selected item
|
|
SendMessage( hwndTemp, CB_DELETESTRING, selection, 0 );
|
|
SendMessage( hwndTemp, CB_INSERTSTRING, selection, (LPARAM)szTextTop);
|
|
|
|
// Now point the current selection back to the top of the list, so it matches
|
|
// what the user just chose
|
|
SendMessage( hwndTemp, CB_SETCURSEL, 0, 0);
|
|
}
|
|
|
|
} else
|
|
#endif // defined(EFI_NVRAM_ENABLED)
|
|
|
|
#ifdef _X86_
|
|
if (Is_ARCx86())
|
|
#endif
|
|
{
|
|
if (fCanUpdateNVRAM) {
|
|
TCHAR szTextNew[MAX_PATH];
|
|
TCHAR szTextTop[MAX_PATH];
|
|
|
|
UpdateNVRAM (hDlg, selection, timeout);
|
|
|
|
/*
|
|
* Now reorder list to match NVRAM
|
|
*/
|
|
// Get the current text
|
|
SendMessage( hwndTemp, CB_GETLBTEXT, selection, (LPARAM)szTextNew );
|
|
SendMessage( hwndTemp, CB_GETLBTEXT, 0, (LPARAM)szTextTop );
|
|
|
|
// Set the new text to the 0th entry in the list
|
|
SendMessage( hwndTemp, CB_DELETESTRING, 0, 0 );
|
|
SendMessage( hwndTemp, CB_INSERTSTRING, 0, (LPARAM)szTextNew);
|
|
|
|
// Set old top text selected item
|
|
SendMessage( hwndTemp, CB_DELETESTRING, selection, 0 );
|
|
SendMessage( hwndTemp, CB_INSERTSTRING, selection, (LPARAM)szTextTop);
|
|
|
|
// Now point the current selection back to the top of the list, so it matches
|
|
// what the user just chose
|
|
SendMessage( hwndTemp, CB_SETCURSEL, 0, 0);
|
|
}
|
|
}
|
|
#ifdef _X86_
|
|
else
|
|
{
|
|
if ((selection != nOriginalSelection) || (timeout != nOriginalTimeout))
|
|
{
|
|
bOK = TRUE;
|
|
|
|
// Change Read-only file attrs on Boot.ini file if necessary
|
|
if ((dwFileAttr = GetFileAttributes (szBootIni)) != 0xFFFFFFFF)
|
|
if (dwFileAttr & FILE_ATTRIBUTE_READONLY)
|
|
if (!SetFileAttributes (szBootIni,
|
|
dwFileAttr & ~FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
BootIniWriteError:
|
|
bOK = FALSE;
|
|
MsgBoxParam (hDlg, IDS_SYSDM_NOCHANGE_BOOTINI, IDS_SYSDM_TITLE, MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
|
|
if (bOK)
|
|
{
|
|
//
|
|
// Write new [operating systems] section and
|
|
// set "default" selection in boot.ini file.
|
|
//
|
|
|
|
if (selection != nOriginalSelection)
|
|
{
|
|
//
|
|
// Allocate buffers for new section
|
|
//
|
|
|
|
hKey = MemAlloc (LPTR, BUFZ*sizeof(TCHAR));
|
|
pszKeyName = (TCHAR *) hKey;
|
|
if (pszKeyName)
|
|
{
|
|
// Total profile section buffer size
|
|
i = dwBufz = 0;
|
|
pszSectionA = (LPSTR) MemAlloc (LPTR, BUFZ);
|
|
if (pszSectionA)
|
|
{
|
|
// Get the User's selection and write it in the
|
|
// section buffer first. Then get all other items.
|
|
pszTemp = (LPTSTR) SendMessage(hwndTemp, CB_GETITEMDATA, selection, 0L);
|
|
|
|
SendMessage (hwndTemp, CB_GETLBTEXT, selection, (LPARAM) (LPTSTR) szTemp);
|
|
|
|
if (pszTemp != (LPTSTR) CB_ERR)
|
|
{
|
|
lstrcpy (pszKeyName, pszTemp);
|
|
lstrcat (pszKeyName, TEXT("="));
|
|
lstrcat (pszKeyName, szTemp);
|
|
|
|
i = lstrlen (pszKeyName) + 1;
|
|
pszKeyName += i;
|
|
|
|
// Set "default" selection in boot.ini file
|
|
if (!WritePrivateProfileString (pszBoot, szDefault, pszTemp, szBootIni))
|
|
{
|
|
goto BootIniWriteError;
|
|
}
|
|
}
|
|
|
|
dwBufz = (DWORD) i;
|
|
|
|
// Get the rest of the selections
|
|
n = (int)SendMessage (hwndTemp, CB_GETCOUNT, 0, 0L);
|
|
if (n != LB_ERR)
|
|
{
|
|
for (iTemp = 0; iTemp < n; iTemp++)
|
|
{
|
|
// Skip the User's selection since we got it
|
|
// above.
|
|
if (iTemp == selection)
|
|
continue;
|
|
|
|
pszTemp = (LPTSTR) SendMessage (hwndTemp, CB_GETITEMDATA, iTemp, 0L);
|
|
|
|
SendMessage (hwndTemp, CB_GETLBTEXT, iTemp, (LPARAM) (LPTSTR) szTemp);
|
|
|
|
if (pszTemp != (LPTSTR) CB_ERR)
|
|
{
|
|
lstrcpy (pszKeyName, pszTemp);
|
|
lstrcat (pszKeyName, TEXT("="));
|
|
lstrcat (pszKeyName, szTemp);
|
|
|
|
i = lstrlen (pszKeyName) + 1;
|
|
pszKeyName += i;
|
|
|
|
dwBufz += (DWORD) i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Double-Null terminate the buffer
|
|
*pszKeyName = TEXT('\0');
|
|
dwBufz++;
|
|
|
|
pszKeyName = (TCHAR *) hKey;
|
|
|
|
// Convert entire buffer from UNICODE to OEM
|
|
WideCharToMultiByte(CP_OEMCP, WC_COMPOSITECHECK, pszKeyName, dwBufz, pszSectionA, BUFZ, NULL, NULL);
|
|
|
|
// Write new section under OS
|
|
if (!WritePrivateProfileSectionA(szOSA, pszSectionA, szBootIniA))
|
|
{
|
|
MemFree((LPVOID)pszSectionA);
|
|
MemFree((LPVOID)hKey);
|
|
goto BootIniWriteError;
|
|
}
|
|
|
|
MemFree ((LPVOID)pszSectionA);
|
|
}
|
|
|
|
MemFree ((LPVOID)hKey);
|
|
}
|
|
}
|
|
|
|
if (timeout != nOriginalTimeout)
|
|
{
|
|
GetDlgItemText (hDlg, IDC_STARTUP_SYS_SECONDS, szTemp2, ARRAYSIZE(szTemp2));
|
|
|
|
if (!CheckVal (hDlg, IDC_STARTUP_SYS_SECONDS, FORMIN, FORMAX, IDS_SYSDM_ENTERSECONDS))
|
|
return RET_BREAK;
|
|
|
|
// Write timeout value to file
|
|
|
|
if (!WritePrivateProfileString (pszBoot, szTimeout,
|
|
szTemp2, szBootIni))
|
|
goto BootIniWriteError;
|
|
}
|
|
|
|
// Restore read-only attr, if necessary, after writes
|
|
if (dwFileAttr != 0xFFFFFFFF && (dwFileAttr & FILE_ATTRIBUTE_READONLY)) {
|
|
SetFileAttributes (szBootIni, dwFileAttr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // _X86_
|
|
|
|
return RET_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
BOOL CheckVal( HWND hDlg, WORD wID, WORD wMin, WORD wMax, WORD wMsgID )
|
|
{
|
|
WORD nVal;
|
|
BOOL bOK;
|
|
HWND hVal;
|
|
WCHAR szTemp[FOR_MAX_LENGTH];
|
|
|
|
if( wMin > wMax )
|
|
{
|
|
nVal = wMin;
|
|
wMin = wMax;
|
|
wMax = nVal;
|
|
}
|
|
|
|
nVal = (WORD) GetDlgItemInt( hDlg, wID, &bOK, FALSE );
|
|
|
|
//
|
|
// This is a hack to make the null string act equivalent to zero
|
|
//
|
|
if (!bOK) {
|
|
bOK = !GetDlgItemTextW( hDlg, wID, szTemp, FOR_MAX_LENGTH );
|
|
}
|
|
|
|
if( !bOK || ( nVal < wMin ) || ( nVal > wMax ) )
|
|
{
|
|
MsgBoxParam( hDlg, wMsgID, IDS_SYSDM_TITLE,
|
|
MB_OK | MB_ICONERROR, wMin, wMax );
|
|
|
|
SendMessage( hDlg, WM_NEXTDLGCTL,
|
|
(WPARAM) ( hVal = GetDlgItem( hDlg, wID ) ), 1L );
|
|
|
|
// SendMessage(hVal, EM_SETSEL, NULL, MAKELONG(0, 32767));
|
|
|
|
SendMessage( hVal, EM_SETSEL, 0, 32767 );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Frees the data (if any) associated with the strings in the combo box
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
void StartListDestroy(HWND hDlg, WPARAM wParam, LPARAM lParam) {
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
if (IsEfi()) {
|
|
FreeEfiBootEntries();
|
|
} else
|
|
#endif // defined(EFI_NVRAM_ENABLED)
|
|
|
|
#ifdef _X86_
|
|
if (Is_ARCx86())
|
|
#endif
|
|
{
|
|
// Reference vars to make compiler happy
|
|
FreeRGSZEnvVar(&CPEBOSLoadIdentifier);
|
|
return;
|
|
|
|
(void)hDlg;
|
|
(void)wParam;
|
|
(void)lParam;
|
|
}
|
|
#ifdef _X86_
|
|
else
|
|
{
|
|
|
|
// Only X86 has data in the combo
|
|
int n;
|
|
HWND hwndTemp;
|
|
int iTemp;
|
|
TCHAR *pszTemp;
|
|
|
|
|
|
//
|
|
// Free strings stored in the listbox
|
|
//
|
|
hwndTemp = GetDlgItem (hDlg, IDC_STARTUP_SYS_OS);
|
|
|
|
n = (int)SendMessage (hwndTemp, CB_GETCOUNT, 0, 0L);
|
|
|
|
if (n != LB_ERR)
|
|
{
|
|
for (iTemp = 0; iTemp < n; iTemp++)
|
|
{
|
|
pszTemp = (LPTSTR) SendMessage (hwndTemp,
|
|
CB_GETITEMDATA,
|
|
iTemp, 0L);
|
|
|
|
if (pszTemp != (LPTSTR) CB_ERR)
|
|
{
|
|
MemFree (pszTemp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // _X86_
|
|
}
|
|
|
|
void AutoAdvancedBootInit( HWND hDlg, WPARAM wParam, LPARAM lParam ) {
|
|
BOOL fEnabled = FALSE;
|
|
UCHAR cTimeout = 0;
|
|
|
|
NTSTATUS status;
|
|
|
|
#ifdef _X86_
|
|
|
|
//
|
|
// Initialize the boot status data.
|
|
//
|
|
|
|
status = RtlLockBootStatusData(&hBootStatusData);
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
|
|
RtlGetSetBootStatusData(hBootStatusData,
|
|
TRUE,
|
|
RtlBsdItemAabEnabled,
|
|
&fEnabled,
|
|
sizeof(BOOL),
|
|
NULL);
|
|
|
|
RtlGetSetBootStatusData(hBootStatusData,
|
|
TRUE,
|
|
RtlBsdItemAabTimeout,
|
|
&cTimeout,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
SetDlgItemInt(hDlg, IDC_STARTUP_AUTOLKG_SECONDS, cTimeout, FALSE);
|
|
CheckDlgButton(hDlg, IDC_STARTUP_AUTOLKG, fEnabled);
|
|
|
|
SendDlgItemMessage(hDlg, IDC_STARTUP_AUTOLKG_SECONDS, EM_LIMITTEXT, 3, 0L);
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_STARTUP_AUTOLKG_SECSCROLL,
|
|
UDM_SETRANGE,
|
|
0,
|
|
(LPARAM)MAKELONG(999,0));
|
|
|
|
|
|
if(!fEnabled) {
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS_LABEL), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECSCROLL), FALSE);
|
|
}
|
|
} else {
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS_LABEL), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECSCROLL), FALSE);
|
|
}
|
|
#else
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS_LABEL), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECONDS), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_STARTUP_AUTOLKG_SECSCROLL), FALSE);
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// IE. We need to handle CANCEL case.
|
|
//
|
|
int AutoAdvancedBootExit(HWND hDlg, WPARAM wParam, LPARAM lParam ) {
|
|
|
|
BOOL fEnabled;
|
|
|
|
UINT iTime;
|
|
UCHAR cTimeout;
|
|
|
|
NTSTATUS status;
|
|
|
|
#if _X86_
|
|
if(LOWORD(wParam) != IDCANCEL) {
|
|
|
|
//
|
|
// Read the setting of the enabled checkbox.
|
|
//
|
|
|
|
fEnabled = IsDlgButtonChecked(hDlg, IDC_STARTUP_AUTOLKG);
|
|
|
|
if(fEnabled) {
|
|
iTime = GetDlgItemInt(hDlg, IDC_STARTUP_AUTOLKG_SECONDS, NULL, FALSE);
|
|
cTimeout = (UCHAR) min(iTime, 0xff);
|
|
}
|
|
|
|
//
|
|
// If we got access in AutoAdvancedBootInit, write the boot status data and exit.
|
|
//
|
|
|
|
if (hBootStatusData)
|
|
{
|
|
RtlGetSetBootStatusData(hBootStatusData,
|
|
FALSE,
|
|
RtlBsdItemAabEnabled,
|
|
&fEnabled,
|
|
sizeof(BOOL),
|
|
NULL);
|
|
|
|
if(fEnabled) {
|
|
RtlGetSetBootStatusData(hBootStatusData,
|
|
FALSE,
|
|
RtlBsdItemAabTimeout,
|
|
&cTimeout,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hBootStatusData)
|
|
{
|
|
RtlUnlockBootStatusData(hBootStatusData);
|
|
hBootStatusData = NULL;
|
|
}
|
|
#endif
|
|
|
|
return RET_CONTINUE;
|
|
}
|