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