/* * ReactOS kernel * Copyright (C) 2004 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/settings.c * PURPOSE: Device settings support functions * PROGRAMMERS: Colin Finck */ /* INCLUDES *****************************************************************/ #include "precomp.h" #include "genlist.h" #include "infsupp.h" #include "mui.h" #include "registry.h" #include "settings.h" #define NDEBUG #include /* GLOBALS ******************************************************************/ static ULONG DefaultLanguageIndex = 0; /* FUNCTIONS ****************************************************************/ static BOOLEAN IsAcpiComputer(VOID) { UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"); UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier"); UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS"); OBJECT_ATTRIBUTES ObjectAttributes; PKEY_BASIC_INFORMATION pDeviceInformation = NULL; ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR); PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL; ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR); ULONG RequiredSize; ULONG IndexDevice = 0; UNICODE_STRING DeviceName, ValueName; HANDLE hDevicesKey = NULL; HANDLE hDeviceKey = NULL; NTSTATUS Status; BOOLEAN ret = FALSE; InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed with status 0x%08lx\n", Status); goto cleanup; } pDeviceInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, DeviceInfoLength); if (!pDeviceInformation) { DPRINT("RtlAllocateHeap() failed\n"); Status = STATUS_NO_MEMORY; goto cleanup; } pValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueInfoLength); if (!pValueInformation) { DPRINT("RtlAllocateHeap() failed\n"); Status = STATUS_NO_MEMORY; goto cleanup; } while (TRUE) { Status = NtEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); if (Status == STATUS_NO_MORE_ENTRIES) break; else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) { RtlFreeHeap(RtlGetProcessHeap(), 0, pDeviceInformation); DeviceInfoLength = RequiredSize; pDeviceInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, DeviceInfoLength); if (!pDeviceInformation) { DPRINT("RtlAllocateHeap() failed\n"); Status = STATUS_NO_MEMORY; goto cleanup; } Status = NtEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); } if (!NT_SUCCESS(Status)) { DPRINT("NtEnumerateKey() failed with status 0x%08lx\n", Status); goto cleanup; } IndexDevice++; /* Open device key */ DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength; DeviceName.Buffer = pDeviceInformation->Name; InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, hDevicesKey, NULL); Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed with status 0x%08lx\n", Status); goto cleanup; } /* Read identifier */ Status = NtQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) { RtlFreeHeap(RtlGetProcessHeap(), 0, pValueInformation); ValueInfoLength = RequiredSize; pValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueInfoLength); if (!pValueInformation) { DPRINT("RtlAllocateHeap() failed\n"); Status = STATUS_NO_MEMORY; goto cleanup; } Status = NtQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); } if (!NT_SUCCESS(Status)) { DPRINT("NtQueryValueKey() failed with status 0x%08lx\n", Status); goto nextdevice; } else if (pValueInformation->Type != REG_SZ) { DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ); goto nextdevice; } ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength; ValueName.Buffer = (PWCHAR)pValueInformation->Data; if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL) ValueName.Length -= sizeof(WCHAR); if (RtlEqualUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE)) { DPRINT("Found ACPI BIOS\n"); ret = TRUE; goto cleanup; } nextdevice: NtClose(hDeviceKey); hDeviceKey = NULL; } cleanup: if (pDeviceInformation) RtlFreeHeap(RtlGetProcessHeap(), 0, pDeviceInformation); if (pValueInformation) RtlFreeHeap(RtlGetProcessHeap(), 0, pValueInformation); if (hDevicesKey) NtClose(hDevicesKey); if (hDeviceKey) NtClose(hDeviceKey); return ret; } static BOOLEAN GetComputerIdentifier( OUT PWSTR Identifier, IN ULONG IdentifierLength) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; LPCWSTR ComputerIdentifier; HANDLE ProcessorsKey; PKEY_FULL_INFORMATION pFullInfo; ULONG Size, SizeNeeded; NTSTATUS Status; DPRINT("GetComputerIdentifier() called\n"); Size = sizeof(KEY_FULL_INFORMATION); pFullInfo = (PKEY_FULL_INFORMATION)RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); if (!pFullInfo) { DPRINT("RtlAllocateHeap() failed\n"); return FALSE; } /* Open the processors key */ RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&ProcessorsKey, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed (Status 0x%lx)\n", Status); RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo); return FALSE; } /* Get number of subkeys */ Status = NtQueryKey(ProcessorsKey, KeyFullInformation, pFullInfo, Size, &Size); NtClose(ProcessorsKey); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { DPRINT("NtQueryKey() failed (Status 0x%lx)\n", Status); RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo); return FALSE; } /* Find computer identifier */ if (pFullInfo->SubKeys == 0) { /* Something strange happened. No processor detected */ RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo); return FALSE; } #ifdef _M_AMD64 /* On x64 we are l33t and use the MP config by default (except when we use KDBG, which is broken) */ #ifndef KDBG ComputerIdentifier = L"X64 MP"; #else ComputerIdentifier = L"X64 UP"; #endif #else if (IsAcpiComputer()) { if (pFullInfo->SubKeys == 1) { /* Computer is mono-CPU */ ComputerIdentifier = L"ACPI UP"; } else { /* Computer is multi-CPUs */ ComputerIdentifier = L"ACPI MP"; } } else { if (pFullInfo->SubKeys == 1) { /* Computer is mono-CPU */ ComputerIdentifier = L"PC UP"; } else { /* Computer is multi-CPUs */ ComputerIdentifier = L"PC MP"; } } #endif RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo); /* Copy computer identifier to return buffer */ SizeNeeded = (wcslen(ComputerIdentifier) + 1) * sizeof(WCHAR); if (SizeNeeded > IdentifierLength) return FALSE; RtlCopyMemory(Identifier, ComputerIdentifier, SizeNeeded); return TRUE; } /* * Return values: * 0x00: Failure, stop the enumeration; * 0x01: Add the entry and continue the enumeration; * 0x02: Skip the entry but continue the enumeration. */ typedef UCHAR (NTAPI *PPROCESS_ENTRY_ROUTINE)( IN PCWSTR KeyName, IN PCWSTR KeyValue, OUT PVOID* UserData, OUT PBOOLEAN Current, IN PVOID Parameter OPTIONAL); static LONG AddEntriesFromInfSection( IN OUT PGENERIC_LIST List, IN HINF InfFile, IN PCWSTR SectionName, IN PINFCONTEXT pContext, IN PPROCESS_ENTRY_ROUTINE ProcessEntry, IN PVOID Parameter OPTIONAL) { LONG TotalCount = 0; PCWSTR KeyName; PCWSTR KeyValue; PVOID UserData; BOOLEAN Current; UCHAR RetVal; if (!SpInfFindFirstLine(InfFile, SectionName, NULL, pContext)) return -1; do { /* * NOTE: Do not use INF_GetData() as it expects INF entries of exactly * two fields ("key = value"); however we expect to be able to deal with * entries having more than two fields, the only requirement being that * the second field (field number 1) contains the field description. */ if (!INF_GetDataField(pContext, 0, &KeyName)) { DPRINT("INF_GetDataField() failed\n"); return -1; } if (!INF_GetDataField(pContext, 1, &KeyValue)) { DPRINT("INF_GetDataField() failed\n"); INF_FreeData(KeyName); return -1; } UserData = NULL; Current = FALSE; RetVal = ProcessEntry(KeyName, KeyValue, &UserData, &Current, Parameter); INF_FreeData(KeyName); INF_FreeData(KeyValue); if (RetVal == 0) { DPRINT("ProcessEntry() failed\n"); return -1; } else if (RetVal == 1) { AppendGenericListEntry(List, UserData, Current); ++TotalCount; } // else if (RetVal == 2), skip the entry. } while (SpInfFindNextLine(pContext, pContext)); return TotalCount; } static UCHAR NTAPI DefaultProcessEntry( IN PCWSTR KeyName, IN PCWSTR KeyValue, OUT PVOID* UserData, OUT PBOOLEAN Current, IN PVOID Parameter OPTIONAL) { PWSTR CompareKey = (PWSTR)Parameter; PGENENTRY GenEntry; SIZE_T IdSize, ValueSize; IdSize = (wcslen(KeyName) + 1) * sizeof(WCHAR); ValueSize = (wcslen(KeyValue) + 1) * sizeof(WCHAR); GenEntry = RtlAllocateHeap(ProcessHeap, 0, sizeof(*GenEntry) + IdSize + ValueSize); if (GenEntry == NULL) { /* Failure, stop enumeration */ DPRINT1("RtlAllocateHeap() failed\n"); return 0; } GenEntry->Id = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry)); GenEntry->Value = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry) + IdSize); RtlStringCbCopyW((PWSTR)GenEntry->Id, IdSize, KeyName); RtlStringCbCopyW((PWSTR)GenEntry->Value, ValueSize, KeyValue); *UserData = GenEntry; *Current = (CompareKey ? !_wcsicmp(KeyName, CompareKey) : FALSE); /* Add the entry */ return 1; } BOOLEAN AddComputerTypeEntries( _In_ HINF InfFile, PGENERIC_LIST List, _In_ PWSTR SectionName) { INFCONTEXT Context; PCWSTR KeyName; PCWSTR KeyValue; WCHAR ComputerIdentifier[128]; WCHAR ComputerKey[32]; ULONG Count1, Count2; /* Get the computer identification */ if (!GetComputerIdentifier(ComputerIdentifier, 128)) { ComputerIdentifier[0] = 0; } DPRINT("Computer identifier: '%S'\n", ComputerIdentifier); /* Search for matching device identifier */ if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &Context)) { /* FIXME: error message */ return FALSE; } do { BOOLEAN FoundId; if (!INF_GetDataField(&Context, 1, &KeyValue)) { /* FIXME: Handle error! */ DPRINT("INF_GetDataField() failed\n"); return FALSE; } DPRINT("KeyValue: %S\n", KeyValue); FoundId = !!wcsstr(ComputerIdentifier, KeyValue); INF_FreeData(KeyValue); if (!FoundId) continue; if (!INF_GetDataField(&Context, 0, &KeyName)) { /* FIXME: Handle error! */ DPRINT("INF_GetDataField() failed\n"); return FALSE; } DPRINT("Computer key: %S\n", KeyName); RtlStringCchCopyW(ComputerKey, ARRAYSIZE(ComputerKey), KeyName); INF_FreeData(KeyName); } while (SpInfFindNextLine(&Context, &Context)); Count1 = AddEntriesFromInfSection(List, InfFile, L"Computer", &Context, DefaultProcessEntry, ComputerKey); Count2 = AddEntriesFromInfSection(List, InfFile, L"Computer.NT" INF_ARCH, &Context, DefaultProcessEntry, ComputerKey); if ((Count1 == -1) && (Count2 == -1)) { return FALSE; } return TRUE; } PGENERIC_LIST CreateComputerTypeList( IN HINF InfFile) { PGENERIC_LIST List; BOOLEAN Success; List = CreateGenericList(); if (List == NULL) return NULL; Success = AddComputerTypeEntries(InfFile, List, L"Map.Computer"); Success |= AddComputerTypeEntries(InfFile, List, L"Map.Computer.NT" INF_ARCH); if (!Success) { DestroyGenericList(List, TRUE); return NULL; } return List; } static BOOLEAN GetDisplayIdentifier( OUT PWSTR Identifier, IN ULONG IdentifierLength) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; WCHAR Buffer[32]; HANDLE BusKey; HANDLE BusInstanceKey; HANDLE ControllerKey; HANDLE ControllerInstanceKey; ULONG BusInstance; ULONG ControllerInstance; ULONG BufferLength; ULONG ReturnedLength; PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; NTSTATUS Status; DPRINT("GetDisplayIdentifier() called\n"); /* Open the bus key */ RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&BusKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } BusInstance = 0; while (TRUE) { RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", BusInstance); RtlInitUnicodeString(&KeyName, Buffer); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, BusKey, NULL); Status = NtOpenKey(&BusInstanceKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed (Status %lx)\n", Status); NtClose(BusKey); return FALSE; } /* Open the controller type key */ RtlInitUnicodeString(&KeyName, L"DisplayController"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, BusInstanceKey, NULL); Status = NtOpenKey(&ControllerKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes); if (NT_SUCCESS(Status)) { ControllerInstance = 0; while (TRUE) { /* Open the pointer controller instance key */ RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", ControllerInstance); RtlInitUnicodeString(&KeyName, Buffer); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, ControllerKey, NULL); Status = NtOpenKey(&ControllerInstanceKey, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed (Status %lx)\n", Status); NtClose(ControllerKey); NtClose(BusInstanceKey); NtClose(BusKey); return FALSE; } /* Get controller identifier */ RtlInitUnicodeString(&KeyName, L"Identifier"); BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR); ValueInfo = (KEY_VALUE_PARTIAL_INFORMATION*) RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); if (ValueInfo == NULL) { DPRINT("RtlAllocateHeap() failed\n"); NtClose(ControllerInstanceKey); NtClose(ControllerKey); NtClose(BusInstanceKey); NtClose(BusKey); return FALSE; } Status = NtQueryValueKey(ControllerInstanceKey, &KeyName, KeyValuePartialInformation, ValueInfo, BufferLength, &ReturnedLength); if (NT_SUCCESS(Status)) { DPRINT("Identifier: %S\n", (PWSTR)ValueInfo->Data); BufferLength = min(ValueInfo->DataLength / sizeof(WCHAR), IdentifierLength); RtlCopyMemory(Identifier, ValueInfo->Data, BufferLength * sizeof(WCHAR)); Identifier[BufferLength] = 0; RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); NtClose(ControllerInstanceKey); NtClose(ControllerKey); NtClose(BusInstanceKey); NtClose(BusKey); return TRUE; } NtClose(ControllerInstanceKey); ControllerInstance++; } NtClose(ControllerKey); } NtClose(BusInstanceKey); BusInstance++; } NtClose(BusKey); return FALSE; } PGENERIC_LIST CreateDisplayDriverList( IN HINF InfFile) { PGENERIC_LIST List; INFCONTEXT Context; PCWSTR KeyName; PCWSTR KeyValue; WCHAR DisplayIdentifier[128]; WCHAR DisplayKey[32]; /* Get the display identification */ if (!GetDisplayIdentifier(DisplayIdentifier, 128)) { DisplayIdentifier[0] = 0; } DPRINT("Display identifier: '%S'\n", DisplayIdentifier); /* Search for matching device identifier */ if (!SpInfFindFirstLine(InfFile, L"Map.Display", NULL, &Context)) { /* FIXME: error message */ return NULL; } do { BOOLEAN FoundId; if (!INF_GetDataField(&Context, 1, &KeyValue)) { /* FIXME: Handle error! */ DPRINT("INF_GetDataField() failed\n"); return NULL; } DPRINT("KeyValue: %S\n", KeyValue); FoundId = !!wcsstr(DisplayIdentifier, KeyValue); INF_FreeData(KeyValue); if (!FoundId) continue; if (!INF_GetDataField(&Context, 0, &KeyName)) { /* FIXME: Handle error! */ DPRINT("INF_GetDataField() failed\n"); return NULL; } DPRINT("Display key: %S\n", KeyName); RtlStringCchCopyW(DisplayKey, ARRAYSIZE(DisplayKey), KeyName); INF_FreeData(KeyName); } while (SpInfFindNextLine(&Context, &Context)); List = CreateGenericList(); if (List == NULL) return NULL; if (AddEntriesFromInfSection(List, InfFile, L"Display", &Context, DefaultProcessEntry, DisplayKey) == -1) { DestroyGenericList(List, TRUE); return NULL; } #if 0 AppendGenericListEntry(List, L"Other display driver", NULL, TRUE); #endif return List; } BOOLEAN ProcessComputerFiles( IN HINF InfFile, IN PGENERIC_LIST List, OUT PWSTR* AdditionalSectionName) { PGENERIC_LIST_ENTRY Entry; static WCHAR SectionName[128]; DPRINT("ProcessComputerFiles() called\n"); Entry = GetCurrentListEntry(List); if (Entry == NULL) return FALSE; RtlStringCchPrintfW(SectionName, ARRAYSIZE(SectionName), L"Files.%s", ((PGENENTRY)GetListEntryData(Entry))->Id); *AdditionalSectionName = SectionName; return TRUE; } BOOLEAN ProcessDisplayRegistry( IN HINF InfFile, IN PGENERIC_LIST List) { NTSTATUS Status; PGENERIC_LIST_ENTRY Entry; INFCONTEXT Context; PCWSTR Buffer; PCWSTR ServiceName; ULONG StartValue; ULONG Width, Height, Bpp; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; HANDLE KeyHandle; WCHAR RegPath[255]; DPRINT("ProcessDisplayRegistry() called\n"); Entry = GetCurrentListEntry(List); if (Entry == NULL) return FALSE; if (!SpInfFindFirstLine(InfFile, L"Display", ((PGENENTRY)GetListEntryData(Entry))->Id, &Context)) { DPRINT1("SpInfFindFirstLine() failed\n"); return FALSE; } /* Enable the correct driver */ if (!INF_GetDataField(&Context, 3, &ServiceName)) { DPRINT1("INF_GetDataField() failed\n"); return FALSE; } ASSERT(wcslen(ServiceName) < 10); DPRINT("Service name: '%S'\n", ServiceName); RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath), L"System\\CurrentControlSet\\Services\\%s", ServiceName); RtlInitUnicodeString(&KeyName, RegPath); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } StartValue = 1; Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle, L"Start", REG_DWORD, &StartValue, sizeof(StartValue)); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status); return FALSE; } /* Set the resolution */ if (!INF_GetDataField(&Context, 4, &Buffer)) { DPRINT1("INF_GetDataField() failed\n"); return FALSE; } RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath), L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0", ServiceName); DPRINT("RegPath: '%S'\n", RegPath); RtlInitUnicodeString(&KeyName, RegPath); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { /* Try without Hardware Profile part */ RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath), L"System\\CurrentControlSet\\Services\\%s\\Device0", ServiceName); RtlInitUnicodeString(&KeyName, RegPath); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); } if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } Width = wcstoul(Buffer, NULL, 10); Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle, L"DefaultSettings.XResolution", REG_DWORD, &Width, sizeof(Width)); if (!NT_SUCCESS(Status)) { DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status); NtClose(KeyHandle); return FALSE; } if (!INF_GetDataField(&Context, 5, &Buffer)) { DPRINT1("INF_GetDataField() failed\n"); NtClose(KeyHandle); return FALSE; } Height = wcstoul(Buffer, 0, 0); Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle, L"DefaultSettings.YResolution", REG_DWORD, &Height, sizeof(Height)); if (!NT_SUCCESS(Status)) { DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status); NtClose(KeyHandle); return FALSE; } if (!INF_GetDataField(&Context, 6, &Buffer)) { DPRINT1("INF_GetDataField() failed\n"); NtClose(KeyHandle); return FALSE; } Bpp = wcstoul(Buffer, 0, 0); Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle, L"DefaultSettings.BitsPerPel", REG_DWORD, &Bpp, sizeof(Bpp)); if (!NT_SUCCESS(Status)) { DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status); NtClose(KeyHandle); return FALSE; } NtClose(KeyHandle); DPRINT("ProcessDisplayRegistry() done\n"); return TRUE; } BOOLEAN ProcessLocaleRegistry( IN PGENERIC_LIST List) { PGENERIC_LIST_ENTRY Entry; PCWSTR LanguageId; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; UNICODE_STRING ValueName; HANDLE KeyHandle; NTSTATUS Status; Entry = GetCurrentListEntry(List); if (Entry == NULL) return FALSE; LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id; if (LanguageId == NULL) return FALSE; DPRINT("LanguageId: %S\n", LanguageId); /* Open the default users locale key */ RtlInitUnicodeString(&KeyName, L".DEFAULT\\Control Panel\\International"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_USERS, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } /* Set default user locale */ RtlInitUnicodeString(&ValueName, L"Locale"); Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, (PVOID)LanguageId, (wcslen(LanguageId) + 1) * sizeof(WCHAR)); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); return FALSE; } /* Skip first 4 zeroes */ if (wcslen(LanguageId) >= 4) LanguageId += 4; /* Open the NLS language key */ RtlInitUnicodeString(&KeyName, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } /* Set default language */ RtlInitUnicodeString(&ValueName, L"Default"); Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, (PVOID)LanguageId, (wcslen(LanguageId) + 1) * sizeof(WCHAR)); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); NtClose(KeyHandle); return FALSE; } /* Set install language */ RtlInitUnicodeString(&ValueName, L"InstallLanguage"); Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, (PVOID)LanguageId, (wcslen(LanguageId) + 1) * sizeof(WCHAR)); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); return FALSE; } return TRUE; } PGENERIC_LIST CreateKeyboardDriverList( IN HINF InfFile) { PGENERIC_LIST List; INFCONTEXT Context; List = CreateGenericList(); if (List == NULL) return NULL; if (AddEntriesFromInfSection(List, InfFile, L"Keyboard", &Context, DefaultProcessEntry, NULL) == -1) { DestroyGenericList(List, TRUE); return NULL; } return List; } ULONG GetDefaultLanguageIndex(VOID) { return DefaultLanguageIndex; } typedef struct _LANG_ENTRY_PARAM { ULONG uIndex; PWCHAR DefaultLanguage; } LANG_ENTRY_PARAM, *PLANG_ENTRY_PARAM; static UCHAR NTAPI ProcessLangEntry( IN PCWSTR KeyName, IN PCWSTR KeyValue, OUT PVOID* UserData, OUT PBOOLEAN Current, IN PVOID Parameter OPTIONAL) { PLANG_ENTRY_PARAM LangEntryParam = (PLANG_ENTRY_PARAM)Parameter; PGENENTRY GenEntry; SIZE_T IdSize, ValueSize; if (!IsLanguageAvailable(KeyName)) { /* The specified language is unavailable, skip the entry */ return 2; } IdSize = (wcslen(KeyName) + 1) * sizeof(WCHAR); ValueSize = (wcslen(KeyValue) + 1) * sizeof(WCHAR); GenEntry = RtlAllocateHeap(ProcessHeap, 0, sizeof(*GenEntry) + IdSize + ValueSize); if (GenEntry == NULL) { /* Failure, stop enumeration */ DPRINT1("RtlAllocateHeap() failed\n"); return 0; } GenEntry->Id = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry)); GenEntry->Value = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry) + IdSize); RtlStringCbCopyW((PWSTR)GenEntry->Id, IdSize, KeyName); RtlStringCbCopyW((PWSTR)GenEntry->Value, ValueSize, KeyValue); *UserData = GenEntry; *Current = FALSE; if (!_wcsicmp(KeyName, LangEntryParam->DefaultLanguage)) DefaultLanguageIndex = LangEntryParam->uIndex; LangEntryParam->uIndex++; /* Add the entry */ return 1; } PGENERIC_LIST CreateLanguageList( IN HINF InfFile, OUT PWSTR DefaultLanguage) { PGENERIC_LIST List; INFCONTEXT Context; PCWSTR KeyValue; LANG_ENTRY_PARAM LangEntryParam; LangEntryParam.uIndex = 0; LangEntryParam.DefaultLanguage = DefaultLanguage; /* Get default language id */ if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLanguage", &Context)) return NULL; if (!INF_GetData(&Context, NULL, &KeyValue)) return NULL; wcscpy(DefaultLanguage, KeyValue); List = CreateGenericList(); if (List == NULL) return NULL; if (AddEntriesFromInfSection(List, InfFile, L"Language", &Context, ProcessLangEntry, &LangEntryParam) == -1) { DestroyGenericList(List, TRUE); return NULL; } /* Only one language available, make it the default one */ if (LangEntryParam.uIndex == 1) { DefaultLanguageIndex = 0; wcscpy(DefaultLanguage, ((PGENENTRY)GetListEntryData(GetFirstListEntry(List)))->Id); } return List; } PGENERIC_LIST CreateKeyboardLayoutList( IN HINF InfFile, IN PCWSTR LanguageId, OUT PWSTR DefaultKBLayout) { PGENERIC_LIST List; INFCONTEXT Context; PCWSTR KeyValue; const MUI_LAYOUTS* LayoutsList; ULONG uIndex = 0; /* Get default layout id */ if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLayout", &Context)) return NULL; if (!INF_GetData(&Context, NULL, &KeyValue)) return NULL; wcscpy(DefaultKBLayout, KeyValue); List = CreateGenericList(); if (List == NULL) return NULL; LayoutsList = MUIGetLayoutsList(LanguageId); do { // NOTE: See https://svn.reactos.org/svn/reactos?view=revision&revision=68354 if (AddEntriesFromInfSection(List, InfFile, L"KeyboardLayout", &Context, DefaultProcessEntry, DefaultKBLayout) == -1) { DestroyGenericList(List, TRUE); return NULL; } uIndex++; } while (LayoutsList[uIndex].LangID != NULL); /* Check whether some keyboard layouts have been found */ /* FIXME: Handle this case */ if (GetNumberOfListEntries(List) == 0) { DPRINT1("No keyboard layouts have been found\n"); DestroyGenericList(List, TRUE); return NULL; } return List; } BOOLEAN ProcessKeyboardLayoutRegistry( IN PGENERIC_LIST List, IN PCWSTR LanguageId) { PGENERIC_LIST_ENTRY Entry; PCWSTR LayoutId; const MUI_LAYOUTS* LayoutsList; MUI_LAYOUTS NewLayoutsList[20]; ULONG uIndex; ULONG uOldPos = 0; Entry = GetCurrentListEntry(List); if (Entry == NULL) return FALSE; LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id; if (LayoutId == NULL) return FALSE; LayoutsList = MUIGetLayoutsList(LanguageId); if (_wcsicmp(LayoutsList[0].LayoutID, LayoutId) == 0) return TRUE; for (uIndex = 1; LayoutsList[uIndex].LangID != NULL; uIndex++) { if (_wcsicmp(LayoutsList[uIndex].LayoutID, LayoutId) == 0) { uOldPos = uIndex; continue; } NewLayoutsList[uIndex].LangID = LayoutsList[uIndex].LangID; NewLayoutsList[uIndex].LayoutID = LayoutsList[uIndex].LayoutID; } NewLayoutsList[uIndex].LangID = NULL; NewLayoutsList[uIndex].LayoutID = NULL; NewLayoutsList[uOldPos].LangID = LayoutsList[0].LangID; NewLayoutsList[uOldPos].LayoutID = LayoutsList[0].LayoutID; NewLayoutsList[0].LangID = LayoutsList[uOldPos].LangID; NewLayoutsList[0].LayoutID = LayoutsList[uOldPos].LayoutID; return AddKbLayoutsToRegistry(NewLayoutsList); } #if 0 BOOLEAN ProcessKeyboardLayoutFiles( IN PGENERIC_LIST List) { return TRUE; } #endif BOOLEAN SetGeoID( IN PCWSTR Id) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING Name; HANDLE KeyHandle; RtlInitUnicodeString(&Name, L".DEFAULT\\Control Panel\\International\\Geo"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_USERS, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); return FALSE; } RtlInitUnicodeString(&Name, L"Nation"); Status = NtSetValueKey(KeyHandle, &Name, 0, REG_SZ, (PVOID)Id, (wcslen(Id) + 1) * sizeof(WCHAR)); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetValueKey() failed (Status = %lx)\n", Status); return FALSE; } return TRUE; } BOOLEAN SetDefaultPagefile( IN WCHAR Drive) { NTSTATUS Status; HANDLE KeyHandle; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"); UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles"); WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0"; InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), NULL); Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; ValueBuffer[0] = Drive; NtSetValueKey(KeyHandle, &ValueName, 0, REG_MULTI_SZ, (PVOID)&ValueBuffer, sizeof(ValueBuffer)); NtClose(KeyHandle); return TRUE; } /* EOF */