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