Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / base / setup / usetup / registry.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003 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: subsys/system/usetup/registry.c
23 * PURPOSE: Registry creation functions
24 * PROGRAMMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "usetup.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 #ifdef __REACTOS__
35 #define FLG_ADDREG_BINVALUETYPE 0x00000001
36 #define FLG_ADDREG_NOCLOBBER 0x00000002
37 #define FLG_ADDREG_DELVAL 0x00000004
38 #define FLG_ADDREG_APPEND 0x00000008
39 #define FLG_ADDREG_KEYONLY 0x00000010
40 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
41 #define FLG_ADDREG_TYPE_SZ 0x00000000
42 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
43 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
44 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
45 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
46 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
47 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
48 #endif
49
50 #ifdef _M_IX86
51 #define Architecture L"x86"
52 #elif defined(_M_AMD64)
53 #define Architecture L"amd64"
54 #elif defined(_M_IA64)
55 #define Architecture L"ia64"
56 #elif defined(_M_ARM)
57 #define Architecture L"arm"
58 #elif defined(_M_PPC)
59 #define Architecture L"ppc"
60 #endif
61
62 #include <pshpack1.h>
63
64 typedef struct _REG_DISK_MOUNT_INFO
65 {
66 ULONG Signature;
67 LARGE_INTEGER StartingOffset;
68 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
69
70 #include <poppack.h>
71
72 /* FUNCTIONS ****************************************************************/
73
74 static BOOLEAN
75 GetRootKey (PWCHAR Name)
76 {
77 if (!_wcsicmp (Name, L"HKCR"))
78 {
79 wcscpy (Name, L"\\Registry\\Machine\\SOFTWARE\\Classes\\");
80 return TRUE;
81 }
82
83 if (!_wcsicmp (Name, L"HKCU"))
84 {
85 wcscpy (Name, L"\\Registry\\User\\.DEFAULT\\");
86 return TRUE;
87 }
88
89 if (!_wcsicmp (Name, L"HKLM"))
90 {
91 wcscpy (Name, L"\\Registry\\Machine\\");
92 return TRUE;
93 }
94
95 if (!_wcsicmp (Name, L"HKU"))
96 {
97 wcscpy (Name, L"\\Registry\\User\\");
98 return TRUE;
99 }
100
101 #if 0
102 if (!_wcsicmp (Name, L"HKR"))
103 return FALSE;
104 #endif
105
106 return FALSE;
107 }
108
109
110 /***********************************************************************
111 * append_multi_sz_value
112 *
113 * Append a multisz string to a multisz registry value.
114 */
115 #if 0
116 static void
117 append_multi_sz_value (HANDLE hkey,
118 const WCHAR *value,
119 const WCHAR *strings,
120 DWORD str_size )
121 {
122 DWORD size, type, total;
123 WCHAR *buffer, *p;
124
125 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
126 if (type != REG_MULTI_SZ) return;
127
128 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
129 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
130
131 /* compare each string against all the existing ones */
132 total = size;
133 while (*strings)
134 {
135 int len = strlenW(strings) + 1;
136
137 for (p = buffer; *p; p += strlenW(p) + 1)
138 if (!strcmpiW( p, strings )) break;
139
140 if (!*p) /* not found, need to append it */
141 {
142 memcpy( p, strings, len * sizeof(WCHAR) );
143 p[len] = 0;
144 total += len;
145 }
146 strings += len;
147 }
148 if (total != size)
149 {
150 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
151 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
152 }
153 done:
154 HeapFree( GetProcessHeap(), 0, buffer );
155 }
156 #endif
157
158 /***********************************************************************
159 * delete_multi_sz_value
160 *
161 * Remove a string from a multisz registry value.
162 */
163 #if 0
164 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
165 {
166 DWORD size, type;
167 WCHAR *buffer, *src, *dst;
168
169 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
170 if (type != REG_MULTI_SZ) return;
171 /* allocate double the size, one for value before and one for after */
172 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
173 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
174 src = buffer;
175 dst = buffer + size;
176 while (*src)
177 {
178 int len = strlenW(src) + 1;
179 if (strcmpiW( src, string ))
180 {
181 memcpy( dst, src, len * sizeof(WCHAR) );
182 dst += len;
183 }
184 src += len;
185 }
186 *dst++ = 0;
187 if (dst != buffer + 2*size) /* did we remove something? */
188 {
189 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
190 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
191 (BYTE *)(buffer + size), dst - (buffer + size) );
192 }
193 done:
194 HeapFree( GetProcessHeap(), 0, buffer );
195 }
196 #endif
197
198 /***********************************************************************
199 * do_reg_operation
200 *
201 * Perform an add/delete registry operation depending on the flags.
202 */
203 static BOOLEAN
204 do_reg_operation(HANDLE KeyHandle,
205 PUNICODE_STRING ValueName,
206 PINFCONTEXT Context,
207 ULONG Flags)
208 {
209 WCHAR EmptyStr = (WCHAR)0;
210 ULONG Type;
211 ULONG Size;
212
213 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
214 {
215 #if 0
216 if (ValueName)
217 {
218 RegDeleteValueW( KeyHandle, ValueName );
219 }
220 else
221 {
222 RegDeleteKeyW( KeyHandle, NULL );
223 }
224 #endif
225 return TRUE;
226 }
227
228 if (Flags & FLG_ADDREG_KEYONLY)
229 return TRUE;
230
231 #if 0
232 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
233 {
234 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
235 if (exists && (flags & FLG_ADDREG_NOCLOBBER))
236 return TRUE;
237 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
238 return TRUE;
239 }
240 #endif
241
242 switch (Flags & FLG_ADDREG_TYPE_MASK)
243 {
244 case FLG_ADDREG_TYPE_SZ:
245 Type = REG_SZ;
246 break;
247
248 case FLG_ADDREG_TYPE_MULTI_SZ:
249 Type = REG_MULTI_SZ;
250 break;
251
252 case FLG_ADDREG_TYPE_EXPAND_SZ:
253 Type = REG_EXPAND_SZ;
254 break;
255
256 case FLG_ADDREG_TYPE_BINARY:
257 Type = REG_BINARY;
258 break;
259
260 case FLG_ADDREG_TYPE_DWORD:
261 Type = REG_DWORD;
262 break;
263
264 case FLG_ADDREG_TYPE_NONE:
265 Type = REG_NONE;
266 break;
267
268 default:
269 Type = Flags >> 16;
270 break;
271 }
272
273 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
274 (Type == REG_DWORD && SetupGetFieldCount (Context) == 5))
275 {
276 PWCHAR Str = NULL;
277
278 if (Type == REG_MULTI_SZ)
279 {
280 if (!SetupGetMultiSzFieldW (Context, 5, NULL, 0, &Size))
281 Size = 0;
282
283 if (Size)
284 {
285 Str = (WCHAR*) RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
286 if (Str == NULL)
287 return FALSE;
288
289 SetupGetMultiSzFieldW (Context, 5, Str, Size, NULL);
290 }
291
292 if (Flags & FLG_ADDREG_APPEND)
293 {
294 if (Str == NULL)
295 return TRUE;
296
297 // append_multi_sz_value( hkey, value, str, size );
298
299 RtlFreeHeap (ProcessHeap, 0, Str);
300 return TRUE;
301 }
302 /* else fall through to normal string handling */
303 }
304 else
305 {
306 if (!SetupGetStringFieldW (Context, 5, NULL, 0, &Size))
307 Size = 0;
308
309 if (Size)
310 {
311 Str = (WCHAR*) RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
312 if (Str == NULL)
313 return FALSE;
314
315 SetupGetStringFieldW (Context, 5, Str, Size, NULL);
316 }
317 }
318
319 if (Type == REG_DWORD)
320 {
321 ULONG dw = Str ? wcstoul (Str, NULL, 0) : 0;
322
323 DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
324
325 #ifdef __REACTOS__
326 NtSetValueKey (KeyHandle,
327 ValueName,
328 0,
329 Type,
330 (PVOID)&dw,
331 sizeof(ULONG));
332 #else
333 RegSetValueExW(KeyHandle, ValueName, 0, Type, (const UCHAR*)&dw, sizeof(ULONG));
334 #endif
335 }
336 else
337 {
338 DPRINT("setting value %wZ to %S\n", ValueName, Str);
339
340 if (Str)
341 {
342 #ifdef __REACTOS__
343 NtSetValueKey (KeyHandle,
344 ValueName,
345 0,
346 Type,
347 (PVOID)Str,
348 Size * sizeof(WCHAR));
349 #else
350 RegSetValueExW(KeyHandle, ValueName, 0, Type, (const UCHAR*)Str, Size * sizeof(WCHAR));
351 #endif
352 }
353 else
354 {
355 #ifdef __REACTOS__
356 NtSetValueKey (KeyHandle,
357 ValueName,
358 0,
359 Type,
360 (PVOID)&EmptyStr,
361 sizeof(WCHAR));
362 #else
363 RegSetValueExW(KeyHandle, ValueName, 0, Type, (const UCHAR*)&EmptyStr, sizeof(WCHAR));
364 #endif
365 }
366 }
367 RtlFreeHeap (ProcessHeap, 0, Str);
368 }
369 else /* get the binary data */
370 {
371 PUCHAR Data = NULL;
372
373 if (!SetupGetBinaryField (Context, 5, NULL, 0, &Size))
374 Size = 0;
375
376 if (Size)
377 {
378 Data = (unsigned char*) RtlAllocateHeap (ProcessHeap, 0, Size);
379 if (Data == NULL)
380 return FALSE;
381
382 DPRINT("setting binary data %wZ len %lu\n", ValueName, Size);
383 SetupGetBinaryField (Context, 5, Data, Size, NULL);
384 }
385
386 #ifdef __REACTOS__
387 NtSetValueKey (KeyHandle,
388 ValueName,
389 0,
390 Type,
391 (PVOID)Data,
392 Size);
393 #else
394 RegSetValueExW(KeyHandle, ValueName, 0, Type, (const UCHAR*)Data, Size);
395 #endif
396
397 RtlFreeHeap (ProcessHeap, 0, Data);
398 }
399
400 return TRUE;
401 }
402
403 #ifdef __REACTOS__
404 NTSTATUS
405 CreateNestedKey (PHANDLE KeyHandle,
406 ACCESS_MASK DesiredAccess,
407 POBJECT_ATTRIBUTES ObjectAttributes)
408 {
409 OBJECT_ATTRIBUTES LocalObjectAttributes;
410 UNICODE_STRING LocalKeyName;
411 ULONG Disposition;
412 NTSTATUS Status;
413 USHORT FullNameLength;
414 PWCHAR Ptr;
415 HANDLE LocalKeyHandle;
416
417 Status = NtCreateKey (KeyHandle,
418 KEY_ALL_ACCESS,
419 ObjectAttributes,
420 0,
421 NULL,
422 0,
423 &Disposition);
424 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
425 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
426 return Status;
427
428 /* Copy object attributes */
429 RtlCopyMemory (&LocalObjectAttributes,
430 ObjectAttributes,
431 sizeof(OBJECT_ATTRIBUTES));
432 RtlCreateUnicodeString (&LocalKeyName,
433 ObjectAttributes->ObjectName->Buffer);
434 LocalObjectAttributes.ObjectName = &LocalKeyName;
435 FullNameLength = LocalKeyName.Length;
436
437 /* Remove the last part of the key name and try to create the key again. */
438 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
439 {
440 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
441 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
442 {
443 Status = STATUS_UNSUCCESSFUL;
444 break;
445 }
446 *Ptr = (WCHAR)0;
447 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
448
449 Status = NtCreateKey (&LocalKeyHandle,
450 KEY_ALL_ACCESS,
451 &LocalObjectAttributes,
452 0,
453 NULL,
454 0,
455 &Disposition);
456 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
457 }
458
459 if (!NT_SUCCESS(Status))
460 {
461 RtlFreeUnicodeString (&LocalKeyName);
462 return Status;
463 }
464
465 /* Add removed parts of the key name and create them too. */
466 while (TRUE)
467 {
468 if (LocalKeyName.Length == FullNameLength)
469 {
470 Status = STATUS_SUCCESS;
471 *KeyHandle = LocalKeyHandle;
472 break;
473 }
474 NtClose (LocalKeyHandle);
475
476 LocalKeyName.Buffer[LocalKeyName.Length / sizeof(WCHAR)] = L'\\';
477 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
478
479 Status = NtCreateKey (&LocalKeyHandle,
480 KEY_ALL_ACCESS,
481 &LocalObjectAttributes,
482 0,
483 NULL,
484 0,
485 &Disposition);
486 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
487 if (!NT_SUCCESS(Status))
488 break;
489 }
490
491 RtlFreeUnicodeString (&LocalKeyName);
492
493 return Status;
494 }
495 #endif
496
497 /***********************************************************************
498 * registry_callback
499 *
500 * Called once for each AddReg and DelReg entry in a given section.
501 */
502 static BOOLEAN
503 registry_callback (HINF hInf, PCWSTR Section, BOOLEAN Delete)
504 {
505 OBJECT_ATTRIBUTES ObjectAttributes;
506 WCHAR Buffer[MAX_INF_STRING_LENGTH];
507 UNICODE_STRING Name;
508 UNICODE_STRING Value;
509 PUNICODE_STRING ValuePtr;
510 NTSTATUS Status;
511 UINT Flags;
512 ULONG Length;
513
514 INFCONTEXT Context;
515 HANDLE KeyHandle;
516 BOOLEAN Ok;
517
518
519 Ok = SetupFindFirstLineW (hInf, Section, NULL, &Context);
520
521 if (Ok)
522 {
523 for (;Ok; Ok = SetupFindNextLine (&Context, &Context))
524 {
525 /* get root */
526 if (!SetupGetStringFieldW (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
527 continue;
528 if (!GetRootKey (Buffer))
529 continue;
530
531 /* get key */
532 Length = wcslen (Buffer);
533 if (!SetupGetStringFieldW (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
534 *Buffer = 0;
535
536 DPRINT("KeyName: <%S>\n", Buffer);
537
538 /* get flags */
539 if (!SetupGetIntField (&Context, 4, (PINT)&Flags))
540 Flags = 0;
541
542 DPRINT("Flags: %lx\n", Flags);
543
544 #ifdef __REACTOS__
545 RtlInitUnicodeString (&Name,
546 Buffer);
547
548 InitializeObjectAttributes (&ObjectAttributes,
549 &Name,
550 OBJ_CASE_INSENSITIVE,
551 NULL,
552 NULL);
553
554 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
555 {
556 Status = NtOpenKey (&KeyHandle,
557 KEY_ALL_ACCESS,
558 &ObjectAttributes);
559 if (!NT_SUCCESS(Status))
560 {
561 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
562 continue; /* ignore if it doesn't exist */
563 }
564 }
565 else
566 {
567 Status = CreateNestedKey (&KeyHandle,
568 KEY_ALL_ACCESS,
569 &ObjectAttributes);
570 if (!NT_SUCCESS(Status))
571 {
572 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
573 continue;
574 }
575 }
576 #else
577 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
578 {
579 LONG rc = RegOpenKeyW(NULL, Buffer, &KeyHandle);
580 if (rc != ERROR_SUCCESS)
581 {
582 DPRINT("RegOpenKeyW(%S) failed (error %lu)\n", Buffer, rc);
583 continue; /* ignore if it doesn't exist */
584 }
585 }
586 else
587 {
588 LONG rc = RegCreateKeyW(NULL, Buffer, &KeyHandle);
589 if (rc != ERROR_SUCCESS)
590 {
591 DPRINT("RegCreateKeyW(%S) failed (error %lu)\n", Buffer, rc);
592 continue;
593 }
594 }
595 #endif
596
597 /* get value name */
598 if (SetupGetStringFieldW (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
599 {
600 RtlInitUnicodeString (&Value,
601 Buffer);
602 ValuePtr = &Value;
603 }
604 else
605 {
606 ValuePtr = NULL;
607 }
608
609 /* and now do it */
610 if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
611 {
612 NtClose (KeyHandle);
613 return FALSE;
614 }
615
616 #ifdef __REACTOS__
617 NtClose (KeyHandle);
618 #endif
619 }
620 }
621
622 return TRUE;
623 }
624
625
626 BOOLEAN
627 ImportRegistryFile(PWSTR Filename,
628 PWSTR Section,
629 LCID LocaleId,
630 BOOLEAN Delete)
631 {
632 WCHAR FileNameBuffer[MAX_PATH];
633 HINF hInf;
634 UINT ErrorLine;
635
636 /* Load inf file from install media. */
637 wcscpy(FileNameBuffer, SourcePath.Buffer);
638 wcscat(FileNameBuffer, L"\\");
639 wcscat(FileNameBuffer, Filename);
640
641 hInf = SetupOpenInfFileW(
642 FileNameBuffer,
643 NULL,
644 INF_STYLE_WIN4,
645 LocaleId,
646 &ErrorLine);
647 if (hInf == INVALID_HANDLE_VALUE)
648 {
649 DPRINT1("SetupOpenInfFile() failed\n");
650 return FALSE;
651 }
652
653 if (!registry_callback (hInf, L"AddReg", FALSE))
654 {
655 DPRINT1("registry_callback() failed\n");
656 }
657
658 if (!registry_callback (hInf, L"AddReg.NT" Architecture, FALSE))
659 {
660 DPRINT1("registry_callback() failed\n");
661 }
662
663 InfCloseFile (hInf);
664
665 return TRUE;
666 }
667
668
669 BOOLEAN
670 SetInstallPathValue(PUNICODE_STRING InstallPath)
671 {
672 OBJECT_ATTRIBUTES ObjectAttributes;
673 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
674 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
675 HANDLE KeyHandle;
676 NTSTATUS Status;
677
678 /* Create the 'secret' InstallPath key */
679 InitializeObjectAttributes (&ObjectAttributes,
680 &KeyName,
681 OBJ_CASE_INSENSITIVE,
682 NULL,
683 NULL);
684 Status = NtOpenKey (&KeyHandle,
685 KEY_ALL_ACCESS,
686 &ObjectAttributes);
687 if (!NT_SUCCESS(Status))
688 {
689 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
690 return FALSE;
691 }
692
693 Status = NtSetValueKey (KeyHandle,
694 &ValueName,
695 0,
696 REG_SZ,
697 (PVOID)InstallPath->Buffer,
698 InstallPath->Length + sizeof(WCHAR));
699 NtClose(KeyHandle);
700 if (!NT_SUCCESS(Status))
701 {
702 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
703 return FALSE;
704 }
705
706 return TRUE;
707 }
708
709 BOOLEAN
710 SetMountedDeviceValue(CHAR Letter, ULONG Signature, LARGE_INTEGER StartingOffset)
711 {
712 OBJECT_ATTRIBUTES ObjectAttributes;
713 WCHAR ValueNameBuffer[16];
714 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
715 UNICODE_STRING ValueName;
716 REG_DISK_MOUNT_INFO MountInfo;
717 NTSTATUS Status;
718 HANDLE KeyHandle;
719
720 swprintf(ValueNameBuffer, L"\\DosDevices\\%C:", Letter);
721 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
722
723 InitializeObjectAttributes (&ObjectAttributes,
724 &KeyName,
725 OBJ_CASE_INSENSITIVE,
726 NULL,
727 NULL);
728 Status = NtOpenKey (&KeyHandle,
729 KEY_ALL_ACCESS,
730 &ObjectAttributes);
731 if (!NT_SUCCESS(Status))
732 {
733 Status = NtCreateKey(&KeyHandle,
734 KEY_ALL_ACCESS,
735 &ObjectAttributes,
736 0,
737 NULL,
738 REG_OPTION_NON_VOLATILE,
739 NULL);
740 }
741
742 if (!NT_SUCCESS(Status))
743 {
744 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
745 return FALSE;
746 }
747
748 MountInfo.Signature = Signature;
749 MountInfo.StartingOffset = StartingOffset;
750 Status = NtSetValueKey (KeyHandle,
751 &ValueName,
752 0,
753 REG_BINARY,
754 (PVOID)&MountInfo,
755 sizeof(MountInfo));
756 NtClose(KeyHandle);
757 if (!NT_SUCCESS(Status))
758 {
759 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
760 return FALSE;
761 }
762
763 return TRUE;
764 }
765
766 /* EOF */