- userinit, usetup, vmwinst, welcome, winefile, winlogon, winver.
[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 WCHAR RegPath [255];
509 PWCHAR Buffer;
510 ULONG Width, Hight, Bpp;
511
512 DPRINT("ProcessDisplayRegistry() called\n");
513
514 Entry = GetGenericListEntry(List);
515 if (Entry == NULL)
516 {
517 DPRINT("GetGenericListEntry() failed\n");
518 return FALSE;
519 }
520
521 if (!InfFindFirstLine(InfFile, L"Display", Entry->UserData, &Context))
522 {
523 DPRINT("InfFindFirstLine() failed\n");
524 return FALSE;
525 }
526
527 /* Enable the right driver */
528 if (!InfGetDataField(Context, 3, &ServiceName))
529 {
530 DPRINT("InfGetDataField() failed\n");
531 return FALSE;
532 }
533
534 ASSERT(wcslen(ServiceName) < 10);
535 DPRINT("Service name: %S\n", ServiceName);
536
537 StartValue = 1;
538 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
539 ServiceName,
540 L"Start",
541 REG_DWORD,
542 &StartValue,
543 sizeof(ULONG));
544
545 if (!NT_SUCCESS(Status))
546 {
547 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
548 return FALSE;
549 }
550
551 /* Set the resolution */
552 swprintf(RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0", ServiceName);
553
554 if (!InfGetDataField(Context, 4, &Buffer))
555 {
556 DPRINT("InfGetDataField() failed\n");
557 return FALSE;
558 }
559 Width = wcstoul(Buffer, NULL, 10);
560 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
561 RegPath,
562 L"DefaultSettings.XResolution",
563 REG_DWORD,
564 &Width,
565 sizeof(ULONG));
566 if (!NT_SUCCESS(Status))
567 {
568 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
569 return FALSE;
570 }
571
572
573 if (!InfGetDataField(Context, 5, &Buffer))
574 {
575 DPRINT("InfGetDataField() failed\n");
576 return FALSE;
577 }
578 Hight = wcstoul(Buffer, 0, 0);
579 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
580 RegPath,
581 L"DefaultSettings.YResolution",
582 REG_DWORD,
583 &Hight,
584 sizeof(ULONG));
585 if (!NT_SUCCESS(Status))
586 {
587 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
588 return FALSE;
589 }
590
591 if (!InfGetDataField(Context, 6, &Buffer))
592 {
593 DPRINT("InfGetDataField() failed\n");
594 return FALSE;
595 }
596 Bpp = wcstoul(Buffer, 0, 0);
597 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
598 RegPath,
599 L"DefaultSettings.BitsPerPel",
600 REG_DWORD,
601 &Bpp,
602 sizeof(ULONG));
603 if (!NT_SUCCESS(Status))
604 {
605 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
606 return FALSE;
607 }
608
609 InfFreeContext(Context);
610
611 DPRINT("ProcessDisplayRegistry() done\n");
612
613 return TRUE;
614 }
615
616
617 PGENERIC_LIST
618 CreateKeyboardDriverList(HINF InfFile)
619 {
620 CHAR Buffer[128];
621 PGENERIC_LIST List;
622 PINFCONTEXT Context;
623 PWCHAR KeyName;
624 PWCHAR KeyValue;
625 PWCHAR UserData;
626
627 List = CreateGenericList();
628 if (List == NULL)
629 return NULL;
630
631 if (!InfFindFirstLine (InfFile, L"Keyboard", NULL, &Context))
632 {
633 DestroyGenericList(List, FALSE);
634 return NULL;
635 }
636
637 do
638 {
639 if (!InfGetData (Context, &KeyName, &KeyValue))
640 {
641 /* FIXME: Handle error! */
642 DPRINT("InfGetData() failed\n");
643 break;
644 }
645
646 UserData = RtlAllocateHeap(ProcessHeap,
647 0,
648 (wcslen(KeyName) + 1) * sizeof(WCHAR));
649 if (UserData == NULL)
650 {
651 /* FIXME: Handle error! */
652 }
653
654 wcscpy(UserData, KeyName);
655
656 sprintf(Buffer, "%S", KeyValue);
657 AppendGenericListEntry(List, Buffer, UserData, FALSE);
658 }
659 while (InfFindNextLine(Context, Context));
660 InfFreeContext(Context);
661
662 return List;
663 }
664
665
666 PGENERIC_LIST
667 CreateKeyboardLayoutList(HINF InfFile)
668 {
669 CHAR Buffer[128];
670 PGENERIC_LIST List;
671 PINFCONTEXT Context;
672 PWCHAR KeyName;
673 PWCHAR KeyValue;
674 PWCHAR UserData;
675 WCHAR DefaultLayout[20];
676
677 /* Get default layout id */
678 if (!InfFindFirstLine (InfFile, L"NLS", L"DefaultLayout", &Context))
679 return NULL;
680
681 if (!InfGetData (Context, NULL, &KeyValue))
682 {
683 InfFreeContext(Context);
684 return NULL;
685 }
686
687 wcscpy(DefaultLayout, KeyValue);
688 InfFreeContext(Context);
689
690 List = CreateGenericList();
691 if (List == NULL)
692 return NULL;
693
694 if (!InfFindFirstLine (InfFile, L"KeyboardLayout", NULL, &Context))
695 {
696 DestroyGenericList(List, FALSE);
697 InfFreeContext(Context);
698 return NULL;
699 }
700
701 do
702 {
703 if (!InfGetData (Context, &KeyName, &KeyValue))
704 {
705 /* FIXME: Handle error! */
706 DPRINT("InfGetData() failed\n");
707 break;
708 }
709
710 UserData = RtlAllocateHeap(ProcessHeap,
711 0,
712 (wcslen(KeyName) + 1) * sizeof(WCHAR));
713 if (UserData == NULL)
714 {
715 /* FIXME: Handle error! */
716 }
717
718 wcscpy(UserData, KeyName);
719
720 sprintf(Buffer, "%S", KeyValue);
721 AppendGenericListEntry(List,
722 Buffer,
723 UserData,
724 _wcsicmp(KeyName, DefaultLayout) ? FALSE : TRUE);
725 }
726 while (InfFindNextLine(Context, Context));
727 InfFreeContext(Context);
728
729 return List;
730 }
731
732
733 BOOLEAN
734 ProcessKeyboardLayoutRegistry(PGENERIC_LIST List)
735 {
736 PGENERIC_LIST_ENTRY Entry;
737 PWCHAR LanguageId;
738 OBJECT_ATTRIBUTES ObjectAttributes;
739 UNICODE_STRING KeyName;
740 UNICODE_STRING ValueName;
741 HANDLE KeyHandle;
742 NTSTATUS Status;
743
744 Entry = GetGenericListEntry(List);
745 if (Entry == NULL)
746 return FALSE;
747
748 LanguageId = (PWCHAR)Entry->UserData;
749 if (LanguageId == NULL)
750 return FALSE;
751
752 /* Open the nls language key */
753 RtlInitUnicodeString(&KeyName,
754 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
755 InitializeObjectAttributes(&ObjectAttributes,
756 &KeyName,
757 OBJ_CASE_INSENSITIVE,
758 NULL,
759 NULL);
760 Status = NtOpenKey(&KeyHandle,
761 KEY_ALL_ACCESS,
762 &ObjectAttributes);
763 if (!NT_SUCCESS(Status))
764 {
765 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
766 return FALSE;
767 }
768
769 /* Set default language */
770 RtlInitUnicodeString(&ValueName,
771 L"Default");
772 Status = NtSetValueKey (KeyHandle,
773 &ValueName,
774 0,
775 REG_SZ,
776 (PVOID)(LanguageId + 4),
777 8);
778 if (!NT_SUCCESS(Status))
779 {
780 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
781 NtClose(KeyHandle);
782 return FALSE;
783 }
784
785 /* Set install language */
786 RtlInitUnicodeString(&ValueName,
787 L"InstallLanguage");
788 Status = NtSetValueKey (KeyHandle,
789 &ValueName,
790 0,
791 REG_SZ,
792 (PVOID)(LanguageId + 4),
793 8);
794 if (!NT_SUCCESS(Status))
795 {
796 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
797 NtClose(KeyHandle);
798 return FALSE;
799 }
800
801 NtClose(KeyHandle);
802
803 return TRUE;
804 }
805
806
807 #if 0
808 BOOLEAN
809 ProcessKeyboardLayoutFiles(PGENERIC_LIST List)
810 {
811 return TRUE;
812 }
813 #endif
814
815 /* EOF */