1cf1f27b29d6e88d64b75b72a171ce984327850e
[reactos.git] / reactos / subsys / system / usetup / settings.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: subsys/system/usetup/settings.c
22 * PURPOSE: Device settings support functions
23 * PROGRAMMER: Eric Kohl
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include <usetup.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 static BOOLEAN
36 GetComputerIdentifier(PWSTR Identifier,
37 ULONG IdentifierLength)
38 {
39 OBJECT_ATTRIBUTES ObjectAttributes;
40 UNICODE_STRING KeyName;
41 LPCWSTR ComputerIdentifier;
42 HANDLE ProcessorsKey;
43 PKEY_FULL_INFORMATION pFullInfo;
44 ULONG Size, SizeNeeded;
45 NTSTATUS Status;
46
47 DPRINT("GetComputerIdentifier() called\n");
48
49 Size = sizeof(KEY_FULL_INFORMATION);
50 pFullInfo = (PKEY_FULL_INFORMATION)RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
51 if (!pFullInfo)
52 {
53 DPRINT("RtlAllocateHeap() failed\n");
54 return FALSE;
55 }
56
57 /* Open the processors key */
58 RtlInitUnicodeString(&KeyName,
59 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
60 InitializeObjectAttributes(&ObjectAttributes,
61 &KeyName,
62 OBJ_CASE_INSENSITIVE,
63 NULL,
64 NULL);
65 Status = NtOpenKey(&ProcessorsKey,
66 KEY_QUERY_VALUE ,
67 &ObjectAttributes);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT("NtOpenKey() failed (Status 0x%lx)\n", Status);
71 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
72 return FALSE;
73 }
74
75 /* Get number of subkeys */
76 Status = NtQueryKey(
77 ProcessorsKey,
78 KeyFullInformation,
79 pFullInfo,
80 Size,
81 &Size);
82 NtClose(ProcessorsKey);
83 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
84 {
85 DPRINT("NtQueryKey() failed (Status 0x%lx)\n", Status);
86 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
87 return FALSE;
88 }
89
90 /* Find computer identifier */
91 if (pFullInfo->SubKeys == 0)
92 {
93 /* Something strange happened. No processor detected */
94 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
95 return FALSE;
96 }
97
98 if (pFullInfo->SubKeys == 1)
99 {
100 /* Computer is mono-CPU */
101 ComputerIdentifier = L"PC UP";
102 }
103 else
104 {
105 /* Computer is multi-CPUs */
106 ComputerIdentifier = L"PC MP";
107 }
108 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
109
110 /* Copy computer identifier to return buffer */
111 SizeNeeded = (wcslen(ComputerIdentifier) + 1) * sizeof(WCHAR);
112 if (SizeNeeded > IdentifierLength)
113 return FALSE;
114 RtlCopyMemory(Identifier, ComputerIdentifier, SizeNeeded);
115 return TRUE;
116 }
117
118
119 PGENERIC_LIST
120 CreateComputerTypeList(HINF InfFile)
121 {
122 CHAR Buffer[128];
123 PGENERIC_LIST List;
124 PINFCONTEXT Context;
125 PWCHAR KeyName;
126 PWCHAR KeyValue;
127 PWCHAR UserData;
128 WCHAR ComputerIdentifier[128];
129 WCHAR ComputerKey[32];
130
131 /* Get the computer identification */
132 if (!GetComputerIdentifier(ComputerIdentifier, 128))
133 {
134 ComputerIdentifier[0] = 0;
135 }
136
137 DPRINT("Computer identifier: '%S'\n", ComputerIdentifier);
138
139 /* Search for matching device identifier */
140 if (!InfFindFirstLine(InfFile, L"Map.Computer", NULL, &Context))
141 {
142 /* FIXME: error message */
143 return NULL;
144 }
145
146 do
147 {
148 if (!InfGetDataField(Context, 1, &KeyValue))
149 {
150 /* FIXME: Handle error! */
151 DPRINT("InfGetDataField() failed\n");
152 return NULL;
153 }
154
155 DPRINT("KeyValue: %S\n", KeyValue);
156 if (wcsstr(ComputerIdentifier, KeyValue))
157 {
158 if (!InfGetDataField(Context, 0, &KeyName))
159 {
160 /* FIXME: Handle error! */
161 DPRINT("InfGetDataField() failed\n");
162 return NULL;
163 }
164
165 DPRINT("Computer key: %S\n", KeyName);
166 wcscpy(ComputerKey, KeyName);
167 }
168 }
169 while (InfFindNextLine(Context, Context));
170 InfFreeContext(Context);
171
172 List = CreateGenericList();
173 if (List == NULL)
174 return NULL;
175
176 if (!InfFindFirstLine (InfFile, L"Computer", NULL, &Context))
177 {
178 DestroyGenericList(List, FALSE);
179 return NULL;
180 }
181
182 do
183 {
184 if (!InfGetData (Context, &KeyName, &KeyValue))
185 {
186 /* FIXME: Handle error! */
187 DPRINT("InfGetData() failed\n");
188 break;
189 }
190
191 UserData = RtlAllocateHeap(ProcessHeap,
192 0,
193 (wcslen(KeyName) + 1) * sizeof(WCHAR));
194 if (UserData == NULL)
195 {
196 /* FIXME: Handle error! */
197 }
198
199 wcscpy(UserData, KeyName);
200
201 sprintf(Buffer, "%S", KeyValue);
202 AppendGenericListEntry(List, Buffer, UserData,
203 _wcsicmp(KeyName, ComputerKey) ? FALSE : TRUE);
204 }
205 while (InfFindNextLine(Context, Context));
206 InfFreeContext(Context);
207
208 return List;
209 }
210
211
212 static BOOLEAN
213 GetDisplayIdentifier(PWSTR Identifier,
214 ULONG IdentifierLength)
215 {
216 OBJECT_ATTRIBUTES ObjectAttributes;
217 UNICODE_STRING KeyName;
218 WCHAR Buffer[32];
219 HANDLE BusKey;
220 HANDLE BusInstanceKey;
221 HANDLE ControllerKey;
222 HANDLE ControllerInstanceKey;
223 ULONG BusInstance;
224 ULONG ControllerInstance;
225 ULONG BufferLength;
226 ULONG ReturnedLength;
227 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
228 NTSTATUS Status;
229
230 DPRINT("GetDisplayIdentifier() called\n");
231
232 /* Open the bus key */
233 RtlInitUnicodeString(&KeyName,
234 L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter");
235 InitializeObjectAttributes(&ObjectAttributes,
236 &KeyName,
237 OBJ_CASE_INSENSITIVE,
238 NULL,
239 NULL);
240 Status = NtOpenKey(&BusKey,
241 KEY_ALL_ACCESS,
242 &ObjectAttributes);
243 if (!NT_SUCCESS(Status))
244 {
245 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
246 return FALSE;
247 }
248
249 BusInstance = 0;
250 while (TRUE)
251 {
252 swprintf(Buffer, L"%lu", BusInstance);
253 RtlInitUnicodeString(&KeyName,
254 Buffer);
255 InitializeObjectAttributes(&ObjectAttributes,
256 &KeyName,
257 OBJ_CASE_INSENSITIVE,
258 BusKey,
259 NULL);
260 Status = NtOpenKey(&BusInstanceKey,
261 KEY_ALL_ACCESS,
262 &ObjectAttributes);
263 if (!NT_SUCCESS(Status))
264 {
265 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
266 NtClose(BusKey);
267 return FALSE;
268 }
269
270 /* Open the controller type key */
271 RtlInitUnicodeString(&KeyName,
272 L"DisplayController");
273 InitializeObjectAttributes(&ObjectAttributes,
274 &KeyName,
275 OBJ_CASE_INSENSITIVE,
276 BusInstanceKey,
277 NULL);
278 Status = NtOpenKey(&ControllerKey,
279 KEY_ALL_ACCESS,
280 &ObjectAttributes);
281 if (NT_SUCCESS(Status))
282 {
283 ControllerInstance = 0;
284 while (TRUE)
285 {
286 /* Open the pointer controller instance key */
287 swprintf(Buffer, L"%lu", ControllerInstance);
288 RtlInitUnicodeString(&KeyName,
289 Buffer);
290 InitializeObjectAttributes(&ObjectAttributes,
291 &KeyName,
292 OBJ_CASE_INSENSITIVE,
293 ControllerKey,
294 NULL);
295 Status = NtOpenKey(&ControllerInstanceKey,
296 KEY_ALL_ACCESS,
297 &ObjectAttributes);
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
301 NtClose(ControllerKey);
302 NtClose(BusInstanceKey);
303 NtClose(BusKey);
304 return FALSE;
305 }
306
307 /* Get controller identifier */
308 RtlInitUnicodeString(&KeyName,
309 L"Identifier");
310
311 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
312 256 * sizeof(WCHAR);
313 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
314 0,
315 BufferLength);
316 if (ValueInfo == NULL)
317 {
318 DPRINT("RtlAllocateHeap() failed\n");
319 NtClose(ControllerInstanceKey);
320 NtClose(ControllerKey);
321 NtClose(BusInstanceKey);
322 NtClose(BusKey);
323 return FALSE;
324 }
325
326 Status = NtQueryValueKey(ControllerInstanceKey,
327 &KeyName,
328 KeyValuePartialInformation,
329 ValueInfo,
330 BufferLength,
331 &ReturnedLength);
332 if (NT_SUCCESS(Status))
333 {
334 DPRINT("Identifier: %S\n", (PWSTR)ValueInfo->Data);
335
336 BufferLength = min(ValueInfo->DataLength / sizeof(WCHAR), IdentifierLength);
337 RtlCopyMemory (Identifier,
338 ValueInfo->Data,
339 BufferLength * sizeof(WCHAR));
340 Identifier[BufferLength] = 0;
341
342 RtlFreeHeap(RtlGetProcessHeap(),
343 0,
344 ValueInfo);
345 NtClose(ControllerInstanceKey);
346 NtClose(ControllerKey);
347 NtClose(BusInstanceKey);
348 NtClose(BusKey);
349 return TRUE;
350 }
351
352 NtClose(ControllerInstanceKey);
353
354 ControllerInstance++;
355 }
356
357 NtClose(ControllerKey);
358 }
359
360 NtClose(BusInstanceKey);
361
362 BusInstance++;
363 }
364
365 NtClose(BusKey);
366
367 return FALSE;
368 }
369
370
371 PGENERIC_LIST
372 CreateDisplayDriverList(HINF InfFile)
373 {
374 CHAR Buffer[128];
375 PGENERIC_LIST List;
376 PINFCONTEXT Context;
377 PWCHAR KeyName;
378 PWCHAR KeyValue;
379 PWCHAR UserData;
380 WCHAR DisplayIdentifier[128];
381 WCHAR DisplayKey[32];
382
383 /* Get the display identification */
384 if (!GetDisplayIdentifier(DisplayIdentifier, 128))
385 {
386 DisplayIdentifier[0] = 0;
387 }
388
389 DPRINT("Display identifier: '%S'\n", DisplayIdentifier);
390
391 /* Search for matching device identifier */
392 if (!InfFindFirstLine(InfFile, L"Map.Display", NULL, &Context))
393 {
394 /* FIXME: error message */
395 return NULL;
396 }
397
398 do
399 {
400 if (!InfGetDataField(Context, 1, &KeyValue))
401 {
402 /* FIXME: Handle error! */
403 DPRINT("InfGetDataField() failed\n");
404 return NULL;
405 }
406
407 DPRINT("KeyValue: %S\n", KeyValue);
408 if (wcsstr(DisplayIdentifier, KeyValue))
409 {
410 if (!InfGetDataField(Context, 0, &KeyName))
411 {
412 /* FIXME: Handle error! */
413 DPRINT("InfGetDataField() failed\n");
414 return NULL;
415 }
416
417 DPRINT("Display key: %S\n", KeyName);
418 wcscpy(DisplayKey, KeyName);
419 }
420 }
421 while (InfFindNextLine(Context, Context));
422 InfFreeContext(Context);
423
424
425 List = CreateGenericList();
426 if (List == NULL)
427 return NULL;
428
429 if (!InfFindFirstLine (InfFile, L"Display", NULL, &Context))
430 {
431 DestroyGenericList(List, FALSE);
432 return NULL;
433 }
434
435 do
436 {
437 if (!InfGetDataField(Context, 0, &KeyName))
438 {
439 DPRINT1("InfGetDataField() failed\n");
440 break;
441 }
442
443 if (!InfGetDataField(Context, 1, &KeyValue))
444 {
445 DPRINT1("InfGetDataField() failed\n");
446 break;
447 }
448
449 UserData = RtlAllocateHeap(ProcessHeap,
450 0,
451 (wcslen(KeyName) + 1) * sizeof(WCHAR));
452 if (UserData == NULL)
453 {
454 DPRINT1("RtlAllocateHeap() failed\n");
455 DestroyGenericList(List, TRUE);
456 return NULL;
457 }
458
459 wcscpy(UserData, KeyName);
460
461 sprintf(Buffer, "%S", KeyValue);
462 AppendGenericListEntry(List,
463 Buffer,
464 UserData,
465 _wcsicmp(KeyName, DisplayKey) ? FALSE : TRUE);
466 }
467 while (InfFindNextLine(Context, Context));
468 InfFreeContext(Context);
469
470 #if 0
471 AppendGenericListEntry(List, "Other display driver", NULL, TRUE);
472 #endif
473
474 return List;
475 }
476
477 BOOLEAN
478 ProcessComputerFiles(HINF InfFile, PGENERIC_LIST List, PWCHAR* AdditionalSectionName)
479 {
480 PGENERIC_LIST_ENTRY Entry;
481 static WCHAR SectionName[128];
482
483 DPRINT("ProcessComputerFiles() called\n");
484
485 Entry = GetGenericListEntry(List);
486 if (Entry == NULL)
487 {
488 DPRINT("GetGenericListEntry() failed\n");
489 return FALSE;
490 }
491
492 wcscpy(SectionName, L"Files.");
493 wcscat(SectionName, Entry->UserData);
494 *AdditionalSectionName = SectionName;
495
496 return TRUE;
497 }
498
499
500 BOOLEAN
501 ProcessDisplayRegistry(HINF InfFile, PGENERIC_LIST List)
502 {
503 PGENERIC_LIST_ENTRY Entry;
504 PINFCONTEXT Context;
505 PWCHAR ServiceName;
506 ULONG StartValue;
507 NTSTATUS Status;
508
509 DPRINT("ProcessDisplayRegistry() called\n");
510
511 Entry = GetGenericListEntry(List);
512 if (Entry == NULL)
513 {
514 DPRINT("GetGenericListEntry() failed\n");
515 return FALSE;
516 }
517
518 if (!InfFindFirstLine(InfFile, L"Display", Entry->UserData, &Context))
519 {
520 DPRINT("InfFindFirstLine() failed\n");
521 return FALSE;
522 }
523
524 /* Enable the right driver */
525 if (!InfGetDataField(Context, 3, &ServiceName))
526 {
527 DPRINT("InfGetDataField() failed\n");
528 return FALSE;
529 }
530
531 ASSERT(wcslen(ServiceName) < 10);
532 DPRINT("Service name: %S\n", ServiceName);
533
534 StartValue = 1;
535 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
536 ServiceName,
537 L"Start",
538 REG_DWORD,
539 &StartValue,
540 sizeof(ULONG));
541
542 if (!NT_SUCCESS(Status))
543 {
544 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
545 return FALSE;
546 }
547
548 /* Set the resolution */
549 WCHAR RegPath [255];
550 swprintf(RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0", ServiceName);
551
552 PWCHAR Buffer;
553 if (!InfGetDataField(Context, 4, &Buffer))
554 {
555 DPRINT("InfGetDataField() failed\n");
556 return FALSE;
557 }
558 ULONG Width = wcstoul(Buffer, NULL, 10);
559 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
560 RegPath,
561 L"DefaultSettings.XResolution",
562 REG_DWORD,
563 &Width,
564 sizeof(ULONG));
565 if (!NT_SUCCESS(Status))
566 {
567 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
568 return FALSE;
569 }
570
571
572 if (!InfGetDataField(Context, 5, &Buffer))
573 {
574 DPRINT("InfGetDataField() failed\n");
575 return FALSE;
576 }
577 ULONG Hight = wcstoul(Buffer, 0, 0);
578 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
579 RegPath,
580 L"DefaultSettings.YResolution",
581 REG_DWORD,
582 &Hight,
583 sizeof(ULONG));
584 if (!NT_SUCCESS(Status))
585 {
586 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
587 return FALSE;
588 }
589
590 if (!InfGetDataField(Context, 6, &Buffer))
591 {
592 DPRINT("InfGetDataField() failed\n");
593 return FALSE;
594 }
595 ULONG Bpp = wcstoul(Buffer, 0, 0);
596 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
597 RegPath,
598 L"DefaultSettings.BitsPerPel",
599 REG_DWORD,
600 &Bpp,
601 sizeof(ULONG));
602 if (!NT_SUCCESS(Status))
603 {
604 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
605 return FALSE;
606 }
607
608 InfFreeContext(Context);
609
610 DPRINT("ProcessDisplayRegistry() done\n");
611
612 return TRUE;
613 }
614
615
616 PGENERIC_LIST
617 CreateKeyboardDriverList(HINF InfFile)
618 {
619 CHAR Buffer[128];
620 PGENERIC_LIST List;
621 PINFCONTEXT Context;
622 PWCHAR KeyName;
623 PWCHAR KeyValue;
624 PWCHAR UserData;
625
626 List = CreateGenericList();
627 if (List == NULL)
628 return NULL;
629
630 if (!InfFindFirstLine (InfFile, L"Keyboard", NULL, &Context))
631 {
632 DestroyGenericList(List, FALSE);
633 return NULL;
634 }
635
636 do
637 {
638 if (!InfGetData (Context, &KeyName, &KeyValue))
639 {
640 /* FIXME: Handle error! */
641 DPRINT("InfGetData() failed\n");
642 break;
643 }
644
645 UserData = RtlAllocateHeap(ProcessHeap,
646 0,
647 (wcslen(KeyName) + 1) * sizeof(WCHAR));
648 if (UserData == NULL)
649 {
650 /* FIXME: Handle error! */
651 }
652
653 wcscpy(UserData, KeyName);
654
655 sprintf(Buffer, "%S", KeyValue);
656 AppendGenericListEntry(List, Buffer, UserData, FALSE);
657 }
658 while (InfFindNextLine(Context, Context));
659 InfFreeContext(Context);
660
661 return List;
662 }
663
664
665 PGENERIC_LIST
666 CreateKeyboardLayoutList(HINF InfFile)
667 {
668 CHAR Buffer[128];
669 PGENERIC_LIST List;
670 PINFCONTEXT Context;
671 PWCHAR KeyName;
672 PWCHAR KeyValue;
673 PWCHAR UserData;
674 WCHAR DefaultLayout[20];
675
676 /* Get default layout id */
677 if (!InfFindFirstLine (InfFile, L"NLS", L"DefaultLayout", &Context))
678 return NULL;
679
680 if (!InfGetData (Context, NULL, &KeyValue))
681 {
682 InfFreeContext(Context);
683 return NULL;
684 }
685
686 wcscpy(DefaultLayout, KeyValue);
687 InfFreeContext(Context);
688
689 List = CreateGenericList();
690 if (List == NULL)
691 return NULL;
692
693 if (!InfFindFirstLine (InfFile, L"KeyboardLayout", NULL, &Context))
694 {
695 DestroyGenericList(List, FALSE);
696 InfFreeContext(Context);
697 return NULL;
698 }
699
700 do
701 {
702 if (!InfGetData (Context, &KeyName, &KeyValue))
703 {
704 /* FIXME: Handle error! */
705 DPRINT("InfGetData() failed\n");
706 break;
707 }
708
709 UserData = RtlAllocateHeap(ProcessHeap,
710 0,
711 (wcslen(KeyName) + 1) * sizeof(WCHAR));
712 if (UserData == NULL)
713 {
714 /* FIXME: Handle error! */
715 }
716
717 wcscpy(UserData, KeyName);
718
719 sprintf(Buffer, "%S", KeyValue);
720 AppendGenericListEntry(List,
721 Buffer,
722 UserData,
723 _wcsicmp(KeyName, DefaultLayout) ? FALSE : TRUE);
724 }
725 while (InfFindNextLine(Context, Context));
726 InfFreeContext(Context);
727
728 return List;
729 }
730
731
732 BOOLEAN
733 ProcessKeyboardLayoutRegistry(PGENERIC_LIST List)
734 {
735 PGENERIC_LIST_ENTRY Entry;
736 PWCHAR LanguageId;
737 OBJECT_ATTRIBUTES ObjectAttributes;
738 UNICODE_STRING KeyName;
739 UNICODE_STRING ValueName;
740 HANDLE KeyHandle;
741 NTSTATUS Status;
742
743 Entry = GetGenericListEntry(List);
744 if (Entry == NULL)
745 return FALSE;
746
747 LanguageId = (PWCHAR)Entry->UserData;
748 if (LanguageId == NULL)
749 return FALSE;
750
751 /* Open the nls language key */
752 RtlInitUnicodeString(&KeyName,
753 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
754 InitializeObjectAttributes(&ObjectAttributes,
755 &KeyName,
756 OBJ_CASE_INSENSITIVE,
757 NULL,
758 NULL);
759 Status = NtOpenKey(&KeyHandle,
760 KEY_ALL_ACCESS,
761 &ObjectAttributes);
762 if (!NT_SUCCESS(Status))
763 {
764 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
765 return FALSE;
766 }
767
768 /* Set default language */
769 RtlInitUnicodeString(&ValueName,
770 L"Default");
771 Status = NtSetValueKey (KeyHandle,
772 &ValueName,
773 0,
774 REG_SZ,
775 (PVOID)(LanguageId + 4),
776 8);
777 if (!NT_SUCCESS(Status))
778 {
779 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
780 NtClose(KeyHandle);
781 return FALSE;
782 }
783
784 /* Set install language */
785 RtlInitUnicodeString(&ValueName,
786 L"InstallLanguage");
787 Status = NtSetValueKey (KeyHandle,
788 &ValueName,
789 0,
790 REG_SZ,
791 (PVOID)(LanguageId + 4),
792 8);
793 if (!NT_SUCCESS(Status))
794 {
795 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
796 NtClose(KeyHandle);
797 return FALSE;
798 }
799
800 NtClose(KeyHandle);
801
802 return TRUE;
803 }
804
805
806 #if 0
807 BOOLEAN
808 ProcessKeyboardLayoutFiles(PGENERIC_LIST List)
809 {
810 return TRUE;
811 }
812 #endif
813
814 /* EOF */