[SETUPLIB][USETUP] Make the GENERIC_LIST store the items display text in UNICODE...
[reactos.git] / base / setup / lib / mui.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2008 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/mui.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER:
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "precomp.h"
30 #include "mui.h"
31 #include "muifonts.h"
32 #include "muilanguages.h"
33 #include "registry.h"
34
35 #define NDEBUG
36 #include <debug.h>
37
38
39 /* FUNCTIONS ****************************************************************/
40
41 static
42 ULONG
43 FindLanguageIndex(
44 IN PCWSTR LanguageId)
45 {
46 ULONG lngIndex = 0;
47
48 if (LanguageId == NULL)
49 {
50 /* Default to en-US */
51 // return 0; // FIXME!!
52 LanguageId = L"00000409";
53 }
54
55 while (MUILanguageList[lngIndex].LanguageID != NULL)
56 {
57 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
58 {
59 return lngIndex;
60 }
61
62 lngIndex++;
63 }
64
65 return 0;
66 }
67
68 BOOLEAN
69 IsLanguageAvailable(
70 IN PCWSTR LanguageId)
71 {
72 ULONG lngIndex = 0;
73
74 while (MUILanguageList[lngIndex].LanguageID != NULL)
75 {
76 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
77 return TRUE;
78
79 lngIndex++;
80 }
81
82 return FALSE;
83 }
84
85
86 PCWSTR
87 MUIDefaultKeyboardLayout(
88 IN PCWSTR LanguageId)
89 {
90 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
91 return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID;
92 }
93
94 PCWSTR
95 MUIGetOEMCodePage(
96 IN PCWSTR LanguageId)
97 {
98 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
99 return MUILanguageList[lngIndex].OEMCPage;
100 }
101
102 PCWSTR
103 MUIGetGeoID(
104 IN PCWSTR LanguageId)
105 {
106 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
107 return MUILanguageList[lngIndex].GeoID;
108 }
109
110 const MUI_LAYOUTS*
111 MUIGetLayoutsList(
112 IN PCWSTR LanguageId)
113 {
114 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
115 return MUILanguageList[lngIndex].MuiLayouts;
116 }
117
118
119 static
120 BOOLEAN
121 AddHotkeySettings(
122 IN PCWSTR Hotkey,
123 IN PCWSTR LangHotkey,
124 IN PCWSTR LayoutHotkey)
125 {
126 OBJECT_ATTRIBUTES ObjectAttributes;
127 UNICODE_STRING KeyName;
128 UNICODE_STRING ValueName;
129 HANDLE KeyHandle;
130 ULONG Disposition;
131 NTSTATUS Status;
132
133 RtlInitUnicodeString(&KeyName,
134 L".DEFAULT\\Keyboard Layout\\Toggle");
135 InitializeObjectAttributes(&ObjectAttributes,
136 &KeyName,
137 OBJ_CASE_INSENSITIVE,
138 GetRootKeyByPredefKey(HKEY_USERS, NULL),
139 NULL);
140
141 Status = NtCreateKey(&KeyHandle,
142 KEY_SET_VALUE,
143 &ObjectAttributes,
144 0,
145 NULL,
146 REG_OPTION_NON_VOLATILE,
147 &Disposition);
148 if (!NT_SUCCESS(Status))
149 {
150 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
151 return FALSE;
152 }
153
154 RtlInitUnicodeString(&ValueName,
155 L"Hotkey");
156
157 Status = NtSetValueKey(KeyHandle,
158 &ValueName,
159 0,
160 REG_SZ,
161 (PVOID)Hotkey,
162 (1 + 1) * sizeof(WCHAR));
163 if (!NT_SUCCESS(Status))
164 {
165 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
166 NtClose(KeyHandle);
167 return FALSE;
168 }
169
170 RtlInitUnicodeString(&ValueName,
171 L"Language Hotkey");
172
173 Status = NtSetValueKey(KeyHandle,
174 &ValueName,
175 0,
176 REG_SZ,
177 (PVOID)LangHotkey,
178 (1 + 1) * sizeof(WCHAR));
179 if (!NT_SUCCESS(Status))
180 {
181 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
182 NtClose(KeyHandle);
183 return FALSE;
184 }
185
186 RtlInitUnicodeString(&ValueName,
187 L"Layout Hotkey");
188
189 Status = NtSetValueKey(KeyHandle,
190 &ValueName,
191 0,
192 REG_SZ,
193 (PVOID)LayoutHotkey,
194 (1 + 1) * sizeof(WCHAR));
195 if (!NT_SUCCESS(Status))
196 {
197 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
198 NtClose(KeyHandle);
199 return FALSE;
200 }
201
202 NtClose(KeyHandle);
203 return TRUE;
204 }
205
206 BOOLEAN
207 AddKbLayoutsToRegistry(
208 IN const MUI_LAYOUTS *MuiLayouts)
209 {
210 OBJECT_ATTRIBUTES ObjectAttributes;
211 UNICODE_STRING KeyName;
212 UNICODE_STRING ValueName;
213 HANDLE KeyHandle;
214 HANDLE SubKeyHandle;
215 NTSTATUS Status;
216 ULONG Disposition;
217 ULONG uIndex = 0;
218 ULONG uCount = 0;
219 WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout";
220 WCHAR szValueName[3 + 1];
221 WCHAR szLangID[8 + 1];
222
223 // Open the keyboard layout key
224 RtlInitUnicodeString(&KeyName, szKeyName);
225 InitializeObjectAttributes(&ObjectAttributes,
226 &KeyName,
227 OBJ_CASE_INSENSITIVE,
228 GetRootKeyByPredefKey(HKEY_USERS, NULL),
229 NULL);
230
231 Status = NtCreateKey(&KeyHandle,
232 KEY_CREATE_SUB_KEY,
233 &ObjectAttributes,
234 0,
235 NULL,
236 REG_OPTION_NON_VOLATILE,
237 &Disposition);
238 if (!NT_SUCCESS(Status))
239 {
240 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
241 return FALSE;
242 }
243
244 NtClose(KeyHandle);
245
246 KeyName.MaximumLength = sizeof(szKeyName);
247 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
248
249 if (!NT_SUCCESS(Status))
250 {
251 DPRINT1("RtlAppend failed! (%lx)\n", Status);
252 DPRINT1("String is %wZ\n", &KeyName);
253 return FALSE;
254 }
255
256 InitializeObjectAttributes(&ObjectAttributes,
257 &KeyName,
258 OBJ_CASE_INSENSITIVE,
259 GetRootKeyByPredefKey(HKEY_USERS, NULL),
260 NULL);
261
262 Status = NtCreateKey(&KeyHandle,
263 KEY_SET_VALUE,
264 &ObjectAttributes,
265 0,
266 NULL,
267 REG_OPTION_NON_VOLATILE,
268 &Disposition);
269 if (!NT_SUCCESS(Status))
270 {
271 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
272 return FALSE;
273 }
274
275 RtlInitUnicodeString(&KeyName, L".DEFAULT\\Keyboard Layout\\Substitutes");
276 InitializeObjectAttributes(&ObjectAttributes,
277 &KeyName,
278 OBJ_CASE_INSENSITIVE,
279 GetRootKeyByPredefKey(HKEY_USERS, NULL),
280 NULL);
281
282 Status = NtCreateKey(&SubKeyHandle,
283 KEY_SET_VALUE,
284 &ObjectAttributes,
285 0,
286 NULL,
287 REG_OPTION_NON_VOLATILE,
288 &Disposition);
289 if (!NT_SUCCESS(Status))
290 {
291 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
292 NtClose(SubKeyHandle);
293 NtClose(KeyHandle);
294 return FALSE;
295 }
296
297 while (MuiLayouts[uIndex].LangID != NULL)
298 {
299 if (uIndex > 19) break;
300
301 swprintf(szValueName, L"%u", uIndex + 1);
302 RtlInitUnicodeString(&ValueName, szValueName);
303
304 swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
305
306 if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
307 {
308 Status = NtSetValueKey(KeyHandle,
309 &ValueName,
310 0,
311 REG_SZ,
312 (PVOID)MuiLayouts[uIndex].LayoutID,
313 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
314 if (!NT_SUCCESS(Status))
315 {
316 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
317 NtClose(SubKeyHandle);
318 NtClose(KeyHandle);
319 return FALSE;
320 }
321 }
322 else
323 {
324 swprintf(szLangID, L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID);
325 Status = NtSetValueKey(KeyHandle,
326 &ValueName,
327 0,
328 REG_SZ,
329 (PVOID)szLangID,
330 (wcslen(szLangID)+1) * sizeof(WCHAR));
331 if (!NT_SUCCESS(Status))
332 {
333 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
334 NtClose(SubKeyHandle);
335 NtClose(KeyHandle);
336 return FALSE;
337 }
338
339 RtlInitUnicodeString(&ValueName, szLangID);
340
341 Status = NtSetValueKey(SubKeyHandle,
342 &ValueName,
343 0,
344 REG_SZ,
345 (PVOID)MuiLayouts[uIndex].LayoutID,
346 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
347 if (!NT_SUCCESS(Status))
348 {
349 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
350 NtClose(SubKeyHandle);
351 NtClose(KeyHandle);
352 return FALSE;
353 }
354
355 uCount++;
356 }
357
358 uIndex++;
359 }
360
361 if (uIndex > 1)
362 AddHotkeySettings(L"2", L"2", L"1");
363 else
364 AddHotkeySettings(L"3", L"3", L"3");
365
366 NtClose(SubKeyHandle);
367 NtClose(KeyHandle);
368 return TRUE;
369 }
370
371 BOOLEAN
372 AddKeyboardLayouts(
373 IN PCWSTR LanguageId)
374 {
375 ULONG lngIndex = 0;
376
377 while (MUILanguageList[lngIndex].LanguageID != NULL)
378 {
379 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
380 {
381 return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts);
382 }
383
384 lngIndex++;
385 }
386
387 return FALSE;
388 }
389
390 static
391 BOOLEAN
392 AddCodepageToRegistry(
393 IN PCWSTR ACPage,
394 IN PCWSTR OEMCPage,
395 IN PCWSTR MACCPage)
396 {
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 UNICODE_STRING KeyName;
399 UNICODE_STRING ValueName;
400 HANDLE KeyHandle;
401 NTSTATUS Status;
402
403 // Open the nls codepage key
404 RtlInitUnicodeString(&KeyName,
405 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
406 InitializeObjectAttributes(&ObjectAttributes,
407 &KeyName,
408 OBJ_CASE_INSENSITIVE,
409 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
410 NULL);
411 Status = NtOpenKey(&KeyHandle,
412 KEY_WRITE,
413 &ObjectAttributes);
414 if (!NT_SUCCESS(Status))
415 {
416 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
417 return FALSE;
418 }
419
420 // Set ANSI codepage
421 RtlInitUnicodeString(&ValueName, L"ACP");
422 Status = NtSetValueKey(KeyHandle,
423 &ValueName,
424 0,
425 REG_SZ,
426 (PVOID)ACPage,
427 (wcslen(ACPage)+1) * sizeof(WCHAR));
428 if (!NT_SUCCESS(Status))
429 {
430 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
431 NtClose(KeyHandle);
432 return FALSE;
433 }
434
435 // Set OEM codepage
436 RtlInitUnicodeString(&ValueName, L"OEMCP");
437 Status = NtSetValueKey(KeyHandle,
438 &ValueName,
439 0,
440 REG_SZ,
441 (PVOID)OEMCPage,
442 (wcslen(OEMCPage)+1) * sizeof(WCHAR));
443 if (!NT_SUCCESS(Status))
444 {
445 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
446 NtClose(KeyHandle);
447 return FALSE;
448 }
449
450 // Set MAC codepage
451 RtlInitUnicodeString(&ValueName, L"MACCP");
452 Status = NtSetValueKey(KeyHandle,
453 &ValueName,
454 0,
455 REG_SZ,
456 (PVOID)MACCPage,
457 (wcslen(MACCPage)+1) * sizeof(WCHAR));
458 if (!NT_SUCCESS(Status))
459 {
460 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
461 NtClose(KeyHandle);
462 return FALSE;
463 }
464
465 NtClose(KeyHandle);
466
467 return TRUE;
468 }
469
470 static
471 BOOLEAN
472 AddFontsSettingsToRegistry(
473 IN const MUI_SUBFONT * MuiSubFonts)
474 {
475 OBJECT_ATTRIBUTES ObjectAttributes;
476 UNICODE_STRING KeyName;
477 UNICODE_STRING ValueName;
478 HANDLE KeyHandle;
479 NTSTATUS Status;
480 ULONG uIndex = 0;
481
482 RtlInitUnicodeString(&KeyName,
483 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
484 InitializeObjectAttributes(&ObjectAttributes,
485 &KeyName,
486 OBJ_CASE_INSENSITIVE,
487 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
488 NULL);
489 Status = NtOpenKey(&KeyHandle,
490 KEY_WRITE,
491 &ObjectAttributes);
492 if (!NT_SUCCESS(Status))
493 {
494 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
495 return FALSE;
496 }
497
498 while (MuiSubFonts[uIndex].FontName != NULL)
499 {
500 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
501 Status = NtSetValueKey(KeyHandle,
502 &ValueName,
503 0,
504 REG_SZ,
505 (PVOID)MuiSubFonts[uIndex].SubFontName,
506 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
507 if (!NT_SUCCESS(Status))
508 {
509 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
510 NtClose(KeyHandle);
511 return FALSE;
512 }
513
514 uIndex++;
515 }
516
517 NtClose(KeyHandle);
518
519 return TRUE;
520 }
521
522 BOOLEAN
523 AddCodePage(
524 IN PCWSTR LanguageId)
525 {
526 ULONG lngIndex = 0;
527
528 while (MUILanguageList[lngIndex].LanguageID != NULL)
529 {
530 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
531 {
532 if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage,
533 MUILanguageList[lngIndex].OEMCPage,
534 MUILanguageList[lngIndex].MACCPage) &&
535 AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts))
536 {
537 return TRUE;
538 }
539 else
540 {
541 return FALSE;
542 }
543 }
544
545 lngIndex++;
546 }
547
548 return FALSE;
549 }
550
551 /* EOF */