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