implemented RegCopyTreeW() (untested!)
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/reg/reg.c
6 * PURPOSE: Registry functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 * 19990309 EA Stubs
11 * 20050502 Fireball imported some stuff from WINE
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <advapi32.h>
17 #define NDEBUG
18 #include <wine/debug.h>
19
20 /* DEFINES ******************************************************************/
21
22 #define MAX_DEFAULT_HANDLES 6
23 #define REG_MAX_NAME_SIZE 256
24 #define REG_MAX_DATA_SIZE 2048
25
26 /* FIXME: should go into msvcrt.h header? */
27 #define offsetof(s,m) (size_t)&(((s*)NULL)->m)
28
29 /* GLOBALS ******************************************************************/
30
31 static RTL_CRITICAL_SECTION HandleTableCS;
32 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
33 static HANDLE ProcessHeap;
34 static BOOLEAN DefaultHandlesDisabled = FALSE;
35
36 /* PROTOTYPES ***************************************************************/
37
38 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
39 static VOID CloseDefaultKeys(VOID);
40 #define CloseDefaultKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
42 NtClose(Handle); \
43 }
44
45 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
46 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
47 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
48 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
49
50
51 /* FUNCTIONS ****************************************************************/
52 /* check if value type needs string conversion (Ansi<->Unicode) */
53 inline static int is_string( DWORD type )
54 {
55 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
56 }
57
58 /************************************************************************
59 * RegInitDefaultHandles
60 */
61 BOOL
62 RegInitialize (VOID)
63 {
64 TRACE("RegInitialize()\n");
65
66 ProcessHeap = RtlGetProcessHeap();
67 RtlZeroMemory (DefaultHandleTable,
68 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
69 RtlInitializeCriticalSection (&HandleTableCS);
70
71 return TRUE;
72 }
73
74
75 /************************************************************************
76 * RegInit
77 */
78 BOOL
79 RegCleanup (VOID)
80 {
81 TRACE("RegCleanup()\n");
82
83 CloseDefaultKeys ();
84 RtlDeleteCriticalSection (&HandleTableCS);
85
86 return TRUE;
87 }
88
89
90 static NTSTATUS
91 MapDefaultKey (OUT PHANDLE RealKey,
92 IN HKEY Key)
93 {
94 PHANDLE Handle;
95 ULONG Index;
96 BOOLEAN DoOpen;
97 NTSTATUS Status = STATUS_SUCCESS;
98
99 TRACE("MapDefaultKey (Key %x)\n", Key);
100
101 if (((ULONG)Key & 0xF0000000) != 0x80000000)
102 {
103 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
104 return STATUS_SUCCESS;
105 }
106
107 /* Handle special cases here */
108 Index = (ULONG)Key & 0x0FFFFFFF;
109 if (Index >= MAX_DEFAULT_HANDLES)
110 {
111 return STATUS_INVALID_PARAMETER;
112 }
113
114 RtlEnterCriticalSection (&HandleTableCS);
115
116 if (!DefaultHandlesDisabled)
117 {
118 Handle = &DefaultHandleTable[Index];
119 DoOpen = (*Handle == NULL);
120 }
121 else
122 {
123 Handle = RealKey;
124 DoOpen = TRUE;
125 }
126
127 if (DoOpen)
128 {
129 /* create/open the default handle */
130 switch (Index)
131 {
132 case 0: /* HKEY_CLASSES_ROOT */
133 Status = OpenClassesRootKey (Handle);
134 break;
135
136 case 1: /* HKEY_CURRENT_USER */
137 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
138 Handle);
139 break;
140
141 case 2: /* HKEY_LOCAL_MACHINE */
142 Status = OpenLocalMachineKey (Handle);
143 break;
144
145 case 3: /* HKEY_USERS */
146 Status = OpenUsersKey (Handle);
147 break;
148 #if 0
149 case 4: /* HKEY_PERFORMANCE_DATA */
150 Status = OpenPerformanceDataKey (Handle);
151 break;
152 #endif
153 case 5: /* HKEY_CURRENT_CONFIG */
154 Status = OpenCurrentConfigKey (Handle);
155 break;
156
157 case 6: /* HKEY_DYN_DATA */
158 Status = STATUS_NOT_IMPLEMENTED;
159 break;
160
161 default:
162 WARN("MapDefaultHandle() no handle creator\n");
163 Status = STATUS_INVALID_PARAMETER;
164 break;
165 }
166 }
167
168 if (NT_SUCCESS(Status))
169 {
170 if (!DefaultHandlesDisabled)
171 *RealKey = *Handle;
172 else
173 *(PULONG_PTR)Handle |= 0x1;
174 }
175
176 RtlLeaveCriticalSection (&HandleTableCS);
177
178 return Status;
179 }
180
181
182 static VOID
183 CloseDefaultKeys (VOID)
184 {
185 ULONG i;
186
187 RtlEnterCriticalSection (&HandleTableCS);
188 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
189 {
190 if (DefaultHandleTable[i] != NULL)
191 {
192 NtClose (DefaultHandleTable[i]);
193 DefaultHandleTable[i] = NULL;
194 }
195 }
196 RtlLeaveCriticalSection (&HandleTableCS);
197 }
198
199
200 static NTSTATUS
201 OpenClassesRootKey (PHANDLE KeyHandle)
202 {
203 OBJECT_ATTRIBUTES Attributes;
204 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
205
206 TRACE("OpenClassesRootKey()\n");
207
208 InitializeObjectAttributes (&Attributes,
209 &KeyName,
210 OBJ_CASE_INSENSITIVE,
211 NULL,
212 NULL);
213 return NtOpenKey (KeyHandle,
214 MAXIMUM_ALLOWED,
215 &Attributes);
216 }
217
218
219 static NTSTATUS
220 OpenLocalMachineKey (PHANDLE KeyHandle)
221 {
222 OBJECT_ATTRIBUTES Attributes;
223 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
224 NTSTATUS Status;
225
226 TRACE("OpenLocalMachineKey()\n");
227
228 InitializeObjectAttributes (&Attributes,
229 &KeyName,
230 OBJ_CASE_INSENSITIVE,
231 NULL,
232 NULL);
233 Status = NtOpenKey (KeyHandle,
234 MAXIMUM_ALLOWED,
235 &Attributes);
236
237 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
238 return Status;
239 }
240
241
242 static NTSTATUS
243 OpenUsersKey (PHANDLE KeyHandle)
244 {
245 OBJECT_ATTRIBUTES Attributes;
246 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
247
248 TRACE("OpenUsersKey()\n");
249
250 InitializeObjectAttributes (&Attributes,
251 &KeyName,
252 OBJ_CASE_INSENSITIVE,
253 NULL,
254 NULL);
255 return NtOpenKey (KeyHandle,
256 MAXIMUM_ALLOWED,
257 &Attributes);
258 }
259
260
261 static NTSTATUS
262 OpenCurrentConfigKey (PHANDLE KeyHandle)
263 {
264 OBJECT_ATTRIBUTES Attributes;
265 UNICODE_STRING KeyName =
266 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
267
268 TRACE("OpenCurrentConfigKey()\n");
269
270 InitializeObjectAttributes (&Attributes,
271 &KeyName,
272 OBJ_CASE_INSENSITIVE,
273 NULL,
274 NULL);
275 return NtOpenKey (KeyHandle,
276 MAXIMUM_ALLOWED,
277 &Attributes);
278 }
279
280
281 /************************************************************************
282 * RegDisablePredefinedCacheEx
283 *
284 * @implemented
285 */
286 LONG STDCALL
287 RegDisablePredefinedCacheEx(VOID)
288 {
289 RtlEnterCriticalSection (&HandleTableCS);
290 DefaultHandlesDisabled = TRUE;
291 RtlLeaveCriticalSection (&HandleTableCS);
292 return ERROR_SUCCESS;
293 }
294
295
296 /************************************************************************
297 * RegCloseKey
298 *
299 * @implemented
300 */
301 LONG STDCALL
302 RegCloseKey (HKEY hKey)
303 {
304 NTSTATUS Status;
305
306 /* don't close null handle or a pseudo handle */
307 if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
308 {
309 return ERROR_INVALID_HANDLE;
310 }
311
312 Status = NtClose (hKey);
313 if (!NT_SUCCESS(Status))
314 {
315 return RtlNtStatusToDosError (Status);
316 }
317
318 return ERROR_SUCCESS;
319 }
320
321
322 static NTSTATUS
323 RegpCopyTree(IN HKEY hKeySrc,
324 IN HKEY hKeyDest)
325 {
326 typedef struct
327 {
328 LIST_ENTRY ListEntry;
329 HANDLE hKeySrc;
330 HANDLE hKeyDest;
331 } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
332
333 LIST_ENTRY copyQueueHead;
334 PREGP_COPY_KEYS copyKeys, newCopyKeys;
335 union
336 {
337 KEY_VALUE_FULL_INFORMATION *KeyValue;
338 KEY_NODE_INFORMATION *KeyNode;
339 PVOID Buffer;
340 } Info;
341 ULONG Index, BufferSizeRequired, BufferSize = 0x200;
342 NTSTATUS Status = STATUS_SUCCESS;
343 NTSTATUS Status2 = STATUS_SUCCESS;
344
345 InitializeListHead(&copyQueueHead);
346
347 Info.Buffer = RtlAllocateHeap(ProcessHeap,
348 0,
349 BufferSize);
350 if (Info.Buffer == NULL)
351 {
352 return STATUS_INSUFFICIENT_RESOURCES;
353 }
354
355 copyKeys = RtlAllocateHeap(ProcessHeap,
356 0,
357 sizeof(REGP_COPY_KEYS));
358 if (copyKeys != NULL)
359 {
360 copyKeys->hKeySrc = hKeySrc;
361 copyKeys->hKeyDest = hKeyDest;
362 InsertHeadList(&copyQueueHead,
363 &copyKeys->ListEntry);
364
365 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
366
367 do
368 {
369 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
370 REGP_COPY_KEYS,
371 ListEntry);
372
373 /* enumerate all values and copy them */
374 Index = 0;
375 for (;;)
376 {
377 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
378 Index,
379 KeyValueFullInformation,
380 Info.KeyValue,
381 BufferSize,
382 &BufferSizeRequired);
383 if (NT_SUCCESS(Status2))
384 {
385 UNICODE_STRING ValueName;
386 PVOID Data;
387
388 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
389 ValueName.Length = Info.KeyValue->NameLength;
390 ValueName.MaximumLength = ValueName.Length;
391 ValueName.Buffer = Info.KeyValue->Name;
392
393 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
394
395 Status2 = NtSetValueKey(copyKeys->hKeyDest,
396 &ValueName,
397 Info.KeyValue->TitleIndex,
398 Info.KeyValue->Type,
399 Data,
400 Info.KeyValue->DataLength);
401
402 /* don't break, let's try to copy as many values as possible */
403 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
404 {
405 Status = Status2;
406 }
407
408 Index++;
409 }
410 else if (Status2 == STATUS_BUFFER_OVERFLOW)
411 {
412 PVOID Buffer;
413
414 ASSERT(BufferSize < BufferSizeRequired);
415
416 Buffer = RtlReAllocateHeap(ProcessHeap,
417 0,
418 Info.Buffer,
419 BufferSizeRequired);
420 if (Buffer != NULL)
421 {
422 Info.Buffer = Buffer;
423 /* try again */
424 }
425 else
426 {
427 /* don't break, let's try to copy as many values as possible */
428 Status2 = STATUS_INSUFFICIENT_RESOURCES;
429 Index++;
430
431 if (NT_SUCCESS(Status))
432 {
433 Status = Status2;
434 }
435 }
436 }
437 else
438 {
439 /* break to avoid an infinite loop in case of denied access or
440 other errors! */
441 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
442 {
443 Status = Status2;
444 }
445
446 break;
447 }
448 }
449
450 /* enumerate all subkeys and open and enqueue them */
451 Index = 0;
452 for (;;)
453 {
454 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
455 Index,
456 KeyNodeInformation,
457 Info.KeyNode,
458 BufferSize,
459 &BufferSizeRequired);
460 if (NT_SUCCESS(Status2))
461 {
462 HANDLE KeyHandle, NewKeyHandle;
463 OBJECT_ATTRIBUTES ObjectAttributes;
464 UNICODE_STRING SubKeyName, ClassName;
465
466 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
467 SubKeyName.Length = Info.KeyNode->NameLength;
468 SubKeyName.MaximumLength = SubKeyName.Length;
469 SubKeyName.Buffer = Info.KeyNode->Name;
470 ClassName.Length = Info.KeyNode->ClassLength;
471 ClassName.MaximumLength = ClassName.Length;
472 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
473
474 /* open the subkey with sufficient rights */
475
476 InitializeObjectAttributes(&ObjectAttributes,
477 &SubKeyName,
478 OBJ_CASE_INSENSITIVE,
479 copyKeys->hKeySrc,
480 NULL);
481
482 Status2 = NtOpenKey(&KeyHandle,
483 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
484 &ObjectAttributes);
485 if (NT_SUCCESS(Status2))
486 {
487 /* FIXME - attempt to query the security information */
488
489 InitializeObjectAttributes(&ObjectAttributes,
490 &SubKeyName,
491 OBJ_CASE_INSENSITIVE,
492 copyKeys->hKeyDest,
493 NULL);
494
495 Status2 = NtCreateKey(&NewKeyHandle,
496 KEY_ALL_ACCESS,
497 &ObjectAttributes,
498 Info.KeyNode->TitleIndex,
499 &ClassName,
500 0,
501 NULL);
502 if (NT_SUCCESS(Status2))
503 {
504 newCopyKeys = RtlAllocateHeap(ProcessHeap,
505 0,
506 sizeof(REGP_COPY_KEYS));
507 if (newCopyKeys != NULL)
508 {
509 /* save the handles and enqueue the subkey */
510 newCopyKeys->hKeySrc = KeyHandle;
511 newCopyKeys->hKeyDest = NewKeyHandle;
512 InsertTailList(&copyQueueHead,
513 &newCopyKeys->ListEntry);
514 }
515 else
516 {
517 NtClose(KeyHandle);
518 NtClose(NewKeyHandle);
519
520 Status2 = STATUS_INSUFFICIENT_RESOURCES;
521 goto GoNextKey;
522 }
523 }
524 else
525 {
526 NtClose(KeyHandle);
527 }
528 }
529
530 GoNextKey:
531 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
532 {
533 Status = Status2;
534 }
535
536 Index++;
537 }
538 else if (Status2 == STATUS_BUFFER_OVERFLOW)
539 {
540 PVOID Buffer;
541
542 ASSERT(BufferSize < BufferSizeRequired);
543
544 Buffer = RtlReAllocateHeap(ProcessHeap,
545 0,
546 Info.Buffer,
547 BufferSizeRequired);
548 if (Buffer != NULL)
549 {
550 Info.Buffer = Buffer;
551 /* try again */
552 }
553 else
554 {
555 /* don't break, let's try to copy as many keys as possible */
556 Status2 = STATUS_INSUFFICIENT_RESOURCES;
557 Index++;
558
559 if (NT_SUCCESS(Status))
560 {
561 Status = Status2;
562 }
563 }
564 }
565 else
566 {
567 /* break to avoid an infinite loop in case of denied access or
568 other errors! */
569 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
570 {
571 Status = Status2;
572 }
573
574 break;
575 }
576 }
577
578 /* close the handles and remove the entry from the list */
579 if (copyKeys->hKeySrc != hKeySrc)
580 {
581 NtClose(copyKeys->hKeySrc);
582 }
583 if (copyKeys->hKeyDest != hKeyDest)
584 {
585 NtClose(copyKeys->hKeyDest);
586 }
587
588 RemoveEntryList(&copyKeys->ListEntry);
589
590 RtlFreeHeap(ProcessHeap,
591 0,
592 copyKeys);
593 } while (!IsListEmpty(&copyQueueHead));
594 }
595 else
596 Status = STATUS_INSUFFICIENT_RESOURCES;
597
598 RtlFreeHeap(ProcessHeap,
599 0,
600 Info.Buffer);
601
602 return Status;
603 }
604
605
606 /************************************************************************
607 * RegCopyTreeW
608 *
609 * @implemented
610 */
611 LONG STDCALL
612 RegCopyTreeW(IN HKEY hKeySrc,
613 IN LPCWSTR lpSubKey OPTIONAL,
614 IN HKEY hKeyDest)
615 {
616 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
617 NTSTATUS Status;
618
619 Status = MapDefaultKey(&KeyHandle,
620 hKeySrc);
621 if (!NT_SUCCESS(Status))
622 {
623 return RtlNtStatusToDosError(Status);
624 }
625
626 Status = MapDefaultKey(&DestKeyHandle,
627 hKeyDest);
628 if (!NT_SUCCESS(Status))
629 {
630 goto Cleanup2;
631 }
632
633 if (lpSubKey != NULL)
634 {
635 OBJECT_ATTRIBUTES ObjectAttributes;
636 UNICODE_STRING SubKeyName;
637
638 RtlInitUnicodeString(&SubKeyName,
639 (LPWSTR)lpSubKey);
640
641 InitializeObjectAttributes(&ObjectAttributes,
642 &SubKeyName,
643 OBJ_CASE_INSENSITIVE,
644 KeyHandle,
645 NULL);
646
647 Status = NtOpenKey(&SubKeyHandle,
648 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
649 &ObjectAttributes);
650 if (!NT_SUCCESS(Status))
651 {
652 goto Cleanup;
653 }
654
655 CurKey = SubKeyHandle;
656 }
657 else
658 CurKey = KeyHandle;
659
660 Status = RegpCopyTree(CurKey,
661 hKeyDest);
662
663 if (SubKeyHandle != NULL)
664 {
665 NtClose(SubKeyHandle);
666 }
667
668 Cleanup:
669 CloseDefaultKey(DestKeyHandle);
670 Cleanup2:
671 CloseDefaultKey(KeyHandle);
672
673 if (!NT_SUCCESS(Status))
674 {
675 return RtlNtStatusToDosError(Status);
676 }
677
678 return ERROR_SUCCESS;
679 }
680
681
682 /************************************************************************
683 * RegCopyTreeA
684 *
685 * @implemented
686 */
687 LONG STDCALL
688 RegCopyTreeA(IN HKEY hKeySrc,
689 IN LPCSTR lpSubKey OPTIONAL,
690 IN HKEY hKeyDest)
691 {
692 UNICODE_STRING SubKeyName = {0};
693 LONG Ret;
694
695 if (lpSubKey != NULL &&
696 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
697 (LPSTR)lpSubKey))
698 {
699 return ERROR_NOT_ENOUGH_MEMORY;
700 }
701
702 Ret = RegCopyTreeW(hKeySrc,
703 SubKeyName.Buffer,
704 hKeyDest);
705
706 RtlFreeUnicodeString(&SubKeyName);
707
708 return Ret;
709 }
710
711
712 /************************************************************************
713 * RegConnectRegistryA
714 *
715 * @implemented
716 */
717 LONG STDCALL
718 RegConnectRegistryA (IN LPCSTR lpMachineName,
719 IN HKEY hKey,
720 OUT PHKEY phkResult)
721 {
722 UNICODE_STRING MachineName = {0};
723 LONG Ret;
724
725 if (lpMachineName != NULL &&
726 !RtlCreateUnicodeStringFromAsciiz(&MachineName,
727 (LPSTR)lpMachineName))
728 {
729 return ERROR_NOT_ENOUGH_MEMORY;
730 }
731
732 Ret = RegConnectRegistryW(MachineName.Buffer,
733 hKey,
734 phkResult);
735
736 RtlFreeUnicodeString(&MachineName);
737
738 return Ret;
739 }
740
741
742 /************************************************************************
743 * RegConnectRegistryW
744 *
745 * @unimplemented
746 */
747 LONG STDCALL
748 RegConnectRegistryW (LPCWSTR lpMachineName,
749 HKEY hKey,
750 PHKEY phkResult)
751 {
752 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
753 return ERROR_CALL_NOT_IMPLEMENTED;
754 }
755
756
757 /************************************************************************
758 * CreateNestedKey
759 *
760 * Create key and all necessary intermediate keys
761 */
762 static NTSTATUS
763 CreateNestedKey(PHKEY KeyHandle,
764 POBJECT_ATTRIBUTES ObjectAttributes,
765 PUNICODE_STRING ClassString,
766 DWORD dwOptions,
767 REGSAM samDesired,
768 DWORD *lpdwDisposition)
769 {
770 OBJECT_ATTRIBUTES LocalObjectAttributes;
771 UNICODE_STRING LocalKeyName;
772 ULONG Disposition;
773 NTSTATUS Status;
774 ULONG FullNameLength;
775 ULONG Length;
776 PWCHAR Ptr;
777 HANDLE LocalKeyHandle;
778
779 Status = NtCreateKey((PHANDLE) KeyHandle,
780 samDesired,
781 ObjectAttributes,
782 0,
783 ClassString,
784 dwOptions,
785 (PULONG)lpdwDisposition);
786 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
787 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
788 return Status;
789
790 /* Copy object attributes */
791 RtlCopyMemory (&LocalObjectAttributes,
792 ObjectAttributes,
793 sizeof(OBJECT_ATTRIBUTES));
794 RtlCreateUnicodeString (&LocalKeyName,
795 ObjectAttributes->ObjectName->Buffer);
796 LocalObjectAttributes.ObjectName = &LocalKeyName;
797 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
798
799 /* Remove the last part of the key name and try to create the key again. */
800 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
801 {
802 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
803 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
804 {
805 Status = STATUS_UNSUCCESSFUL;
806 break;
807 }
808 *Ptr = (WCHAR)0;
809 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
810
811 Status = NtCreateKey (&LocalKeyHandle,
812 KEY_ALL_ACCESS,
813 &LocalObjectAttributes,
814 0,
815 NULL,
816 0,
817 &Disposition);
818 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
819 }
820
821 if (!NT_SUCCESS(Status))
822 {
823 RtlFreeUnicodeString (&LocalKeyName);
824 return Status;
825 }
826
827 /* Add removed parts of the key name and create them too. */
828 Length = wcslen (LocalKeyName.Buffer);
829 while (TRUE)
830 {
831 NtClose (LocalKeyHandle);
832
833 LocalKeyName.Buffer[Length] = L'\\';
834 Length = wcslen (LocalKeyName.Buffer);
835 LocalKeyName.Length = Length * sizeof(WCHAR);
836
837 if (Length == FullNameLength)
838 {
839 Status = NtCreateKey((PHANDLE) KeyHandle,
840 samDesired,
841 ObjectAttributes,
842 0,
843 ClassString,
844 dwOptions,
845 (PULONG)lpdwDisposition);
846 break;
847 }
848 Status = NtCreateKey (&LocalKeyHandle,
849 KEY_CREATE_SUB_KEY,
850 &LocalObjectAttributes,
851 0,
852 NULL,
853 0,
854 &Disposition);
855 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
856 if (!NT_SUCCESS(Status))
857 break;
858 }
859
860 RtlFreeUnicodeString (&LocalKeyName);
861
862 return Status;
863 }
864
865
866 /************************************************************************
867 * RegCreateKeyExA
868 *
869 * @implemented
870 */
871 LONG STDCALL
872 RegCreateKeyExA (HKEY hKey,
873 LPCSTR lpSubKey,
874 DWORD Reserved,
875 LPSTR lpClass,
876 DWORD dwOptions,
877 REGSAM samDesired,
878 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
879 PHKEY phkResult,
880 LPDWORD lpdwDisposition)
881 {
882 UNICODE_STRING SubKeyString;
883 UNICODE_STRING ClassString;
884 OBJECT_ATTRIBUTES Attributes;
885 HANDLE ParentKey;
886 NTSTATUS Status;
887
888 TRACE("RegCreateKeyExA() called\n");
889
890 /* get the real parent key */
891 Status = MapDefaultKey (&ParentKey,
892 hKey);
893 if (!NT_SUCCESS(Status))
894 {
895 return RtlNtStatusToDosError (Status);
896 }
897 TRACE("ParentKey %x\n", (ULONG)ParentKey);
898
899 if (lpClass != NULL)
900 {
901 RtlCreateUnicodeStringFromAsciiz (&ClassString,
902 lpClass);
903 }
904
905 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
906 (LPSTR)lpSubKey);
907 InitializeObjectAttributes (&Attributes,
908 &SubKeyString,
909 OBJ_CASE_INSENSITIVE,
910 (HANDLE)ParentKey,
911 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
912 Status = CreateNestedKey(phkResult,
913 &Attributes,
914 (lpClass == NULL)? NULL : &ClassString,
915 dwOptions,
916 samDesired,
917 lpdwDisposition);
918 RtlFreeUnicodeString (&SubKeyString);
919 if (lpClass != NULL)
920 {
921 RtlFreeUnicodeString (&ClassString);
922 }
923
924 CloseDefaultKey(ParentKey);
925
926 TRACE("Status %x\n", Status);
927 if (!NT_SUCCESS(Status))
928 {
929 return RtlNtStatusToDosError (Status);
930 }
931
932 return ERROR_SUCCESS;
933 }
934
935
936 /************************************************************************
937 * RegCreateKeyExW
938 *
939 * @implemented
940 */
941 LONG STDCALL
942 RegCreateKeyExW (HKEY hKey,
943 LPCWSTR lpSubKey,
944 DWORD Reserved,
945 LPWSTR lpClass,
946 DWORD dwOptions,
947 REGSAM samDesired,
948 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
949 PHKEY phkResult,
950 LPDWORD lpdwDisposition)
951 {
952 UNICODE_STRING SubKeyString;
953 UNICODE_STRING ClassString;
954 OBJECT_ATTRIBUTES Attributes;
955 HANDLE ParentKey;
956 NTSTATUS Status;
957
958 TRACE("RegCreateKeyExW() called\n");
959
960 /* get the real parent key */
961 Status = MapDefaultKey (&ParentKey,
962 hKey);
963 if (!NT_SUCCESS(Status))
964 {
965 return RtlNtStatusToDosError(Status);
966 }
967 TRACE("ParentKey %x\n", (ULONG)ParentKey);
968
969 RtlInitUnicodeString (&ClassString,
970 lpClass);
971 RtlInitUnicodeString (&SubKeyString,
972 lpSubKey);
973 InitializeObjectAttributes (&Attributes,
974 &SubKeyString,
975 OBJ_CASE_INSENSITIVE,
976 (HANDLE)ParentKey,
977 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
978 Status = CreateNestedKey(phkResult,
979 &Attributes,
980 (lpClass == NULL)? NULL : &ClassString,
981 dwOptions,
982 samDesired,
983 lpdwDisposition);
984
985 CloseDefaultKey(ParentKey);
986
987 TRACE("Status %x\n", Status);
988 if (!NT_SUCCESS(Status))
989 {
990 return RtlNtStatusToDosError (Status);
991 }
992
993 return ERROR_SUCCESS;
994 }
995
996
997 /************************************************************************
998 * RegCreateKeyA
999 *
1000 * @implemented
1001 */
1002 LONG STDCALL
1003 RegCreateKeyA (HKEY hKey,
1004 LPCSTR lpSubKey,
1005 PHKEY phkResult)
1006 {
1007 return RegCreateKeyExA (hKey,
1008 lpSubKey,
1009 0,
1010 NULL,
1011 0,
1012 MAXIMUM_ALLOWED,
1013 NULL,
1014 phkResult,
1015 NULL);
1016 }
1017
1018
1019 /************************************************************************
1020 * RegCreateKeyW
1021 *
1022 * @implemented
1023 */
1024 LONG STDCALL
1025 RegCreateKeyW (HKEY hKey,
1026 LPCWSTR lpSubKey,
1027 PHKEY phkResult)
1028 {
1029 return RegCreateKeyExW (hKey,
1030 lpSubKey,
1031 0,
1032 NULL,
1033 0,
1034 MAXIMUM_ALLOWED,
1035 NULL,
1036 phkResult,
1037 NULL);
1038 }
1039
1040
1041 /************************************************************************
1042 * RegDeleteKeyA
1043 *
1044 * @implemented
1045 */
1046 LONG STDCALL
1047 RegDeleteKeyA (HKEY hKey,
1048 LPCSTR lpSubKey)
1049 {
1050 OBJECT_ATTRIBUTES ObjectAttributes;
1051 UNICODE_STRING SubKeyName;
1052 HANDLE ParentKey;
1053 HANDLE TargetKey;
1054 NTSTATUS Status;
1055
1056 Status = MapDefaultKey (&ParentKey,
1057 hKey);
1058 if (!NT_SUCCESS(Status))
1059 {
1060 return RtlNtStatusToDosError (Status);
1061 }
1062
1063 RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
1064 (LPSTR)lpSubKey);
1065 InitializeObjectAttributes(&ObjectAttributes,
1066 &SubKeyName,
1067 OBJ_CASE_INSENSITIVE,
1068 ParentKey,
1069 NULL);
1070
1071 Status = NtOpenKey (&TargetKey,
1072 DELETE,
1073 &ObjectAttributes);
1074 RtlFreeUnicodeString (&SubKeyName);
1075 if (!NT_SUCCESS(Status))
1076 {
1077 goto Cleanup;
1078 }
1079
1080 Status = NtDeleteKey (TargetKey);
1081 NtClose (TargetKey);
1082
1083 Cleanup:
1084 CloseDefaultKey(ParentKey);
1085
1086 if (!NT_SUCCESS(Status))
1087 {
1088 return RtlNtStatusToDosError(Status);
1089 }
1090
1091 return ERROR_SUCCESS;
1092 }
1093
1094
1095 /************************************************************************
1096 * RegDeleteKeyW
1097 *
1098 * @implemented
1099 */
1100 LONG STDCALL
1101 RegDeleteKeyW (HKEY hKey,
1102 LPCWSTR lpSubKey)
1103 {
1104 OBJECT_ATTRIBUTES ObjectAttributes;
1105 UNICODE_STRING SubKeyName;
1106 HANDLE ParentKey;
1107 HANDLE TargetKey;
1108 NTSTATUS Status;
1109
1110 Status = MapDefaultKey (&ParentKey,
1111 hKey);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 return RtlNtStatusToDosError (Status);
1115 }
1116
1117 RtlInitUnicodeString (&SubKeyName,
1118 (LPWSTR)lpSubKey);
1119 InitializeObjectAttributes (&ObjectAttributes,
1120 &SubKeyName,
1121 OBJ_CASE_INSENSITIVE,
1122 ParentKey,
1123 NULL);
1124 Status = NtOpenKey (&TargetKey,
1125 DELETE,
1126 &ObjectAttributes);
1127 if (!NT_SUCCESS(Status))
1128 {
1129 goto Cleanup;
1130 }
1131
1132 Status = NtDeleteKey (TargetKey);
1133 NtClose (TargetKey);
1134
1135 Cleanup:
1136 CloseDefaultKey(ParentKey);
1137
1138 if (!NT_SUCCESS(Status))
1139 {
1140 return RtlNtStatusToDosError (Status);
1141 }
1142
1143 return ERROR_SUCCESS;
1144 }
1145
1146
1147 /************************************************************************
1148 * RegDeleteKeyValueW
1149 *
1150 * @implemented
1151 */
1152 LONG STDCALL
1153 RegDeleteKeyValueW(IN HKEY hKey,
1154 IN LPCWSTR lpSubKey OPTIONAL,
1155 IN LPCWSTR lpValueName OPTIONAL)
1156 {
1157 UNICODE_STRING ValueName;
1158 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1159 NTSTATUS Status;
1160
1161 Status = MapDefaultKey(&KeyHandle,
1162 hKey);
1163 if (!NT_SUCCESS(Status))
1164 {
1165 return RtlNtStatusToDosError(Status);
1166 }
1167
1168 if (lpSubKey != NULL)
1169 {
1170 OBJECT_ATTRIBUTES ObjectAttributes;
1171 UNICODE_STRING SubKeyName;
1172
1173 RtlInitUnicodeString(&SubKeyName,
1174 (LPWSTR)lpSubKey);
1175
1176 InitializeObjectAttributes(&ObjectAttributes,
1177 &SubKeyName,
1178 OBJ_CASE_INSENSITIVE,
1179 KeyHandle,
1180 NULL);
1181
1182 Status = NtOpenKey(&SubKeyHandle,
1183 KEY_SET_VALUE,
1184 &ObjectAttributes);
1185 if (!NT_SUCCESS(Status))
1186 {
1187 goto Cleanup;
1188 }
1189
1190 CurKey = SubKeyHandle;
1191 }
1192 else
1193 CurKey = KeyHandle;
1194
1195 RtlInitUnicodeString(&ValueName,
1196 (LPWSTR)lpValueName);
1197
1198 Status = NtDeleteValueKey(CurKey,
1199 &ValueName);
1200
1201 if (SubKeyHandle != NULL)
1202 {
1203 NtClose(SubKeyHandle);
1204 }
1205
1206 Cleanup:
1207 CloseDefaultKey(KeyHandle);
1208
1209 if (!NT_SUCCESS(Status))
1210 {
1211 return RtlNtStatusToDosError(Status);
1212 }
1213
1214 return ERROR_SUCCESS;
1215 }
1216
1217
1218 /************************************************************************
1219 * RegDeleteKeyValueA
1220 *
1221 * @implemented
1222 */
1223 LONG STDCALL
1224 RegDeleteKeyValueA(IN HKEY hKey,
1225 IN LPCSTR lpSubKey OPTIONAL,
1226 IN LPCSTR lpValueName OPTIONAL)
1227 {
1228 UNICODE_STRING SubKey = {0}, ValueName = {0};
1229 LONG Ret;
1230
1231 if (lpSubKey != NULL &&
1232 !RtlCreateUnicodeStringFromAsciiz(&SubKey,
1233 (LPSTR)lpSubKey))
1234 {
1235 return ERROR_NOT_ENOUGH_MEMORY;
1236 }
1237
1238 if (lpValueName != NULL &&
1239 !RtlCreateUnicodeStringFromAsciiz(&ValueName,
1240 (LPSTR)lpValueName))
1241 {
1242 RtlFreeUnicodeString(&SubKey);
1243 return ERROR_NOT_ENOUGH_MEMORY;
1244 }
1245
1246 Ret = RegDeleteKeyValueW(hKey,
1247 SubKey.Buffer,
1248 SubKey.Buffer);
1249
1250 RtlFreeUnicodeString(&SubKey);
1251 RtlFreeUnicodeString(&ValueName);
1252
1253 return Ret;
1254 }
1255
1256
1257 static NTSTATUS
1258 RegpDeleteTree(IN HKEY hKey)
1259 {
1260 typedef struct
1261 {
1262 LIST_ENTRY ListEntry;
1263 HANDLE KeyHandle;
1264 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1265
1266 LIST_ENTRY delQueueHead;
1267 PREG_DEL_KEYS delKeys, newDelKeys;
1268 HANDLE ProcessHeap;
1269 ULONG BufferSize;
1270 PKEY_BASIC_INFORMATION BasicInfo;
1271 PREG_DEL_KEYS KeyDelRoot;
1272 NTSTATUS Status = STATUS_SUCCESS;
1273 NTSTATUS Status2 = STATUS_SUCCESS;
1274
1275 InitializeListHead(&delQueueHead);
1276
1277 ProcessHeap = RtlGetProcessHeap();
1278
1279 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1280 structure for the root key, we only do that for subkeys as we need to
1281 allocate REGP_DEL_KEYS structures anyway! */
1282 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1283 0,
1284 sizeof(REGP_DEL_KEYS));
1285 if (KeyDelRoot != NULL)
1286 {
1287 KeyDelRoot->KeyHandle = hKey;
1288 InsertTailList(&delQueueHead,
1289 &KeyDelRoot->ListEntry);
1290
1291 do
1292 {
1293 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1294 REGP_DEL_KEYS,
1295 ListEntry);
1296
1297 BufferSize = 0;
1298 BasicInfo = NULL;
1299 newDelKeys = NULL;
1300
1301 ReadFirstSubKey:
1302 /* check if this key contains subkeys and delete them first by queuing
1303 them at the head of the list */
1304 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1305 0,
1306 KeyBasicInformation,
1307 BasicInfo,
1308 BufferSize,
1309 &BufferSize);
1310
1311 if (NT_SUCCESS(Status2))
1312 {
1313 OBJECT_ATTRIBUTES ObjectAttributes;
1314 UNICODE_STRING SubKeyName;
1315
1316 ASSERT(newDelKeys != NULL);
1317 ASSERT(BasicInfo != NULL);
1318
1319 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1320 SubKeyName.Length = BasicInfo->NameLength;
1321 SubKeyName.MaximumLength = BasicInfo->NameLength;
1322 SubKeyName.Buffer = BasicInfo->Name;
1323
1324 InitializeObjectAttributes(&ObjectAttributes,
1325 &SubKeyName,
1326 OBJ_CASE_INSENSITIVE,
1327 delKeys->KeyHandle,
1328 NULL);
1329
1330 /* open the subkey */
1331 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1332 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1333 &ObjectAttributes);
1334 if (!NT_SUCCESS(Status2))
1335 {
1336 goto SubKeyFailure;
1337 }
1338
1339 /* enqueue this key to the head of the deletion queue */
1340 InsertHeadList(&delQueueHead,
1341 &newDelKeys->ListEntry);
1342
1343 /* try again from the head of the list */
1344 continue;
1345 }
1346 else
1347 {
1348 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1349 {
1350 newDelKeys = RtlAllocateHeap(ProcessHeap,
1351 0,
1352 BufferSize + sizeof(REGP_DEL_KEYS));
1353 if (newDelKeys != NULL)
1354 {
1355 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1356
1357 /* try again */
1358 goto ReadFirstSubKey;
1359 }
1360 else
1361 {
1362 /* don't break, let's try to delete as many keys as possible */
1363 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1364 goto SubKeyFailureNoFree;
1365 }
1366 }
1367 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1368 {
1369 PREG_DEL_KEYS newDelKeys2;
1370
1371 ASSERT(newDelKeys != NULL);
1372
1373 /* we need more memory to query the key name */
1374 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1375 0,
1376 newDelKeys,
1377 BufferSize + sizeof(REGP_DEL_KEYS));
1378 if (newDelKeys2 != NULL)
1379 {
1380 newDelKeys = newDelKeys2;
1381 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1382
1383 /* try again */
1384 goto ReadFirstSubKey;
1385 }
1386 else
1387 {
1388 /* don't break, let's try to delete as many keys as possible */
1389 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1390 }
1391 }
1392
1393 SubKeyFailure:
1394 ASSERT(newDelKeys != NULL);
1395 RtlFreeHeap(ProcessHeap,
1396 0,
1397 newDelKeys);
1398
1399 SubKeyFailureNoFree:
1400 /* don't break, let's try to delete as many keys as possible */
1401 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
1402 {
1403 Status = Status2;
1404 }
1405 }
1406
1407 Status2 = NtDeleteKey(delKeys->KeyHandle);
1408
1409 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1410
1411 if (!NT_SUCCESS(Status2))
1412 {
1413 /* close the key handle so we don't leak handles for keys we were
1414 unable to delete. But only do this for handles not supplied
1415 by the caller! */
1416
1417 if (delKeys->KeyHandle != hKey)
1418 {
1419 NtClose(delKeys->KeyHandle);
1420 }
1421
1422 if (NT_SUCCESS(Status))
1423 {
1424 /* don't break, let's try to delete as many keys as possible */
1425 Status = Status2;
1426 }
1427 }
1428
1429 /* remove the entry from the list */
1430 RemoveEntryList(&delKeys->ListEntry);
1431
1432 RtlFreeHeap(ProcessHeap,
1433 0,
1434 delKeys);
1435 } while (!IsListEmpty(&delQueueHead));
1436 }
1437 else
1438 Status = STATUS_INSUFFICIENT_RESOURCES;
1439
1440 return Status;
1441 }
1442
1443
1444 /************************************************************************
1445 * RegDeleteTreeW
1446 *
1447 * @implemented
1448 */
1449 LONG STDCALL
1450 RegDeleteTreeW(IN HKEY hKey,
1451 IN LPCWSTR lpSubKey OPTIONAL)
1452 {
1453 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1454 NTSTATUS Status;
1455
1456 Status = MapDefaultKey(&KeyHandle,
1457 hKey);
1458 if (!NT_SUCCESS(Status))
1459 {
1460 return RtlNtStatusToDosError(Status);
1461 }
1462
1463 if (lpSubKey != NULL)
1464 {
1465 OBJECT_ATTRIBUTES ObjectAttributes;
1466 UNICODE_STRING SubKeyName;
1467
1468 RtlInitUnicodeString(&SubKeyName,
1469 (LPWSTR)lpSubKey);
1470
1471 InitializeObjectAttributes(&ObjectAttributes,
1472 &SubKeyName,
1473 OBJ_CASE_INSENSITIVE,
1474 KeyHandle,
1475 NULL);
1476
1477 Status = NtOpenKey(&SubKeyHandle,
1478 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1479 &ObjectAttributes);
1480 if (!NT_SUCCESS(Status))
1481 {
1482 goto Cleanup;
1483 }
1484
1485 CurKey = SubKeyHandle;
1486 }
1487 else
1488 CurKey = KeyHandle;
1489
1490 Status = RegpDeleteTree(CurKey);
1491
1492 if (NT_SUCCESS(Status))
1493 {
1494 /* make sure we only close hKey (KeyHandle) when the caller specified a
1495 subkey, because the handle would be invalid already! */
1496 if (CurKey != KeyHandle)
1497 {
1498 CloseDefaultKey(KeyHandle);
1499 }
1500
1501 return ERROR_SUCCESS;
1502 }
1503 else
1504 {
1505 /* make sure we close all handles we created! */
1506 if (SubKeyHandle != NULL)
1507 {
1508 NtClose(SubKeyHandle);
1509 }
1510
1511 Cleanup:
1512 CloseDefaultKey(KeyHandle);
1513
1514 return RtlNtStatusToDosError(Status);
1515 }
1516 }
1517
1518
1519 /************************************************************************
1520 * RegDeleteTreeA
1521 *
1522 * @implemented
1523 */
1524 LONG STDCALL
1525 RegDeleteTreeA(IN HKEY hKey,
1526 IN LPCSTR lpSubKey OPTIONAL)
1527 {
1528 UNICODE_STRING SubKeyName = {0};
1529 LONG Ret;
1530
1531 if (lpSubKey != NULL &&
1532 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1533 (LPSTR)lpSubKey))
1534 {
1535 return ERROR_NOT_ENOUGH_MEMORY;
1536 }
1537
1538 Ret = RegDeleteTreeW(hKey,
1539 SubKeyName.Buffer);
1540
1541 RtlFreeUnicodeString(&SubKeyName);
1542
1543 return Ret;
1544 }
1545
1546
1547 /************************************************************************
1548 * RegSetKeyValueW
1549 *
1550 * @implemented
1551 */
1552 LONG STDCALL
1553 RegSetKeyValueW(IN HKEY hKey,
1554 IN LPCWSTR lpSubKey OPTIONAL,
1555 IN LPCWSTR lpValueName OPTIONAL,
1556 IN DWORD dwType,
1557 IN LPCVOID lpData OPTIONAL,
1558 IN DWORD cbData)
1559 {
1560 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1561 NTSTATUS Status;
1562 LONG Ret;
1563
1564 Status = MapDefaultKey(&KeyHandle,
1565 hKey);
1566 if (!NT_SUCCESS(Status))
1567 {
1568 return RtlNtStatusToDosError(Status);
1569 }
1570
1571 if (lpSubKey != NULL)
1572 {
1573 OBJECT_ATTRIBUTES ObjectAttributes;
1574 UNICODE_STRING SubKeyName;
1575
1576 RtlInitUnicodeString(&SubKeyName,
1577 (LPWSTR)lpSubKey);
1578
1579 InitializeObjectAttributes(&ObjectAttributes,
1580 &SubKeyName,
1581 OBJ_CASE_INSENSITIVE,
1582 KeyHandle,
1583 NULL);
1584
1585 Status = NtOpenKey(&SubKeyHandle,
1586 KEY_SET_VALUE,
1587 &ObjectAttributes);
1588 if (!NT_SUCCESS(Status))
1589 {
1590 Ret = RtlNtStatusToDosError(Status);
1591 goto Cleanup;
1592 }
1593
1594 CurKey = SubKeyHandle;
1595 }
1596 else
1597 CurKey = KeyHandle;
1598
1599 Ret = RegSetValueExW(CurKey,
1600 lpValueName,
1601 0,
1602 dwType,
1603 lpData,
1604 cbData);
1605
1606 if (SubKeyHandle != NULL)
1607 {
1608 NtClose(SubKeyHandle);
1609 }
1610
1611 Cleanup:
1612 CloseDefaultKey(KeyHandle);
1613
1614 return Ret;
1615 }
1616
1617
1618 /************************************************************************
1619 * RegSetKeyValueA
1620 *
1621 * @implemented
1622 */
1623 LONG STDCALL
1624 RegSetKeyValueA(IN HKEY hKey,
1625 IN LPCSTR lpSubKey OPTIONAL,
1626 IN LPCSTR lpValueName OPTIONAL,
1627 IN DWORD dwType,
1628 IN LPCVOID lpData OPTIONAL,
1629 IN DWORD cbData)
1630 {
1631 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1632 NTSTATUS Status;
1633 LONG Ret;
1634
1635 Status = MapDefaultKey(&KeyHandle,
1636 hKey);
1637 if (!NT_SUCCESS(Status))
1638 {
1639 return RtlNtStatusToDosError(Status);
1640 }
1641
1642 if (lpSubKey != NULL)
1643 {
1644 OBJECT_ATTRIBUTES ObjectAttributes;
1645 UNICODE_STRING SubKeyName;
1646
1647 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1648 (LPSTR)lpSubKey))
1649 {
1650 Ret = ERROR_NOT_ENOUGH_MEMORY;
1651 goto Cleanup;
1652 }
1653
1654 InitializeObjectAttributes(&ObjectAttributes,
1655 &SubKeyName,
1656 OBJ_CASE_INSENSITIVE,
1657 KeyHandle,
1658 NULL);
1659
1660 Status = NtOpenKey(&SubKeyHandle,
1661 KEY_SET_VALUE,
1662 &ObjectAttributes);
1663
1664 RtlFreeUnicodeString(&SubKeyName);
1665
1666 if (!NT_SUCCESS(Status))
1667 {
1668 Ret = RtlNtStatusToDosError(Status);
1669 goto Cleanup;
1670 }
1671
1672 CurKey = SubKeyHandle;
1673 }
1674 else
1675 CurKey = KeyHandle;
1676
1677 Ret = RegSetValueExA(CurKey,
1678 lpValueName,
1679 0,
1680 dwType,
1681 lpData,
1682 cbData);
1683
1684 if (SubKeyHandle != NULL)
1685 {
1686 NtClose(SubKeyHandle);
1687 }
1688
1689 Cleanup:
1690 CloseDefaultKey(KeyHandle);
1691
1692 return Ret;
1693 }
1694
1695
1696 /************************************************************************
1697 * RegDeleteValueA
1698 *
1699 * @implemented
1700 */
1701 LONG STDCALL
1702 RegDeleteValueA (HKEY hKey,
1703 LPCSTR lpValueName)
1704 {
1705 UNICODE_STRING ValueName;
1706 HANDLE KeyHandle;
1707 NTSTATUS Status;
1708
1709 Status = MapDefaultKey (&KeyHandle,
1710 hKey);
1711 if (!NT_SUCCESS(Status))
1712 {
1713 return RtlNtStatusToDosError (Status);
1714 }
1715
1716 RtlCreateUnicodeStringFromAsciiz (&ValueName,
1717 (LPSTR)lpValueName);
1718 Status = NtDeleteValueKey (KeyHandle,
1719 &ValueName);
1720 RtlFreeUnicodeString (&ValueName);
1721
1722 CloseDefaultKey(KeyHandle);
1723
1724 if (!NT_SUCCESS(Status))
1725 {
1726 return RtlNtStatusToDosError (Status);
1727 }
1728
1729 return ERROR_SUCCESS;
1730 }
1731
1732
1733 /************************************************************************
1734 * RegDeleteValueW
1735 *
1736 * @implemented
1737 */
1738 LONG STDCALL
1739 RegDeleteValueW (HKEY hKey,
1740 LPCWSTR lpValueName)
1741 {
1742 UNICODE_STRING ValueName;
1743 NTSTATUS Status;
1744 HANDLE KeyHandle;
1745
1746 Status = MapDefaultKey (&KeyHandle,
1747 hKey);
1748 if (!NT_SUCCESS(Status))
1749 {
1750 return RtlNtStatusToDosError (Status);
1751 }
1752
1753 RtlInitUnicodeString (&ValueName,
1754 (LPWSTR)lpValueName);
1755
1756 Status = NtDeleteValueKey (KeyHandle,
1757 &ValueName);
1758
1759 CloseDefaultKey(KeyHandle);
1760
1761 if (!NT_SUCCESS(Status))
1762 {
1763 return RtlNtStatusToDosError (Status);
1764 }
1765
1766 return ERROR_SUCCESS;
1767 }
1768
1769
1770 /************************************************************************
1771 * RegEnumKeyA
1772 *
1773 * @implemented
1774 */
1775 LONG STDCALL
1776 RegEnumKeyA (HKEY hKey,
1777 DWORD dwIndex,
1778 LPSTR lpName,
1779 DWORD cbName)
1780 {
1781 DWORD dwLength;
1782
1783 dwLength = cbName;
1784 return RegEnumKeyExA (hKey,
1785 dwIndex,
1786 lpName,
1787 &dwLength,
1788 NULL,
1789 NULL,
1790 NULL,
1791 NULL);
1792 }
1793
1794
1795 /************************************************************************
1796 * RegEnumKeyW
1797 *
1798 * @implemented
1799 */
1800 LONG STDCALL
1801 RegEnumKeyW (HKEY hKey,
1802 DWORD dwIndex,
1803 LPWSTR lpName,
1804 DWORD cbName)
1805 {
1806 DWORD dwLength;
1807
1808 dwLength = cbName;
1809 return RegEnumKeyExW (hKey,
1810 dwIndex,
1811 lpName,
1812 &dwLength,
1813 NULL,
1814 NULL,
1815 NULL,
1816 NULL);
1817 }
1818
1819
1820 /************************************************************************
1821 * RegEnumKeyExA
1822 *
1823 * @implemented
1824 */
1825 LONG STDCALL
1826 RegEnumKeyExA (HKEY hKey,
1827 DWORD dwIndex,
1828 LPSTR lpName,
1829 LPDWORD lpcbName,
1830 LPDWORD lpReserved,
1831 LPSTR lpClass,
1832 LPDWORD lpcbClass,
1833 PFILETIME lpftLastWriteTime)
1834 {
1835 union
1836 {
1837 KEY_NODE_INFORMATION Node;
1838 KEY_BASIC_INFORMATION Basic;
1839 } *KeyInfo;
1840
1841 UNICODE_STRING StringU;
1842 ANSI_STRING StringA;
1843 LONG ErrorCode = ERROR_SUCCESS;
1844 DWORD NameLength;
1845 DWORD ClassLength = 0;
1846 DWORD BufferSize;
1847 DWORD ResultSize;
1848 HANDLE KeyHandle;
1849 NTSTATUS Status;
1850
1851 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1852 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
1853
1854 if ((lpClass) && (!lpcbClass))
1855 {
1856 return ERROR_INVALID_PARAMETER;
1857 }
1858
1859 Status = MapDefaultKey(&KeyHandle, hKey);
1860 if (!NT_SUCCESS(Status))
1861 {
1862 return RtlNtStatusToDosError (Status);
1863 }
1864
1865 if (*lpcbName > 0)
1866 {
1867 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
1868 }
1869 else
1870 {
1871 NameLength = 0;
1872 }
1873
1874 if (lpClass)
1875 {
1876 if (*lpcbClass > 0)
1877 {
1878 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1879 }
1880 else
1881 {
1882 ClassLength = 0;
1883 }
1884
1885 /* The class name should start at a dword boundary */
1886 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
1887 }
1888 else
1889 {
1890 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
1891 }
1892
1893 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
1894 if (KeyInfo == NULL)
1895 {
1896 ErrorCode = ERROR_OUTOFMEMORY;
1897 goto Cleanup;
1898 }
1899
1900 Status = NtEnumerateKey (KeyHandle,
1901 (ULONG)dwIndex,
1902 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
1903 KeyInfo,
1904 BufferSize,
1905 &ResultSize);
1906 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
1907 if (!NT_SUCCESS(Status))
1908 {
1909 ErrorCode = RtlNtStatusToDosError (Status);
1910 }
1911 else
1912 {
1913 if (lpClass == NULL)
1914 {
1915 if (KeyInfo->Basic.NameLength > NameLength)
1916 {
1917 ErrorCode = ERROR_BUFFER_OVERFLOW;
1918 }
1919 else
1920 {
1921 StringU.Buffer = KeyInfo->Basic.Name;
1922 StringU.Length = KeyInfo->Basic.NameLength;
1923 StringU.MaximumLength = KeyInfo->Basic.NameLength;
1924 }
1925 }
1926 else
1927 {
1928 if (KeyInfo->Node.NameLength > NameLength ||
1929 KeyInfo->Node.ClassLength > ClassLength)
1930 {
1931 ErrorCode = ERROR_BUFFER_OVERFLOW;
1932 }
1933 else
1934 {
1935 StringA.Buffer = lpClass;
1936 StringA.Length = 0;
1937 StringA.MaximumLength = *lpcbClass;
1938 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
1939 StringU.Length = KeyInfo->Node.ClassLength;
1940 StringU.MaximumLength = KeyInfo->Node.ClassLength;
1941 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1942 lpClass[StringA.Length] = 0;
1943 *lpcbClass = StringA.Length;
1944 StringU.Buffer = KeyInfo->Node.Name;
1945 StringU.Length = KeyInfo->Node.NameLength;
1946 StringU.MaximumLength = KeyInfo->Node.NameLength;
1947 }
1948 }
1949
1950 if (ErrorCode == ERROR_SUCCESS)
1951 {
1952 StringA.Buffer = lpName;
1953 StringA.Length = 0;
1954 StringA.MaximumLength = *lpcbName;
1955 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1956 lpName[StringA.Length] = 0;
1957 *lpcbName = StringA.Length;
1958 if (lpftLastWriteTime != NULL)
1959 {
1960 if (lpClass == NULL)
1961 {
1962 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1963 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1964 }
1965 else
1966 {
1967 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1968 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1969 }
1970 }
1971 }
1972 }
1973
1974 TRACE("Key Namea0 Length %d\n", StringU.Length);
1975 TRACE("Key Namea1 Length %d\n", NameLength);
1976 TRACE("Key Namea Length %d\n", *lpcbName);
1977 TRACE("Key Namea %s\n", lpName);
1978
1979 RtlFreeHeap (ProcessHeap,
1980 0,
1981 KeyInfo);
1982
1983 Cleanup:
1984 CloseDefaultKey(KeyHandle);
1985
1986 return ErrorCode;
1987 }
1988
1989
1990 /************************************************************************
1991 * RegEnumKeyExW
1992 *
1993 * @implemented
1994 */
1995 LONG STDCALL
1996 RegEnumKeyExW (HKEY hKey,
1997 DWORD dwIndex,
1998 LPWSTR lpName,
1999 LPDWORD lpcbName,
2000 LPDWORD lpReserved,
2001 LPWSTR lpClass,
2002 LPDWORD lpcbClass,
2003 PFILETIME lpftLastWriteTime)
2004 {
2005 union
2006 {
2007 KEY_NODE_INFORMATION Node;
2008 KEY_BASIC_INFORMATION Basic;
2009 } *KeyInfo;
2010
2011 ULONG BufferSize;
2012 ULONG ResultSize;
2013 ULONG NameLength;
2014 ULONG ClassLength = 0;
2015 HANDLE KeyHandle;
2016 LONG ErrorCode = ERROR_SUCCESS;
2017 NTSTATUS Status;
2018
2019 Status = MapDefaultKey(&KeyHandle,
2020 hKey);
2021 if (!NT_SUCCESS(Status))
2022 {
2023 return RtlNtStatusToDosError (Status);
2024 }
2025
2026 if (*lpcbName > 0)
2027 {
2028 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2029 }
2030 else
2031 {
2032 NameLength = 0;
2033 }
2034
2035 if (lpClass)
2036 {
2037 if (*lpcbClass > 0)
2038 {
2039 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2040 }
2041 else
2042 {
2043 ClassLength = 0;
2044 }
2045
2046 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2047 }
2048 else
2049 {
2050 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2051 }
2052
2053 KeyInfo = RtlAllocateHeap (ProcessHeap,
2054 0,
2055 BufferSize);
2056 if (KeyInfo == NULL)
2057 {
2058 ErrorCode = ERROR_OUTOFMEMORY;
2059 goto Cleanup;
2060 }
2061
2062 Status = NtEnumerateKey (KeyHandle,
2063 (ULONG)dwIndex,
2064 lpClass ? KeyNodeInformation : KeyBasicInformation,
2065 KeyInfo,
2066 BufferSize,
2067 &ResultSize);
2068 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2069 if (!NT_SUCCESS(Status))
2070 {
2071 ErrorCode = RtlNtStatusToDosError (Status);
2072 }
2073 else
2074 {
2075 if (lpClass == NULL)
2076 {
2077 if (KeyInfo->Basic.NameLength > NameLength)
2078 {
2079 ErrorCode = ERROR_BUFFER_OVERFLOW;
2080 }
2081 else
2082 {
2083 RtlCopyMemory (lpName,
2084 KeyInfo->Basic.Name,
2085 KeyInfo->Basic.NameLength);
2086 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2087 lpName[*lpcbName] = 0;
2088 }
2089 }
2090 else
2091 {
2092 if (KeyInfo->Node.NameLength > NameLength ||
2093 KeyInfo->Node.ClassLength > ClassLength)
2094 {
2095 ErrorCode = ERROR_BUFFER_OVERFLOW;
2096 }
2097 else
2098 {
2099 RtlCopyMemory (lpName,
2100 KeyInfo->Node.Name,
2101 KeyInfo->Node.NameLength);
2102 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2103 lpName[*lpcbName] = 0;
2104 RtlCopyMemory (lpClass,
2105 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2106 KeyInfo->Node.ClassLength);
2107 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2108 lpClass[*lpcbClass] = 0;
2109 }
2110 }
2111
2112 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2113 {
2114 if (lpClass == NULL)
2115 {
2116 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2117 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2118 }
2119 else
2120 {
2121 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2122 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2123 }
2124 }
2125 }
2126
2127 RtlFreeHeap (ProcessHeap,
2128 0,
2129 KeyInfo);
2130
2131 Cleanup:
2132 CloseDefaultKey(KeyHandle);
2133
2134 return ErrorCode;
2135 }
2136
2137 /************************************************************************
2138 * RegEnumValueA
2139 *
2140 * @implemented
2141 */
2142 LONG STDCALL
2143 RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
2144 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2145 {
2146 HANDLE KeyHandle;
2147 NTSTATUS status;
2148 DWORD total_size;
2149 char buffer[256], *buf_ptr = buffer;
2150 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2151 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2152
2153 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2154 // hkey, index, value, val_count, reserved, type, data, count );
2155
2156 /* NT only checks count, not val_count */
2157 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2158 status = MapDefaultKey (&KeyHandle, hKey);
2159 if (!NT_SUCCESS(status))
2160 {
2161 return RtlNtStatusToDosError (status);
2162 }
2163
2164 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2165 if (data) total_size += *count;
2166 total_size = min( sizeof(buffer), total_size );
2167
2168 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2169 buffer, total_size, &total_size );
2170 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2171
2172 /* we need to fetch the contents for a string type even if not requested,
2173 * because we need to compute the length of the ASCII string. */
2174 if (value || data || is_string(info->Type))
2175 {
2176 /* retry with a dynamically allocated buffer */
2177 while (status == STATUS_BUFFER_OVERFLOW)
2178 {
2179 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2180 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2181 {
2182 status = STATUS_INSUFFICIENT_RESOURCES;
2183 goto done;
2184 }
2185 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2186 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2187 buf_ptr, total_size, &total_size );
2188 }
2189
2190 if (status) goto done;
2191
2192 if (is_string(info->Type))
2193 {
2194 DWORD len;
2195 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2196 total_size - info->DataOffset );
2197 if (data && len)
2198 {
2199 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2200 else
2201 {
2202 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2203 total_size - info->DataOffset );
2204 /* if the type is REG_SZ and data is not 0-terminated
2205 * and there is enough space in the buffer NT appends a \0 */
2206 if (len < *count && data[len-1]) data[len] = 0;
2207 }
2208 }
2209 info->DataLength = len;
2210 }
2211 else if (data)
2212 {
2213 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2214 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2215 }
2216
2217 if (value && !status)
2218 {
2219 DWORD len;
2220
2221 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2222 if (len >= *val_count)
2223 {
2224 status = STATUS_BUFFER_OVERFLOW;
2225 if (*val_count)
2226 {
2227 len = *val_count - 1;
2228 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2229 value[len] = 0;
2230 }
2231 }
2232 else
2233 {
2234 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2235 value[len] = 0;
2236 *val_count = len;
2237 }
2238 }
2239 }
2240 else status = STATUS_SUCCESS;
2241
2242 if (type) *type = info->Type;
2243 if (count) *count = info->DataLength;
2244
2245 done:
2246 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2247 CloseDefaultKey(KeyHandle);
2248 return RtlNtStatusToDosError(status);
2249 }
2250
2251 /******************************************************************************
2252 * RegEnumValueW [ADVAPI32.@]
2253 * @implemented
2254 *
2255 * PARAMS
2256 * hkey [I] Handle to key to query
2257 * index [I] Index of value to query
2258 * value [O] Value string
2259 * val_count [I/O] Size of value buffer (in wchars)
2260 * reserved [I] Reserved
2261 * type [O] Type code
2262 * data [O] Value data
2263 * count [I/O] Size of data buffer (in bytes)
2264 *
2265 * RETURNS
2266 * Success: ERROR_SUCCESS
2267 * Failure: nonzero error code from Winerror.h
2268 */
2269 LONG STDCALL
2270 RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
2271 PDWORD reserved, PDWORD type, LPBYTE data, PDWORD count )
2272 {
2273 HANDLE KeyHandle;
2274 NTSTATUS status;
2275 DWORD total_size;
2276 char buffer[256], *buf_ptr = buffer;
2277 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2278 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2279
2280 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2281 // hkey, index, value, val_count, reserved, type, data, count );
2282
2283 /* NT only checks count, not val_count */
2284 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2285
2286 status = MapDefaultKey (&KeyHandle, hKey);
2287 if (!NT_SUCCESS(status))
2288 {
2289 return RtlNtStatusToDosError (status);
2290 }
2291
2292 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2293 if (data) total_size += *count;
2294 total_size = min( sizeof(buffer), total_size );
2295
2296 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2297 buffer, total_size, &total_size );
2298 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2299
2300 if (value || data)
2301 {
2302 /* retry with a dynamically allocated buffer */
2303 while (status == STATUS_BUFFER_OVERFLOW)
2304 {
2305 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2306 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2307 {
2308 status = ERROR_NOT_ENOUGH_MEMORY;
2309 goto done;
2310 }
2311 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2312 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2313 buf_ptr, total_size, &total_size );
2314 }
2315
2316 if (status) goto done;
2317
2318 if (value)
2319 {
2320 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2321 {
2322 status = STATUS_BUFFER_OVERFLOW;
2323 goto overflow;
2324 }
2325 memcpy( value, info->Name, info->NameLength );
2326 *val_count = info->NameLength / sizeof(WCHAR);
2327 value[*val_count] = 0;
2328 }
2329
2330 if (data)
2331 {
2332 if (total_size - info->DataOffset > *count)
2333 {
2334 status = STATUS_BUFFER_OVERFLOW;
2335 goto overflow;
2336 }
2337 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2338 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
2339 {
2340 /* if the type is REG_SZ and data is not 0-terminated
2341 * and there is enough space in the buffer NT appends a \0 */
2342 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
2343 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2344 }
2345 }
2346 }
2347 else status = STATUS_SUCCESS;
2348
2349 overflow:
2350 if (type) *type = info->Type;
2351 if (count) *count = info->DataLength;
2352
2353 done:
2354 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2355 CloseDefaultKey(KeyHandle);
2356 return RtlNtStatusToDosError(status);
2357 }
2358
2359 /************************************************************************
2360 * RegFlushKey
2361 *
2362 * @implemented
2363 */
2364 LONG STDCALL
2365 RegFlushKey(HKEY hKey)
2366 {
2367 HANDLE KeyHandle;
2368 NTSTATUS Status;
2369
2370 if (hKey == HKEY_PERFORMANCE_DATA)
2371 {
2372 return ERROR_SUCCESS;
2373 }
2374
2375 Status = MapDefaultKey (&KeyHandle,
2376 hKey);
2377 if (!NT_SUCCESS(Status))
2378 {
2379 return RtlNtStatusToDosError (Status);
2380 }
2381
2382 Status = NtFlushKey (KeyHandle);
2383
2384 CloseDefaultKey(KeyHandle);
2385
2386 if (!NT_SUCCESS(Status))
2387 {
2388 return RtlNtStatusToDosError (Status);
2389 }
2390
2391 return ERROR_SUCCESS;
2392 }
2393
2394
2395 /************************************************************************
2396 * RegGetKeySecurity
2397 *
2398 * @implemented
2399 */
2400 LONG STDCALL
2401 RegGetKeySecurity(HKEY hKey,
2402 SECURITY_INFORMATION SecurityInformation,
2403 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2404 LPDWORD lpcbSecurityDescriptor)
2405 {
2406 HANDLE KeyHandle;
2407 NTSTATUS Status;
2408
2409 if (hKey == HKEY_PERFORMANCE_DATA)
2410 {
2411 return ERROR_INVALID_HANDLE;
2412 }
2413
2414 Status = MapDefaultKey(&KeyHandle,
2415 hKey);
2416 if (!NT_SUCCESS(Status))
2417 {
2418 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
2419 return RtlNtStatusToDosError (Status);
2420 }
2421
2422 Status = NtQuerySecurityObject(KeyHandle,
2423 SecurityInformation,
2424 pSecurityDescriptor,
2425 *lpcbSecurityDescriptor,
2426 lpcbSecurityDescriptor);
2427
2428 CloseDefaultKey(KeyHandle);
2429
2430 if (!NT_SUCCESS(Status))
2431 {
2432 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
2433 return RtlNtStatusToDosError (Status);
2434 }
2435
2436 return ERROR_SUCCESS;
2437 }
2438
2439
2440 /************************************************************************
2441 * RegLoadKeyA
2442 *
2443 * @implemented
2444 */
2445 LONG STDCALL
2446 RegLoadKeyA (HKEY hKey,
2447 LPCSTR lpSubKey,
2448 LPCSTR lpFile)
2449 {
2450 UNICODE_STRING FileName;
2451 UNICODE_STRING KeyName;
2452 LONG ErrorCode;
2453
2454 RtlCreateUnicodeStringFromAsciiz (&KeyName,
2455 (LPSTR)lpSubKey);
2456 RtlCreateUnicodeStringFromAsciiz (&FileName,
2457 (LPSTR)lpFile);
2458
2459 ErrorCode = RegLoadKeyW (hKey,
2460 KeyName.Buffer,
2461 FileName.Buffer);
2462
2463 RtlFreeUnicodeString (&FileName);
2464 RtlFreeUnicodeString (&KeyName);
2465
2466 return ErrorCode;
2467 }
2468
2469
2470 /************************************************************************
2471 * RegLoadKeyW
2472 *
2473 * @implemented
2474 */
2475 LONG STDCALL
2476 RegLoadKeyW (HKEY hKey,
2477 LPCWSTR lpSubKey,
2478 LPCWSTR lpFile)
2479 {
2480 OBJECT_ATTRIBUTES FileObjectAttributes;
2481 OBJECT_ATTRIBUTES KeyObjectAttributes;
2482 UNICODE_STRING FileName;
2483 UNICODE_STRING KeyName;
2484 HANDLE KeyHandle;
2485 NTSTATUS Status;
2486 LONG ErrorCode = ERROR_SUCCESS;
2487
2488 if (hKey == HKEY_PERFORMANCE_DATA)
2489 {
2490 return ERROR_INVALID_HANDLE;
2491 }
2492
2493 Status = MapDefaultKey (&KeyHandle,
2494 hKey);
2495 if (!NT_SUCCESS(Status))
2496 {
2497 return RtlNtStatusToDosError (Status);
2498 }
2499
2500 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
2501 &FileName,
2502 NULL,
2503 NULL))
2504 {
2505 ErrorCode = ERROR_BAD_PATHNAME;
2506 goto Cleanup;
2507 }
2508
2509 InitializeObjectAttributes (&FileObjectAttributes,
2510 &FileName,
2511 OBJ_CASE_INSENSITIVE,
2512 NULL,
2513 NULL);
2514
2515 RtlInitUnicodeString (&KeyName,
2516 (LPWSTR)lpSubKey);
2517
2518 InitializeObjectAttributes (&KeyObjectAttributes,
2519 &KeyName,
2520 OBJ_CASE_INSENSITIVE,
2521 KeyHandle,
2522 NULL);
2523
2524 Status = NtLoadKey (&KeyObjectAttributes,
2525 &FileObjectAttributes);
2526
2527 RtlFreeUnicodeString (&FileName);
2528
2529 if (!NT_SUCCESS(Status))
2530 {
2531 ErrorCode = RtlNtStatusToDosError (Status);
2532 goto Cleanup;
2533 }
2534
2535 Cleanup:
2536 CloseDefaultKey(KeyHandle);
2537
2538 return ErrorCode;
2539 }
2540
2541
2542 /************************************************************************
2543 * RegNotifyChangeKeyValue
2544 *
2545 * @unimplemented
2546 */
2547 LONG STDCALL
2548 RegNotifyChangeKeyValue (HKEY hKey,
2549 BOOL bWatchSubtree,
2550 DWORD dwNotifyFilter,
2551 HANDLE hEvent,
2552 BOOL fAsynchronous)
2553 {
2554 IO_STATUS_BLOCK IoStatusBlock;
2555 HANDLE KeyHandle;
2556 NTSTATUS Status;
2557 LONG ErrorCode = ERROR_SUCCESS;
2558
2559 if (hKey == HKEY_PERFORMANCE_DATA)
2560 {
2561 return ERROR_INVALID_HANDLE;
2562 }
2563
2564 if (fAsynchronous == TRUE && hEvent == NULL)
2565 {
2566 return ERROR_INVALID_PARAMETER;
2567 }
2568
2569 Status = MapDefaultKey (&KeyHandle,
2570 hKey);
2571 if (!NT_SUCCESS(Status))
2572 {
2573 return RtlNtStatusToDosError (Status);
2574 }
2575
2576 /* FIXME: Remote key handles must fail */
2577
2578 Status = NtNotifyChangeKey (KeyHandle,
2579 hEvent,
2580 0,
2581 0,
2582 &IoStatusBlock,
2583 dwNotifyFilter,
2584 bWatchSubtree,
2585 0,
2586 0,
2587 fAsynchronous);
2588 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
2589 {
2590 ErrorCode = RtlNtStatusToDosError (Status);
2591 }
2592
2593 CloseDefaultKey(KeyHandle);
2594
2595 return ErrorCode;
2596 }
2597
2598
2599 /************************************************************************
2600 * RegOpenCurrentUser
2601 *
2602 * @implemented
2603 */
2604 LONG STDCALL
2605 RegOpenCurrentUser (IN REGSAM samDesired,
2606 OUT PHKEY phkResult)
2607 {
2608 NTSTATUS Status;
2609
2610 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
2611 (PHANDLE)phkResult);
2612 if (!NT_SUCCESS(Status))
2613 {
2614 /* NOTE - don't set the last error code! just return the error! */
2615 return RtlNtStatusToDosError(Status);
2616 }
2617
2618 return ERROR_SUCCESS;
2619 }
2620
2621
2622 /************************************************************************
2623 * RegOpenKeyA
2624 *
2625 * 20050503 Fireball - imported from WINE
2626 *
2627 * @implemented
2628 */
2629 LONG STDCALL
2630 RegOpenKeyA (HKEY hKey,
2631 LPCSTR lpSubKey,
2632 PHKEY phkResult)
2633 {
2634 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey, lpSubKey, phkResult);
2635
2636 if (!lpSubKey || !*lpSubKey)
2637 {
2638 *phkResult = hKey;
2639 return ERROR_SUCCESS;
2640 }
2641
2642 return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2643 }
2644
2645
2646 /************************************************************************
2647 * RegOpenKeyW
2648 *
2649 * 19981101 Ariadne
2650 * 19990525 EA
2651 * 20050503 Fireball - imported from WINE
2652 *
2653 * @implemented
2654 */
2655 LONG STDCALL
2656 RegOpenKeyW (HKEY hKey,
2657 LPCWSTR lpSubKey,
2658 PHKEY phkResult)
2659 {
2660 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
2661
2662 if (!lpSubKey || !*lpSubKey)
2663 {
2664 *phkResult = hKey;
2665 return ERROR_SUCCESS;
2666 }
2667 return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2668 }
2669
2670
2671 /************************************************************************
2672 * RegOpenKeyExA
2673 *
2674 * @implemented
2675 */
2676 LONG STDCALL
2677 RegOpenKeyExA (HKEY hKey,
2678 LPCSTR lpSubKey,
2679 DWORD ulOptions,
2680 REGSAM samDesired,
2681 PHKEY phkResult)
2682 {
2683 OBJECT_ATTRIBUTES ObjectAttributes;
2684 UNICODE_STRING SubKeyString;
2685 HANDLE KeyHandle;
2686 NTSTATUS Status;
2687 LONG ErrorCode = ERROR_SUCCESS;
2688
2689 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2690 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2691
2692 Status = MapDefaultKey (&KeyHandle, hKey);
2693 if (!NT_SUCCESS(Status))
2694 {
2695 return RtlNtStatusToDosError (Status);
2696 }
2697
2698 RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
2699 InitializeObjectAttributes (&ObjectAttributes,
2700 &SubKeyString,
2701 OBJ_CASE_INSENSITIVE,
2702 KeyHandle,
2703 NULL);
2704
2705 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2706 RtlFreeUnicodeString (&SubKeyString);
2707 if (!NT_SUCCESS(Status))
2708 {
2709 ErrorCode = RtlNtStatusToDosError (Status);
2710 }
2711
2712 CloseDefaultKey(KeyHandle);
2713
2714 return ErrorCode;
2715 }
2716
2717
2718 /************************************************************************
2719 * RegOpenKeyExW
2720 *
2721 * @implemented
2722 */
2723 LONG STDCALL
2724 RegOpenKeyExW (HKEY hKey,
2725 LPCWSTR lpSubKey,
2726 DWORD ulOptions,
2727 REGSAM samDesired,
2728 PHKEY phkResult)
2729 {
2730 OBJECT_ATTRIBUTES ObjectAttributes;
2731 UNICODE_STRING SubKeyString;
2732 HANDLE KeyHandle;
2733 NTSTATUS Status;
2734 LONG ErrorCode = ERROR_SUCCESS;
2735
2736 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2737 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2738
2739 Status = MapDefaultKey (&KeyHandle, hKey);
2740 if (!NT_SUCCESS(Status))
2741 {
2742 return RtlNtStatusToDosError (Status);
2743 }
2744
2745 if (lpSubKey != NULL)
2746 RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
2747 else
2748 RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
2749
2750 InitializeObjectAttributes (&ObjectAttributes,
2751 &SubKeyString,
2752 OBJ_CASE_INSENSITIVE,
2753 KeyHandle,
2754 NULL);
2755
2756 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2757
2758 if (!NT_SUCCESS(Status))
2759 {
2760 ErrorCode = RtlNtStatusToDosError (Status);
2761 }
2762
2763 CloseDefaultKey(KeyHandle);
2764
2765 return ErrorCode;
2766 }
2767
2768
2769 /************************************************************************
2770 * RegOpenUserClassesRoot
2771 *
2772 * @implemented
2773 */
2774 LONG STDCALL
2775 RegOpenUserClassesRoot (IN HANDLE hToken,
2776 IN DWORD dwOptions,
2777 IN REGSAM samDesired,
2778 OUT PHKEY phkResult)
2779 {
2780 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
2781 const WCHAR UserClassesKeySuffix[] = L"_Classes";
2782 PTOKEN_USER TokenUserData;
2783 ULONG RequiredLength;
2784 UNICODE_STRING UserSidString, UserClassesKeyRoot;
2785 OBJECT_ATTRIBUTES ObjectAttributes;
2786 NTSTATUS Status;
2787
2788 /* check parameters */
2789 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
2790 {
2791 return ERROR_INVALID_PARAMETER;
2792 }
2793
2794 /*
2795 * Get the user sid from the token
2796 */
2797
2798 ReadTokenSid:
2799 /* determine how much memory we need */
2800 Status = NtQueryInformationToken(hToken,
2801 TokenUser,
2802 NULL,
2803 0,
2804 &RequiredLength);
2805 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
2806 {
2807 /* NOTE - as opposed to all other registry functions windows does indeed
2808 change the last error code in case the caller supplied a invalid
2809 handle for example! */
2810 return RtlNtStatusToDosError (Status);
2811 }
2812
2813 TokenUserData = RtlAllocateHeap(ProcessHeap,
2814 0,
2815 RequiredLength);
2816 if (TokenUserData == NULL)
2817 {
2818 return ERROR_NOT_ENOUGH_MEMORY;
2819 }
2820
2821 /* attempt to read the information */
2822 Status = NtQueryInformationToken(hToken,
2823 TokenUser,
2824 TokenUserData,
2825 RequiredLength,
2826 &RequiredLength);
2827 if (!NT_SUCCESS(Status))
2828 {
2829 RtlFreeHeap(ProcessHeap,
2830 0,
2831 TokenUserData);
2832 if (Status == STATUS_BUFFER_TOO_SMALL)
2833 {
2834 /* the information appears to have changed?! try again */
2835 goto ReadTokenSid;
2836 }
2837
2838 /* NOTE - as opposed to all other registry functions windows does indeed
2839 change the last error code in case the caller supplied a invalid
2840 handle for example! */
2841 return RtlNtStatusToDosError (Status);
2842 }
2843
2844 /*
2845 * Build the absolute path for the user's registry in the form
2846 * "\Registry\User\<SID>_Classes"
2847 */
2848 Status = RtlConvertSidToUnicodeString(&UserSidString,
2849 TokenUserData->User.Sid,
2850 TRUE);
2851
2852 /* we don't need the user data anymore, free it */
2853 RtlFreeHeap(ProcessHeap,
2854 0,
2855 TokenUserData);
2856
2857 if (!NT_SUCCESS(Status))
2858 {
2859 return RtlNtStatusToDosError (Status);
2860 }
2861
2862 /* allocate enough memory for the entire key string */
2863 UserClassesKeyRoot.Length = 0;
2864 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
2865 sizeof(UserClassesKeyPrefix) +
2866 sizeof(UserClassesKeySuffix);
2867 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
2868 0,
2869 UserClassesKeyRoot.MaximumLength);
2870 if (UserClassesKeyRoot.Buffer == NULL)
2871 {
2872 RtlFreeUnicodeString(&UserSidString);
2873 return RtlNtStatusToDosError (Status);
2874 }
2875
2876 /* build the string */
2877 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2878 UserClassesKeyPrefix);
2879 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
2880 &UserSidString);
2881 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2882 UserClassesKeySuffix);
2883
2884 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
2885
2886 /*
2887 * Open the key
2888 */
2889
2890 InitializeObjectAttributes (&ObjectAttributes,
2891 &UserClassesKeyRoot,
2892 OBJ_CASE_INSENSITIVE,
2893 NULL,
2894 NULL);
2895
2896 Status = NtOpenKey((PHANDLE)phkResult,
2897 samDesired,
2898 &ObjectAttributes);
2899
2900 RtlFreeUnicodeString(&UserSidString);
2901 RtlFreeUnicodeString(&UserClassesKeyRoot);
2902
2903 if (!NT_SUCCESS(Status))
2904 {
2905 return RtlNtStatusToDosError (Status);
2906 }
2907
2908 return ERROR_SUCCESS;
2909 }
2910
2911
2912 /************************************************************************
2913 * RegQueryInfoKeyA
2914 *
2915 * @implemented
2916 */
2917 LONG STDCALL
2918 RegQueryInfoKeyA (HKEY hKey,
2919 LPSTR lpClass,
2920 LPDWORD lpcbClass,
2921 LPDWORD lpReserved,
2922 LPDWORD lpcSubKeys,
2923 LPDWORD lpcbMaxSubKeyLen,
2924 LPDWORD lpcbMaxClassLen,
2925 LPDWORD lpcValues,
2926 LPDWORD lpcbMaxValueNameLen,
2927 LPDWORD lpcbMaxValueLen,
2928 LPDWORD lpcbSecurityDescriptor,
2929 PFILETIME lpftLastWriteTime)
2930 {
2931 WCHAR ClassName[MAX_PATH];
2932 UNICODE_STRING UnicodeString;
2933 ANSI_STRING AnsiString;
2934 LONG ErrorCode;
2935
2936 RtlInitUnicodeString (&UnicodeString,
2937 NULL);
2938 if (lpClass != NULL)
2939 {
2940 UnicodeString.Buffer = &ClassName[0];
2941 UnicodeString.MaximumLength = sizeof(ClassName);
2942 AnsiString.MaximumLength = *lpcbClass;
2943 }
2944
2945 ErrorCode = RegQueryInfoKeyW (hKey,
2946 UnicodeString.Buffer,
2947 lpcbClass,
2948 lpReserved,
2949 lpcSubKeys,
2950 lpcbMaxSubKeyLen,
2951 lpcbMaxClassLen,
2952 lpcValues,
2953 lpcbMaxValueNameLen,
2954 lpcbMaxValueLen,
2955 lpcbSecurityDescriptor,
2956 lpftLastWriteTime);
2957 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
2958 {
2959 AnsiString.Buffer = lpClass;
2960 AnsiString.Length = 0;
2961 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
2962 RtlUnicodeStringToAnsiString (&AnsiString,
2963 &UnicodeString,
2964 FALSE);
2965 *lpcbClass = AnsiString.Length;
2966 lpClass[AnsiString.Length] = 0;
2967 }
2968
2969 return ErrorCode;
2970 }
2971
2972
2973 /************************************************************************
2974 * RegQueryInfoKeyW
2975 *
2976 * @implemented
2977 */
2978 LONG STDCALL
2979 RegQueryInfoKeyW (HKEY hKey,
2980 LPWSTR lpClass,
2981 LPDWORD lpcbClass,
2982 LPDWORD lpReserved,
2983 LPDWORD lpcSubKeys,
2984 LPDWORD lpcbMaxSubKeyLen,
2985 LPDWORD lpcbMaxClassLen,
2986 LPDWORD lpcValues,
2987 LPDWORD lpcbMaxValueNameLen,
2988 LPDWORD lpcbMaxValueLen,
2989 LPDWORD lpcbSecurityDescriptor,
2990 PFILETIME lpftLastWriteTime)
2991 {
2992 KEY_FULL_INFORMATION FullInfoBuffer;
2993 PKEY_FULL_INFORMATION FullInfo;
2994 ULONG FullInfoSize;
2995 ULONG ClassLength = 0;
2996 HANDLE KeyHandle;
2997 NTSTATUS Status;
2998 ULONG Length;
2999 LONG ErrorCode = ERROR_SUCCESS;
3000
3001 if ((lpClass) && (!lpcbClass))
3002 {
3003 return ERROR_INVALID_PARAMETER;
3004 }
3005
3006 Status = MapDefaultKey (&KeyHandle,
3007 hKey);
3008 if (!NT_SUCCESS(Status))
3009 {
3010 return RtlNtStatusToDosError (Status);
3011 }
3012
3013 if (lpClass != NULL)
3014 {
3015 if (*lpcbClass > 0)
3016 {
3017 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3018 }
3019 else
3020 {
3021 ClassLength = 0;
3022 }
3023
3024 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3025 FullInfo = RtlAllocateHeap (ProcessHeap,
3026 0,
3027 FullInfoSize);
3028 if (FullInfo == NULL)
3029 {
3030 ErrorCode = ERROR_OUTOFMEMORY;
3031 goto Cleanup;
3032 }
3033
3034 FullInfo->ClassLength = ClassLength;
3035 }
3036 else
3037 {
3038 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3039 FullInfo = &FullInfoBuffer;
3040 FullInfo->ClassLength = 0;
3041 }
3042 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
3043
3044 Status = NtQueryKey (KeyHandle,
3045 KeyFullInformation,
3046 FullInfo,
3047 FullInfoSize,
3048 &Length);
3049 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3050 if (!NT_SUCCESS(Status))
3051 {
3052 if (lpClass != NULL)
3053 {
3054 RtlFreeHeap (ProcessHeap,
3055 0,
3056 FullInfo);
3057 }
3058
3059 ErrorCode = RtlNtStatusToDosError (Status);
3060 goto Cleanup;
3061 }
3062
3063 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3064 if (lpcSubKeys != NULL)
3065 {
3066 *lpcSubKeys = FullInfo->SubKeys;
3067 }
3068
3069 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3070 if (lpcbMaxSubKeyLen != NULL)
3071 {
3072 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
3073 }
3074
3075 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3076 if (lpcbMaxClassLen != NULL)
3077 {
3078 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
3079 }
3080
3081 TRACE("Values %lu\n", FullInfo->Values);
3082 if (lpcValues != NULL)
3083 {
3084 *lpcValues = FullInfo->Values;
3085 }
3086
3087 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3088 if (lpcbMaxValueNameLen != NULL)
3089 {
3090 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
3091 }
3092
3093 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3094 if (lpcbMaxValueLen != NULL)
3095 {
3096 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
3097 }
3098
3099 if (lpcbSecurityDescriptor != NULL)
3100 {
3101 Status = NtQuerySecurityObject(KeyHandle,
3102 OWNER_SECURITY_INFORMATION |
3103 GROUP_SECURITY_INFORMATION |
3104 DACL_SECURITY_INFORMATION,
3105 NULL,
3106 0,
3107 lpcbSecurityDescriptor);
3108 if (!NT_SUCCESS(Status))
3109 {
3110 if (lpClass != NULL)
3111 {
3112 RtlFreeHeap(ProcessHeap,
3113 0,
3114 FullInfo);
3115 }
3116
3117 ErrorCode = RtlNtStatusToDosError (Status);
3118 goto Cleanup;
3119 }
3120 }
3121
3122 if (lpftLastWriteTime != NULL)
3123 {
3124 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3125 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3126 }
3127
3128 if (lpClass != NULL)
3129 {
3130 if (FullInfo->ClassLength > ClassLength)
3131 {
3132 ErrorCode = ERROR_BUFFER_OVERFLOW;
3133 }
3134 else
3135 {
3136 RtlCopyMemory (lpClass,
3137 FullInfo->Class,
3138 FullInfo->ClassLength);
3139 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
3140 lpClass[*lpcbClass] = 0;
3141 }
3142
3143 RtlFreeHeap (ProcessHeap,
3144 0,
3145 FullInfo);
3146 }
3147
3148 Cleanup:
3149 CloseDefaultKey(KeyHandle);
3150
3151 return ErrorCode;
3152 }
3153
3154
3155 /************************************************************************
3156 * RegQueryMultipleValuesA
3157 *
3158 * @implemented
3159 */
3160 LONG STDCALL
3161 RegQueryMultipleValuesA (HKEY hKey,
3162 PVALENTA val_list,
3163 DWORD num_vals,
3164 LPSTR lpValueBuf,
3165 LPDWORD ldwTotsize)
3166 {
3167 ULONG i;
3168 DWORD maxBytes = *ldwTotsize;
3169 LPSTR bufptr = (LPSTR)lpValueBuf;
3170 LONG ErrorCode;
3171
3172 if (maxBytes >= (1024*1024))
3173 return ERROR_TRANSFER_TOO_LONG;
3174
3175 *ldwTotsize = 0;
3176
3177 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3178 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3179
3180 for (i = 0; i < num_vals; i++)
3181 {
3182 val_list[i].ve_valuelen = 0;
3183 ErrorCode = RegQueryValueExA (hKey,
3184 val_list[i].ve_valuename,
3185 NULL,
3186 NULL,
3187 NULL,
3188 &val_list[i].ve_valuelen);
3189 if (ErrorCode != ERROR_SUCCESS)
3190 {
3191 return ErrorCode;
3192 }
3193
3194 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3195 {
3196 ErrorCode = RegQueryValueExA (hKey,
3197 val_list[i].ve_valuename,
3198 NULL,
3199 &val_list[i].ve_type,
3200 (LPBYTE)bufptr,
3201 &val_list[i].ve_valuelen);
3202 if (ErrorCode != ERROR_SUCCESS)
3203 {
3204 return ErrorCode;
3205 }
3206
3207 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3208
3209 bufptr += val_list[i].ve_valuelen;
3210 }
3211
3212 *ldwTotsize += val_list[i].ve_valuelen;
3213 }
3214
3215 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3216 }
3217
3218
3219 /************************************************************************
3220 * RegQueryMultipleValuesW
3221 *
3222 * @implemented
3223 */
3224 LONG STDCALL
3225 RegQueryMultipleValuesW (HKEY hKey,
3226 PVALENTW val_list,
3227 DWORD num_vals,
3228 LPWSTR lpValueBuf,
3229 LPDWORD ldwTotsize)
3230 {
3231 ULONG i;
3232 DWORD maxBytes = *ldwTotsize;
3233 LPSTR bufptr = (LPSTR)lpValueBuf;
3234 LONG ErrorCode;
3235
3236 if (maxBytes >= (1024*1024))
3237 return ERROR_TRANSFER_TOO_LONG;
3238
3239 *ldwTotsize = 0;
3240
3241 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3242 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3243
3244 for (i = 0; i < num_vals; i++)
3245 {
3246 val_list[i].ve_valuelen = 0;
3247 ErrorCode = RegQueryValueExW (hKey,
3248 val_list[i].ve_valuename,
3249 NULL,
3250 NULL,
3251 NULL,
3252 &val_list[i].ve_valuelen);
3253 if (ErrorCode != ERROR_SUCCESS)
3254 {
3255 return ErrorCode;
3256 }
3257
3258 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3259 {
3260 ErrorCode = RegQueryValueExW (hKey,
3261 val_list[i].ve_valuename,
3262 NULL,
3263 &val_list[i].ve_type,
3264 (LPBYTE)bufptr,
3265 &val_list[i].ve_valuelen);
3266 if (ErrorCode != ERROR_SUCCESS)
3267 {
3268 return ErrorCode;
3269 }
3270
3271 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3272
3273 bufptr += val_list[i].ve_valuelen;
3274 }
3275
3276 *ldwTotsize += val_list[i].ve_valuelen;
3277 }
3278
3279 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3280 }
3281
3282
3283 /************************************************************************
3284 * RegQueryValueExW
3285 *
3286 * @implemented
3287 */
3288 LONG STDCALL
3289 RegQueryValueExW (HKEY hKey,
3290 LPCWSTR lpValueName,
3291 LPDWORD lpReserved,
3292 LPDWORD lpType,
3293 LPBYTE lpData,
3294 LPDWORD lpcbData)
3295 {
3296 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
3297 UNICODE_STRING ValueName;
3298 NTSTATUS Status;
3299 ULONG BufferSize;
3300 ULONG ResultSize;
3301 HANDLE KeyHandle;
3302 LONG ErrorCode = ERROR_SUCCESS;
3303 ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
3304
3305 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3306 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3307
3308 Status = MapDefaultKey (&KeyHandle,
3309 hKey);
3310 if (!NT_SUCCESS(Status))
3311 {
3312 return RtlNtStatusToDosError (Status);
3313 }
3314
3315 if (lpData != NULL && lpcbData == NULL)
3316 {
3317 ErrorCode = ERROR_INVALID_PARAMETER;
3318 goto Cleanup;
3319 }
3320
3321 RtlInitUnicodeString (&ValueName,
3322 lpValueName);
3323 BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
3324 ValueInfo = RtlAllocateHeap (ProcessHeap,
3325 0,
3326 BufferSize);
3327 if (ValueInfo == NULL)
3328 {
3329 ErrorCode = ERROR_OUTOFMEMORY;
3330 goto Cleanup;
3331 }
3332
3333 Status = NtQueryValueKey (KeyHandle,
3334 &ValueName,
3335 KeyValuePartialInformation,
3336 ValueInfo,
3337 BufferSize,
3338 &ResultSize);
3339 TRACE("Status 0x%X\n", Status);
3340 if (Status == STATUS_BUFFER_OVERFLOW)
3341 {
3342 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3343 MaxCopy = 0;
3344 ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
3345 }
3346 else if (!NT_SUCCESS(Status))
3347 {
3348 ErrorCode = RtlNtStatusToDosError (Status);
3349 MaxCopy = 0;
3350 if (lpcbData != NULL)
3351 {
3352 ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
3353 }
3354 }
3355
3356 if (lpType != NULL)
3357 {
3358 *lpType = ValueInfo->Type;
3359 }
3360
3361 if (NT_SUCCESS(Status) && lpData != NULL)
3362 {
3363 RtlMoveMemory (lpData,
3364 ValueInfo->Data,
3365 min(ValueInfo->DataLength, MaxCopy));
3366 }
3367
3368 if ((ValueInfo->Type == REG_SZ) ||
3369 (ValueInfo->Type == REG_MULTI_SZ) ||
3370 (ValueInfo->Type == REG_EXPAND_SZ))
3371 {
3372 if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
3373 {
3374 ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
3375 }
3376
3377 if (lpcbData != NULL)
3378 {
3379 *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
3380 TRACE("(string) Returning Size: %lu\n", *lpcbData);
3381 }
3382 }
3383 else
3384 {
3385 if (lpcbData != NULL)
3386 {
3387 *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
3388 TRACE("(other) Returning Size: %lu\n", *lpcbData);
3389 }
3390 }
3391
3392 TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
3393
3394 RtlFreeHeap (ProcessHeap,
3395 0,
3396 ValueInfo);
3397
3398 Cleanup:
3399 CloseDefaultKey(KeyHandle);
3400
3401 return ErrorCode;
3402 }
3403
3404
3405 /************************************************************************
3406 * RegQueryValueExA
3407 *
3408 * @implemented
3409 */
3410 LONG STDCALL
3411 RegQueryValueExA (HKEY hKey,
3412 LPCSTR lpValueName,
3413 LPDWORD lpReserved,
3414 LPDWORD lpType,
3415 LPBYTE lpData,
3416 LPDWORD lpcbData)
3417 {
3418 UNICODE_STRING ValueName;
3419 UNICODE_STRING ValueData;
3420 ANSI_STRING AnsiString;
3421 LONG ErrorCode;
3422 DWORD Length;
3423 DWORD Type;
3424
3425 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3426 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3427
3428 if (lpData != NULL && lpcbData == NULL)
3429 {
3430 return ERROR_INVALID_PARAMETER;
3431 }
3432
3433 if (lpData)
3434 {
3435 ValueData.Length = 0;
3436 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
3437 ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
3438 0,
3439 ValueData.MaximumLength);
3440 if (!ValueData.Buffer)
3441 {
3442 return ERROR_OUTOFMEMORY;
3443 }
3444 }
3445 else
3446 {
3447 ValueData.Buffer = NULL;
3448 ValueData.Length = 0;
3449 ValueData.MaximumLength = 0;
3450 }
3451
3452 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3453 (LPSTR)lpValueName);
3454
3455 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
3456 ErrorCode = RegQueryValueExW (hKey,
3457 ValueName.Buffer,
3458 lpReserved,
3459 &Type,
3460 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
3461 &Length);
3462 TRACE("ErrorCode %lu\n", ErrorCode);
3463 RtlFreeUnicodeString(&ValueName);
3464
3465 if (ErrorCode == ERROR_SUCCESS ||
3466 ErrorCode == ERROR_MORE_DATA)
3467 {
3468 if (lpType != NULL)
3469 {
3470 *lpType = Type;
3471 }
3472
3473 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
3474 {
3475 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3476 {
3477 RtlInitAnsiString(&AnsiString, NULL);
3478 AnsiString.Buffer = (LPSTR)lpData;
3479 AnsiString.MaximumLength = *lpcbData;
3480 ValueData.Length = Length;
3481 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
3482 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
3483 }
3484 Length = Length / sizeof(WCHAR);
3485 }
3486 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3487 {
3488 if (*lpcbData < Length)
3489 {
3490 ErrorCode = ERROR_MORE_DATA;
3491 }
3492 else
3493 {
3494 RtlMoveMemory(lpData, ValueData.Buffer, Length);
3495 }
3496 }
3497
3498 if (lpcbData != NULL)
3499 {
3500 *lpcbData = Length;
3501 }
3502 }
3503
3504 if (ValueData.Buffer != NULL)
3505 {
3506 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
3507 }
3508
3509 return ErrorCode;
3510 }
3511
3512
3513 /************************************************************************
3514 * RegQueryValueA
3515 *
3516 * @implemented
3517 */
3518 LONG STDCALL
3519 RegQueryValueA (HKEY hKey,
3520 LPCSTR lpSubKey,
3521 LPSTR lpValue,
3522 PLONG lpcbValue)
3523 {
3524 WCHAR SubKeyNameBuffer[MAX_PATH+1];
3525 UNICODE_STRING SubKeyName;
3526 UNICODE_STRING Value;
3527 ANSI_STRING AnsiString;
3528 LONG ValueSize;
3529 LONG ErrorCode;
3530
3531 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3532 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3533
3534 if (lpValue != NULL &&
3535 lpcbValue == NULL)
3536 {
3537 return ERROR_INVALID_PARAMETER;
3538 }
3539
3540 RtlInitUnicodeString (&SubKeyName,
3541 NULL);
3542 RtlInitUnicodeString (&Value,
3543 NULL);
3544 if (lpSubKey != NULL &&
3545 strlen(lpSubKey) != 0)
3546 {
3547 RtlInitAnsiString (&AnsiString,
3548 (LPSTR)lpSubKey);
3549 SubKeyName.Buffer = &SubKeyNameBuffer[0];
3550 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
3551 RtlAnsiStringToUnicodeString (&SubKeyName,
3552 &AnsiString,
3553 FALSE);
3554 }
3555
3556 if (lpValue != NULL)
3557 {
3558 ValueSize = *lpcbValue * sizeof(WCHAR);
3559 Value.MaximumLength = ValueSize;
3560 Value.Buffer = RtlAllocateHeap (ProcessHeap,
3561 0,
3562 ValueSize);
3563 if (Value.Buffer == NULL)
3564 {
3565 return ERROR_OUTOFMEMORY;
3566 }
3567 }
3568 else
3569 {
3570 ValueSize = 0;
3571 }
3572
3573 ErrorCode = RegQueryValueW (hKey,
3574 (LPCWSTR)SubKeyName.Buffer,
3575 Value.Buffer,
3576 &ValueSize);
3577 if (ErrorCode == ERROR_SUCCESS)
3578 {
3579 Value.Length = ValueSize;
3580 RtlInitAnsiString (&AnsiString,
3581 NULL);
3582 AnsiString.Buffer = lpValue;
3583 AnsiString.MaximumLength = *lpcbValue;
3584 RtlUnicodeStringToAnsiString (&AnsiString,
3585 &Value,
3586 FALSE);
3587 }
3588
3589 *lpcbValue = ValueSize;
3590 if (Value.Buffer != NULL)
3591 {
3592 RtlFreeHeap (ProcessHeap,
3593 0,
3594 Value.Buffer);
3595 }
3596
3597 return ErrorCode;
3598 }
3599
3600
3601 /************************************************************************
3602 * RegQueryValueW
3603 *
3604 * @implemented
3605 */
3606 LONG STDCALL
3607 RegQueryValueW (HKEY hKey,
3608 LPCWSTR lpSubKey,
3609 LPWSTR lpValue,
3610 PLONG lpcbValue)
3611 {
3612 OBJECT_ATTRIBUTES ObjectAttributes;
3613 UNICODE_STRING SubKeyString;
3614 HANDLE KeyHandle;
3615 HANDLE RealKey;
3616 LONG ErrorCode;
3617 BOOL CloseRealKey;
3618 NTSTATUS Status;
3619
3620 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3621 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3622
3623 Status = MapDefaultKey (&KeyHandle,
3624 hKey);
3625 if (!NT_SUCCESS(Status))
3626 {
3627 return RtlNtStatusToDosError (Status);
3628 }
3629
3630 if (lpSubKey != NULL &&
3631 wcslen(lpSubKey) != 0)
3632 {
3633 RtlInitUnicodeString (&SubKeyString,
3634 (LPWSTR)lpSubKey);
3635 InitializeObjectAttributes (&ObjectAttributes,
3636 &SubKeyString,
3637 OBJ_CASE_INSENSITIVE,
3638 KeyHandle,
3639 NULL);
3640 Status = NtOpenKey (&RealKey,
3641 KEY_QUERY_VALUE,
3642 &ObjectAttributes);
3643 if (!NT_SUCCESS(Status))
3644 {
3645 ErrorCode = RtlNtStatusToDosError (Status);
3646 goto Cleanup;
3647 }
3648 CloseRealKey = TRUE;
3649 }
3650 else
3651 {
3652 RealKey = hKey;
3653 CloseRealKey = FALSE;
3654 }
3655
3656 ErrorCode = RegQueryValueExW (RealKey,
3657 NULL,
3658 NULL,
3659 NULL,
3660 (LPBYTE)lpValue,
3661 (LPDWORD)lpcbValue);
3662 if (CloseRealKey)
3663 {
3664 NtClose (RealKey);
3665 }
3666
3667 Cleanup:
3668 CloseDefaultKey(KeyHandle);
3669
3670 return ErrorCode;
3671 }
3672
3673
3674 /************************************************************************
3675 * RegReplaceKeyA
3676 *
3677 * @implemented
3678 */
3679 LONG STDCALL
3680 RegReplaceKeyA (HKEY hKey,
3681 LPCSTR lpSubKey,
3682 LPCSTR lpNewFile,
3683 LPCSTR lpOldFile)
3684 {
3685 UNICODE_STRING SubKey;
3686 UNICODE_STRING NewFile;
3687 UNICODE_STRING OldFile;
3688 LONG ErrorCode;
3689
3690 RtlCreateUnicodeStringFromAsciiz (&SubKey,
3691 (PCSZ)lpSubKey);
3692 RtlCreateUnicodeStringFromAsciiz (&OldFile,
3693 (PCSZ)lpOldFile);
3694 RtlCreateUnicodeStringFromAsciiz (&NewFile,
3695 (PCSZ)lpNewFile);
3696
3697 ErrorCode = RegReplaceKeyW (hKey,
3698 SubKey.Buffer,
3699 NewFile.Buffer,
3700 OldFile.Buffer);
3701
3702 RtlFreeUnicodeString (&OldFile);
3703 RtlFreeUnicodeString (&NewFile);
3704 RtlFreeUnicodeString (&SubKey);
3705
3706 return ErrorCode;
3707 }
3708
3709
3710 /************************************************************************
3711 * RegReplaceKeyW
3712 *
3713 * @unimplemented
3714 */
3715 LONG STDCALL
3716 RegReplaceKeyW (HKEY hKey,
3717 LPCWSTR lpSubKey,
3718 LPCWSTR lpNewFile,
3719 LPCWSTR lpOldFile)
3720 {
3721 OBJECT_ATTRIBUTES KeyObjectAttributes;
3722 OBJECT_ATTRIBUTES NewObjectAttributes;
3723 OBJECT_ATTRIBUTES OldObjectAttributes;
3724 UNICODE_STRING SubKeyName;
3725 UNICODE_STRING NewFileName;
3726 UNICODE_STRING OldFileName;
3727 BOOLEAN CloseRealKey;
3728 HANDLE RealKeyHandle;
3729 HANDLE KeyHandle;
3730 NTSTATUS Status;
3731 LONG ErrorCode = ERROR_SUCCESS;
3732
3733 if (hKey == HKEY_PERFORMANCE_DATA)
3734 {
3735 return ERROR_INVALID_HANDLE;
3736 }
3737
3738 Status = MapDefaultKey (&KeyHandle,
3739 hKey);
3740 if (!NT_SUCCESS(Status))
3741 {
3742 return RtlNtStatusToDosError (Status);
3743 }
3744
3745 /* Open the real key */
3746 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
3747 {
3748 RtlInitUnicodeString (&SubKeyName,
3749 (PWSTR)lpSubKey);
3750 InitializeObjectAttributes (&KeyObjectAttributes,
3751 &SubKeyName,
3752 OBJ_CASE_INSENSITIVE,
3753 KeyHandle,
3754 NULL);
3755 Status = NtOpenKey (&RealKeyHandle,
3756 MAXIMUM_ALLOWED,
3757 &KeyObjectAttributes);
3758 if (!NT_SUCCESS(Status))
3759 {
3760 ErrorCode = RtlNtStatusToDosError (Status);
3761 goto Cleanup;
3762 }
3763 CloseRealKey = TRUE;
3764 }
3765 else
3766 {
3767 RealKeyHandle = KeyHandle;
3768 CloseRealKey = FALSE;
3769 }
3770
3771 /* Convert new file name */
3772 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
3773 &NewFileName,
3774 NULL,
3775 NULL))
3776 {
3777 if (CloseRealKey)
3778 {
3779 NtClose (RealKeyHandle);
3780 }
3781 ErrorCode = ERROR_INVALID_PARAMETER;
3782 goto Cleanup;
3783 }
3784
3785 InitializeObjectAttributes (&NewObjectAttributes,
3786 &NewFileName,
3787 OBJ_CASE_INSENSITIVE,
3788 NULL,
3789 NULL);
3790
3791 /* Convert old file name */
3792 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
3793 &OldFileName,
3794 NULL,
3795 NULL))
3796 {
3797 RtlFreeUnicodeString (&NewFileName);
3798 if (CloseRealKey)
3799 {
3800 NtClose (RealKeyHandle);
3801 }
3802 ErrorCode = ERROR_INVALID_PARAMETER;
3803 goto Cleanup;
3804 }
3805
3806 InitializeObjectAttributes (&OldObjectAttributes,
3807 &OldFileName,
3808 OBJ_CASE_INSENSITIVE,
3809 NULL,
3810 NULL);
3811
3812 Status = NtReplaceKey (&NewObjectAttributes,
3813 RealKeyHandle,
3814 &OldObjectAttributes);
3815
3816 RtlFreeUnicodeString (&OldFileName);
3817 RtlFreeUnicodeString (&NewFileName);
3818
3819 if (CloseRealKey)
3820 {
3821 NtClose (RealKeyHandle);
3822 }
3823
3824 if (!NT_SUCCESS(Status))
3825 {
3826 return RtlNtStatusToDosError (Status);
3827 }
3828
3829 Cleanup:
3830 CloseDefaultKey(KeyHandle);
3831
3832 return ErrorCode;
3833 }
3834
3835
3836 /************************************************************************
3837 * RegRestoreKeyA
3838 *
3839 * @implemented
3840 */
3841 LONG STDCALL
3842 RegRestoreKeyA (HKEY hKey,
3843 LPCSTR lpFile,
3844 DWORD dwFlags)
3845 {
3846 UNICODE_STRING FileName;
3847 LONG ErrorCode;
3848
3849 RtlCreateUnicodeStringFromAsciiz (&FileName,
3850 (PCSZ)lpFile);
3851
3852 ErrorCode = RegRestoreKeyW (hKey,
3853 FileName.Buffer,
3854 dwFlags);
3855
3856 RtlFreeUnicodeString (&FileName);
3857
3858 return ErrorCode;
3859 }
3860
3861
3862 /************************************************************************
3863 * RegRestoreKeyW
3864 *
3865 * @implemented
3866 */
3867 LONG STDCALL
3868 RegRestoreKeyW (HKEY hKey,
3869 LPCWSTR lpFile,
3870 DWORD dwFlags)
3871 {
3872 OBJECT_ATTRIBUTES ObjectAttributes;
3873 IO_STATUS_BLOCK IoStatusBlock;
3874 UNICODE_STRING FileName;
3875 HANDLE FileHandle;
3876 HANDLE KeyHandle;
3877 NTSTATUS Status;
3878
3879 if (hKey == HKEY_PERFORMANCE_DATA)
3880 {
3881 return ERROR_INVALID_HANDLE;
3882 }
3883
3884 Status = MapDefaultKey (&KeyHandle,
3885 hKey);
3886 if (!NT_SUCCESS(Status))
3887 {
3888 return RtlNtStatusToDosError (Status);
3889 }
3890
3891 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
3892 &FileName,
3893 NULL,
3894 NULL))
3895 {
3896 Status = STATUS_INVALID_PARAMETER;
3897 goto Cleanup;
3898 }
3899
3900 InitializeObjectAttributes (&ObjectAttributes,
3901 &FileName,
3902 OBJ_CASE_INSENSITIVE,
3903 NULL,
3904 NULL);
3905
3906 Status = NtOpenFile (&FileHandle,
3907 FILE_GENERIC_READ,
3908 &ObjectAttributes,
3909 &IoStatusBlock,
3910 FILE_SHARE_READ,
3911 FILE_SYNCHRONOUS_IO_NONALERT);
3912 RtlFreeUnicodeString (&FileName);
3913 if (!NT_SUCCESS(Status))
3914 {
3915 goto Cleanup;
3916 }
3917
3918 Status = NtRestoreKey (KeyHandle,
3919 FileHandle,
3920 (ULONG)dwFlags);
3921 NtClose (FileHandle);
3922
3923 Cleanup:
3924 CloseDefaultKey(KeyHandle);
3925
3926 if (!NT_SUCCESS(Status))
3927 {
3928 return RtlNtStatusToDosError (Status);
3929 }
3930
3931 return ERROR_SUCCESS;
3932 }
3933
3934
3935 /************************************************************************
3936 * RegSaveKeyA
3937 *
3938 * @implemented
3939 */
3940 LONG STDCALL
3941 RegSaveKeyA (HKEY hKey,
3942 LPCSTR lpFile,
3943 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3944 {
3945 UNICODE_STRING FileName;
3946 LONG ErrorCode;
3947
3948 RtlCreateUnicodeStringFromAsciiz (&FileName,
3949 (LPSTR)lpFile);
3950 ErrorCode = RegSaveKeyW (hKey,
3951 FileName.Buffer,
3952 lpSecurityAttributes);
3953 RtlFreeUnicodeString (&FileName);
3954
3955 return ErrorCode;
3956 }
3957
3958
3959 /************************************************************************
3960 * RegSaveKeyW
3961 *
3962 * @implemented
3963 */
3964 LONG STDCALL
3965 RegSaveKeyW (HKEY hKey,
3966 LPCWSTR lpFile,
3967 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3968 {
3969 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
3970 OBJECT_ATTRIBUTES ObjectAttributes;
3971 UNICODE_STRING FileName;
3972 IO_STATUS_BLOCK IoStatusBlock;
3973 HANDLE FileHandle;
3974 HANDLE KeyHandle;
3975 NTSTATUS Status;
3976
3977 Status = MapDefaultKey (&KeyHandle,
3978 hKey);
3979 if (!NT_SUCCESS(Status))
3980 {
3981 return RtlNtStatusToDosError (Status);
3982 }
3983
3984 if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
3985 &FileName,
3986 NULL,
3987 NULL))
3988 {
3989 Status = STATUS_INVALID_PARAMETER;
3990 goto Cleanup;
3991 }
3992
3993 if (lpSecurityAttributes != NULL)
3994 {
3995 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
3996 }
3997
3998 InitializeObjectAttributes (&ObjectAttributes,
3999 &FileName,
4000 OBJ_CASE_INSENSITIVE,
4001 NULL,
4002 SecurityDescriptor);
4003 Status = NtCreateFile (&FileHandle,
4004 GENERIC_WRITE | SYNCHRONIZE,
4005 &ObjectAttributes,
4006 &IoStatusBlock,
4007 NULL,
4008 FILE_ATTRIBUTE_NORMAL,
4009 FILE_SHARE_READ,
4010 FILE_CREATE,
4011 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4012 NULL,
4013 0);
4014 RtlFreeUnicodeString (&FileName);
4015 if (!NT_SUCCESS(Status))
4016 {
4017 goto Cleanup;
4018 }
4019
4020 Status = NtSaveKey (KeyHandle,
4021 FileHandle);
4022 NtClose (FileHandle);
4023
4024 Cleanup:
4025 CloseDefaultKey(KeyHandle);
4026
4027 if (!NT_SUCCESS(Status))
4028 {
4029 return RtlNtStatusToDosError (Status);
4030 }
4031
4032 return ERROR_SUCCESS;
4033 }
4034
4035
4036 /************************************************************************
4037 * RegSetKeySecurity
4038 *
4039 * @implemented
4040 */
4041 LONG STDCALL
4042 RegSetKeySecurity (HKEY hKey,
4043 SECURITY_INFORMATION SecurityInformation,
4044 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4045 {
4046 HANDLE KeyHandle;
4047 NTSTATUS Status;
4048
4049 if (hKey == HKEY_PERFORMANCE_DATA)
4050 {
4051 return ERROR_INVALID_HANDLE;
4052 }
4053
4054 Status = MapDefaultKey (&KeyHandle,
4055 hKey);
4056 if (!NT_SUCCESS(Status))
4057 {
4058 return RtlNtStatusToDosError (Status);
4059 }
4060
4061 Status = NtSetSecurityObject (KeyHandle,
4062 SecurityInformation,
4063 pSecurityDescriptor);
4064
4065 CloseDefaultKey(KeyHandle);
4066
4067 if (!NT_SUCCESS(Status))
4068 {
4069 return RtlNtStatusToDosError (Status);
4070 }
4071
4072 return ERROR_SUCCESS;
4073 }
4074
4075
4076 /************************************************************************
4077 * RegSetValueExA
4078 *
4079 * @implemented
4080 */
4081 LONG STDCALL
4082 RegSetValueExA (HKEY hKey,
4083 LPCSTR lpValueName,
4084 DWORD Reserved,
4085 DWORD dwType,
4086 CONST BYTE* lpData,
4087 DWORD cbData)
4088 {
4089 UNICODE_STRING ValueName;
4090 LPWSTR pValueName;
4091 ANSI_STRING AnsiString;
4092 UNICODE_STRING Data;
4093 LONG ErrorCode;
4094 LPBYTE pData;
4095 DWORD DataSize;
4096
4097 if (lpValueName != NULL &&
4098 strlen(lpValueName) != 0)
4099 {
4100 RtlCreateUnicodeStringFromAsciiz (&ValueName,
4101 (PSTR)lpValueName);
4102 pValueName = (LPWSTR)ValueName.Buffer;
4103 }
4104 else
4105 {
4106 pValueName = NULL;
4107 }
4108
4109 if (((dwType == REG_SZ) ||
4110 (dwType == REG_MULTI_SZ) ||
4111 (dwType == REG_EXPAND_SZ)) &&
4112 (cbData != 0))
4113 {
4114 /* NT adds one if the caller forgot the NULL-termination character */
4115 if (lpData[cbData - 1] != '\0')
4116 {
4117 cbData++;
4118 }
4119
4120 RtlInitAnsiString (&AnsiString,
4121 NULL);
4122 AnsiString.Buffer = (PSTR)lpData;
4123 AnsiString.Length = cbData - 1;
4124 AnsiString.MaximumLength = cbData;
4125 RtlAnsiStringToUnicodeString (&Data,
4126 &AnsiString,
4127 TRUE);
4128 pData = (LPBYTE)Data.Buffer;
4129 DataSize = cbData * sizeof(WCHAR);
4130 }
4131 else
4132 {
4133 RtlInitUnicodeString (&Data,
4134 NULL);
4135 pData = (LPBYTE)lpData;
4136 DataSize = cbData;
4137 }
4138
4139 ErrorCode = RegSetValueExW (hKey,
4140 pValueName,
4141 Reserved,
4142 dwType,
4143 pData,
4144 DataSize);
4145 if (pValueName != NULL)
4146 {
4147 RtlFreeHeap (ProcessHeap,
4148 0,
4149 ValueName.Buffer);
4150 }
4151
4152 if (Data.Buffer != NULL)
4153 {
4154 RtlFreeHeap (ProcessHeap,
4155 0,
4156 Data.Buffer);
4157 }
4158
4159 return ErrorCode;
4160 }
4161
4162
4163 /************************************************************************
4164 * RegSetValueExW
4165 *
4166 * @implemented
4167 */
4168 LONG STDCALL
4169 RegSetValueExW (HKEY hKey,
4170 LPCWSTR lpValueName,
4171 DWORD Reserved,
4172 DWORD dwType,
4173 CONST BYTE* lpData,
4174 DWORD cbData)
4175 {
4176 UNICODE_STRING ValueName;
4177 PUNICODE_STRING pValueName;
4178 HANDLE KeyHandle;
4179 NTSTATUS Status;
4180
4181 Status = MapDefaultKey (&KeyHandle,
4182 hKey);
4183 if (!NT_SUCCESS(Status))
4184 {
4185 return RtlNtStatusToDosError (Status);
4186 }
4187
4188 if (lpValueName != NULL)
4189 {
4190 RtlInitUnicodeString (&ValueName,
4191 lpValueName);
4192 }
4193 else
4194 {
4195 RtlInitUnicodeString (&ValueName, L"");
4196 }
4197 pValueName = &ValueName;
4198
4199 if (((dwType == REG_SZ) ||
4200 (dwType == REG_MULTI_SZ) ||
4201 (dwType == REG_EXPAND_SZ)) &&
4202 (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
4203 {
4204 /* NT adds one if the caller forgot the NULL-termination character */
4205 cbData += sizeof(WCHAR);
4206 }
4207
4208 Status = NtSetValueKey (KeyHandle,
4209 pValueName,
4210 0,
4211 dwType,
4212 (PVOID)lpData,
4213 (ULONG)cbData);
4214
4215 CloseDefaultKey(KeyHandle);
4216
4217 if (!NT_SUCCESS(Status))
4218 {
4219 return RtlNtStatusToDosError (Status);
4220 }
4221
4222 return ERROR_SUCCESS;
4223 }
4224
4225
4226 /************************************************************************
4227 * RegSetValueA
4228 *
4229 * @implemented
4230 */
4231 LONG STDCALL
4232 RegSetValueA (HKEY hKey,
4233 LPCSTR lpSubKey,
4234 DWORD dwType,
4235 LPCSTR lpData,
4236 DWORD cbData)
4237 {
4238 LONG ret;
4239 HKEY hSubKey;
4240
4241 if (dwType != REG_SZ)
4242 {
4243 return ERROR_INVALID_PARAMETER;
4244 }
4245
4246 if (lpSubKey != NULL && lpSubKey[0] != '\0')
4247 {
4248 ret = RegCreateKeyA(hKey,
4249 lpSubKey,
4250 &hSubKey);
4251
4252 if (ret != ERROR_SUCCESS)
4253 {
4254 return ret;
4255 }
4256 }
4257 else
4258 hSubKey = hKey;
4259
4260 ret = RegSetValueExA(hSubKey,
4261 NULL,
4262 0,
4263 REG_SZ,
4264 (CONST BYTE*)lpData,
4265 strlen(lpData) + 1);
4266
4267 if (hSubKey != hKey)
4268 {
4269 RegCloseKey(hSubKey);
4270 }
4271
4272 return ret;
4273 }
4274
4275
4276 /************************************************************************
4277 * RegSetValueW
4278 *
4279 * @implemented
4280 */
4281 LONG STDCALL
4282 RegSetValueW (HKEY hKey,
4283 LPCWSTR lpSubKey,
4284 DWORD dwType,
4285 LPCWSTR lpData,
4286 DWORD cbData)
4287 {
4288 OBJECT_ATTRIBUTES ObjectAttributes;
4289 UNICODE_STRING SubKeyString;
4290 HANDLE KeyHandle;
4291 HANDLE RealKey;
4292 BOOL CloseRealKey;
4293 NTSTATUS Status;
4294 LONG ErrorCode;
4295
4296 Status = MapDefaultKey (&KeyHandle,
4297 hKey);
4298 if (!NT_SUCCESS(Status))
4299 {
4300 return RtlNtStatusToDosError (Status);
4301 }
4302
4303 if ((lpSubKey) && (wcslen(lpSubKey) != 0))
4304 {
4305 RtlInitUnicodeString (&SubKeyString,
4306 (LPWSTR)lpSubKey);
4307 InitializeObjectAttributes (&ObjectAttributes,
4308 &SubKeyString,
4309 OBJ_CASE_INSENSITIVE,
4310 KeyHandle,
4311 NULL);
4312 Status = NtOpenKey (&RealKey,
4313 KEY_SET_VALUE,
4314 &ObjectAttributes);
4315 if (!NT_SUCCESS(Status))
4316 {
4317 ErrorCode = RtlNtStatusToDosError (Status);
4318 goto Cleanup;
4319 }
4320 CloseRealKey = TRUE;
4321 }
4322 else
4323 {
4324 RealKey = hKey;
4325 CloseRealKey = FALSE;
4326 }
4327
4328 ErrorCode = RegSetValueExW (RealKey,
4329 NULL,
4330 0,
4331 dwType,
4332 (LPBYTE)lpData,
4333 cbData);
4334 if (CloseRealKey == TRUE)
4335 {
4336 NtClose (RealKey);
4337 }
4338
4339 Cleanup:
4340 CloseDefaultKey(KeyHandle);
4341
4342 return ErrorCode;
4343 }
4344
4345
4346 /************************************************************************
4347 * RegUnLoadKeyA
4348 *
4349 * @implemented
4350 */
4351 LONG STDCALL
4352 RegUnLoadKeyA (HKEY hKey,
4353 LPCSTR lpSubKey)
4354 {
4355 UNICODE_STRING KeyName;
4356 DWORD ErrorCode;
4357
4358 RtlCreateUnicodeStringFromAsciiz (&KeyName,
4359 (LPSTR)lpSubKey);
4360
4361 ErrorCode = RegUnLoadKeyW (hKey,
4362 KeyName.Buffer);
4363
4364 RtlFreeUnicodeString (&KeyName);
4365
4366 return ErrorCode;
4367 }
4368
4369
4370 /************************************************************************
4371 * RegUnLoadKeyW
4372 *
4373 * @implemented
4374 */
4375 LONG STDCALL
4376 RegUnLoadKeyW (HKEY hKey,
4377 LPCWSTR lpSubKey)
4378 {
4379 OBJECT_ATTRIBUTES ObjectAttributes;
4380 UNICODE_STRING KeyName;
4381 HANDLE KeyHandle;
4382 NTSTATUS Status;
4383
4384 if (hKey == HKEY_PERFORMANCE_DATA)
4385 {
4386 return ERROR_INVALID_HANDLE;
4387 }
4388
4389 Status = MapDefaultKey (&KeyHandle, hKey);
4390 if (!NT_SUCCESS(Status))
4391 {
4392 return RtlNtStatusToDosError (Status);
4393 }
4394
4395 RtlInitUnicodeString (&KeyName,
4396 (LPWSTR)lpSubKey);
4397
4398 InitializeObjectAttributes (&ObjectAttributes,
4399 &KeyName,
4400 OBJ_CASE_INSENSITIVE,
4401 KeyHandle,
4402 NULL);
4403
4404 Status = NtUnloadKey (&ObjectAttributes);
4405
4406 CloseDefaultKey(KeyHandle);
4407
4408 if (!NT_SUCCESS(Status))
4409 {
4410 return RtlNtStatusToDosError (Status);
4411 }
4412
4413 return ERROR_SUCCESS;
4414 }
4415
4416
4417 /************************************************************************
4418 * RegLoadMUIStringW
4419 *
4420 * @unimplemented
4421 */
4422 LONG STDCALL
4423 RegLoadMUIStringW(IN HKEY hKey,
4424 IN LPCWSTR pszValue OPTIONAL,
4425 OUT LPWSTR pszOutBuf,
4426 IN ULONG cbOutBuf,
4427 IN ULONG Reserved,
4428 IN LPCWSTR pszDirectory OPTIONAL)
4429 {
4430 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4431 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4432 return ERROR_CALL_NOT_IMPLEMENTED;
4433 }
4434
4435
4436 /************************************************************************
4437 * RegLoadMUIStringA
4438 *
4439 * @unimplemented
4440 */
4441 LONG STDCALL
4442 RegLoadMUIStringA(IN HKEY hKey,
4443 IN LPCSTR pszValue OPTIONAL,
4444 OUT LPSTR pszOutBuf,
4445 IN ULONG cbOutBuf,
4446 IN ULONG Reserved,
4447 IN LPCSTR pszDirectory OPTIONAL)
4448 {
4449 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4450 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4451 return ERROR_CALL_NOT_IMPLEMENTED;
4452 }
4453
4454
4455 /* EOF */