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