reactos/base/setup/usetup/mui.c
Hermès Bélusca-Maïto bbb04c470a
[USETUP] Implement offline ReactOS registry initialization in USetup (equivalent of mkhive, but using OS functionality).
The rationale is as follows.

We now have the 1st-stage ReactOS setup running with its own registry SYSTEM hive,
similarly to regular ROS running instances (livecd, regular installation...).

The ReactOS-specific SetInstallPathValue() hack, introduced in a76689e9 (r3794)
and 5f973ce0 (r3795), is removed. This hack told the kernel that, during the setup,
it had to "switch" the used registry hives and instead use the ones of the ROS
installation being prepared.

This was really hackish because this means, mixing between registry settings used only
for the setup running instance, that could use different registry settings
than the ones that should be set for the ROS installation being actually performed.

Also, note that in the case of a 1st-stage GUI setup, consisting in running the
LiveCD + the GUI setup program, this situation would be untenable. Note also that
for people willing to use the Setup*** functions exported by setupapi.dll to parse
the registry INF files to initialize the registry of the ROS installation being
prepared, this would be impossible either.

Hence the need to have offline registry modification functionality.

svn path=/branches/setup_improvements/; revision=74766
2018-10-25 00:57:02 +02:00

749 lines
19 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2008 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/mui.c
* PURPOSE: Text-mode setup
* PROGRAMMER:
*/
#include "usetup.h"
#include "muifonts.h"
#include "muilanguages.h"
#define NDEBUG
#include <debug.h>
extern
VOID
PopupError(IN PCCH Text,
IN PCCH Status,
IN PINPUT_RECORD Ir,
IN ULONG WaitEvent);
static
ULONG
FindLanguageIndex(VOID)
{
ULONG lngIndex = 0;
if (SelectedLanguageId == NULL)
{
/* default to english */
return 0;
}
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
return lngIndex;
}
lngIndex++;
} while (MUILanguageList[lngIndex].MuiPages != NULL);
return 0;
}
BOOLEAN
IsLanguageAvailable(
PWCHAR LanguageId)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , LanguageId) == 0)
return TRUE;
lngIndex++;
} while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
static
const MUI_ENTRY *
FindMUIEntriesOfPage(
IN ULONG PageNumber)
{
ULONG muiIndex = 0;
ULONG lngIndex;
const MUI_PAGE * Pages = NULL;
lngIndex = max(FindLanguageIndex(), 0);
Pages = MUILanguageList[lngIndex].MuiPages;
do
{
if (Pages[muiIndex].Number == PageNumber)
return Pages[muiIndex].MuiEntry;
muiIndex++;
}while (Pages[muiIndex].MuiEntry != NULL);
return NULL;
}
static
const MUI_ERROR *
FindMUIErrorEntries(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiErrors;
}
static
const MUI_STRING *
FindMUIStringEntries(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiStrings;
}
LPCWSTR
MUIDefaultKeyboardLayout(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID;
}
PWCHAR
MUIGetGeoID(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].GeoID;
}
const MUI_LAYOUTS *
MUIGetLayoutsList(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiLayouts;
}
VOID
MUIClearPage(
IN ULONG page)
{
const MUI_ENTRY * entry;
int index;
entry = FindMUIEntriesOfPage(page);
if (!entry)
{
PopupError("Error: Failed to find translated page",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
index = 0;
do
{
CONSOLE_ClearStyledText(entry[index].X,
entry[index].Y,
entry[index].Flags,
strlen(entry[index].Buffer));
index++;
}
while (entry[index].Buffer != NULL);
}
VOID
MUIDisplayPage(
IN ULONG page)
{
const MUI_ENTRY * entry;
int index;
entry = FindMUIEntriesOfPage(page);
if (!entry)
{
PopupError("Error: Failed to find translated page",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
index = 0;
do
{
CONSOLE_SetStyledText(entry[index].X,
entry[index].Y,
entry[index].Flags,
entry[index].Buffer);
index++;
}
while (entry[index].Buffer != NULL);
}
VOID
MUIDisplayError(
IN ULONG ErrorNum,
OUT PINPUT_RECORD Ir,
IN ULONG WaitEvent,
...)
{
const MUI_ERROR * entry;
CHAR Buffer[2048];
va_list ap;
if (ErrorNum >= ERROR_LAST_ERROR_CODE)
{
PopupError("Invalid error number provided",
"Press ENTER to continue",
Ir,
POPUP_WAIT_ENTER);
return;
}
entry = FindMUIErrorEntries();
if (!entry)
{
PopupError("Error: Failed to find translated error message",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
va_start(ap, WaitEvent);
vsprintf(Buffer, entry[ErrorNum].ErrorText, ap);
va_end(ap);
PopupError(Buffer,
entry[ErrorNum].ErrorStatus,
Ir,
WaitEvent);
}
LPSTR
MUIGetString(
ULONG Number)
{
ULONG i;
const MUI_STRING * entry;
CHAR szErr[128];
entry = FindMUIStringEntries();
if (entry)
{
for (i = 0; entry[i].Number != 0; i++)
{
if (entry[i].Number == Number)
{
return entry[i].String;
}
}
}
sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
PopupError(szErr,
NULL,
NULL,
POPUP_WAIT_NONE);
return "<nostring>";
}
static
BOOLEAN
AddHotkeySettings(
IN LPCWSTR Hotkey,
IN LPCWSTR LangHotkey,
IN LPCWSTR LayoutHotkey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
ULONG Disposition;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
L".DEFAULT\\Keyboard Layout\\Toggle");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_USERS, NULL),
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)Hotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Language Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)LangHotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Layout Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)LayoutHotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddKbLayoutsToRegistry(
IN const MUI_LAYOUTS *MuiLayouts)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
HANDLE SubKeyHandle;
NTSTATUS Status;
ULONG Disposition;
ULONG uIndex = 0;
ULONG uCount = 0;
WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout";
WCHAR szValueName[3 + 1];
WCHAR szLangID[8 + 1];
// Open the keyboard layout key
RtlInitUnicodeString(&KeyName, szKeyName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_USERS, NULL),
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_CREATE_SUB_KEY,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(NT_SUCCESS(Status))
NtClose(KeyHandle);
else
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
KeyName.MaximumLength = sizeof(szKeyName);
Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlAppend failed! (%lx)\n", Status);
DPRINT1("String is %wZ\n", &KeyName);
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_USERS, NULL),
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
RtlInitUnicodeString(&KeyName, L".DEFAULT\\Keyboard Layout\\Substitutes");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_USERS, NULL),
NULL);
Status = NtCreateKey(&SubKeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
do
{
if (uIndex > 19) break;
swprintf(szValueName, L"%u", uIndex + 1);
RtlInitUnicodeString(&ValueName, szValueName);
swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
{
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiLayouts[uIndex].LayoutID,
(wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
}
else
{
swprintf(szLangID, L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID);
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)szLangID,
(wcslen(szLangID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName, szLangID);
Status = NtSetValueKey(SubKeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiLayouts[uIndex].LayoutID,
(wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
uCount++;
}
uIndex++;
}
while (MuiLayouts[uIndex].LangID != NULL);
if (uIndex > 1)
AddHotkeySettings(L"2", L"2", L"1");
else
AddHotkeySettings(L"3", L"3", L"3");
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddKeyboardLayouts(VOID)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts);
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
static
BOOLEAN
AddCodepageToRegistry(
IN LPCWSTR ACPage,
IN LPCWSTR OEMCPage,
IN LPCWSTR MACCPage)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
NTSTATUS Status;
// Open the nls codepage key
RtlInitUnicodeString(&KeyName,
L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
NULL);
Status = NtOpenKey(&KeyHandle,
KEY_WRITE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
return FALSE;
}
// Set ANSI codepage
RtlInitUnicodeString(&ValueName, L"ACP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)ACPage,
(wcslen(ACPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
// Set OEM codepage
RtlInitUnicodeString(&ValueName, L"OEMCP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)OEMCPage,
(wcslen(OEMCPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
// Set MAC codepage
RtlInitUnicodeString(&ValueName, L"MACCP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MACCPage,
(wcslen(MACCPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
NtClose(KeyHandle);
return TRUE;
}
static
BOOLEAN
AddFontsSettingsToRegistry(
IN const MUI_SUBFONT * MuiSubFonts)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
NTSTATUS Status;
ULONG uIndex = 0;
RtlInitUnicodeString(&KeyName,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
NULL);
Status = NtOpenKey(&KeyHandle,
KEY_WRITE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
return FALSE;
}
do
{
RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiSubFonts[uIndex].SubFontName,
(wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(KeyHandle);
return FALSE;
}
uIndex++;
}
while (MuiSubFonts[uIndex].FontName != NULL);
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddCodePage(VOID)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage,
MUILanguageList[lngIndex].OEMCPage,
MUILanguageList[lngIndex].MACCPage)&&
AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts))
{
return TRUE;
}
else
{
return FALSE;
}
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
VOID
SetConsoleCodePage(VOID)
{
ULONG lngIndex = 0;
UINT wCodePage;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
wCodePage = (UINT) wcstoul(MUILanguageList[lngIndex].OEMCPage, NULL, 10);
SetConsoleOutputCP(wCodePage);
return;
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
}
/* EOF */