88e6049c1c1da2f0042da7c0ed846c7f0da3e576
[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(
1017 _In_ HKEY hKey,
1018 _In_ LPCSTR lpSubKey,
1019 _In_ DWORD Reserved,
1020 _In_ LPSTR lpClass,
1021 _In_ DWORD dwOptions,
1022 _In_ REGSAM samDesired,
1023 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1024 _Out_ PHKEY phkResult,
1025 _Out_ LPDWORD lpdwDisposition)
1026 {
1027 UNICODE_STRING SubKeyString;
1028 UNICODE_STRING ClassString;
1029 DWORD ErrorCode;
1030
1031 RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass);
1032 RtlCreateUnicodeStringFromAsciiz(&SubKeyString, (LPSTR)lpSubKey);
1033
1034 ErrorCode = RegCreateKeyExW(
1035 hKey,
1036 SubKeyString.Buffer,
1037 Reserved,
1038 ClassString.Buffer,
1039 dwOptions,
1040 samDesired,
1041 lpSecurityAttributes,
1042 phkResult,
1043 lpdwDisposition);
1044
1045 RtlFreeUnicodeString(&SubKeyString);
1046 RtlFreeUnicodeString(&ClassString);
1047
1048 return ErrorCode;
1049 }
1050
1051
1052 /************************************************************************
1053 * RegCreateKeyExW
1054 *
1055 * @implemented
1056 */
1057 LONG WINAPI
1058 RegCreateKeyExW(HKEY hKey,
1059 LPCWSTR lpSubKey,
1060 DWORD Reserved,
1061 LPWSTR lpClass,
1062 DWORD dwOptions,
1063 REGSAM samDesired,
1064 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1065 PHKEY phkResult,
1066 LPDWORD lpdwDisposition)
1067 {
1068 UNICODE_STRING SubKeyString;
1069 UNICODE_STRING ClassString;
1070 OBJECT_ATTRIBUTES ObjectAttributes;
1071 HANDLE ParentKey;
1072 ULONG Attributes = OBJ_CASE_INSENSITIVE;
1073 NTSTATUS Status;
1074
1075 TRACE("RegCreateKeyExW() called\n");
1076
1077 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1078 return ERROR_INVALID_USER_BUFFER;
1079
1080 /* get the real parent key */
1081 Status = MapDefaultKey(&ParentKey,
1082 hKey);
1083 if (!NT_SUCCESS(Status))
1084 {
1085 return RtlNtStatusToDosError(Status);
1086 }
1087
1088 TRACE("ParentKey %p\n", ParentKey);
1089
1090 if (dwOptions & REG_OPTION_OPEN_LINK)
1091 Attributes |= OBJ_OPENLINK;
1092
1093 RtlInitUnicodeString(&ClassString,
1094 lpClass);
1095 RtlInitUnicodeString(&SubKeyString,
1096 lpSubKey);
1097 InitializeObjectAttributes(&ObjectAttributes,
1098 &SubKeyString,
1099 Attributes,
1100 (HANDLE)ParentKey,
1101 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1102 Status = CreateNestedKey(phkResult,
1103 &ObjectAttributes,
1104 (lpClass == NULL)? NULL : &ClassString,
1105 dwOptions,
1106 samDesired,
1107 lpdwDisposition);
1108
1109 ClosePredefKey(ParentKey);
1110
1111 TRACE("Status %x\n", Status);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 return RtlNtStatusToDosError(Status);
1115 }
1116
1117 return ERROR_SUCCESS;
1118 }
1119
1120
1121 /************************************************************************
1122 * RegCreateKeyA
1123 *
1124 * @implemented
1125 */
1126 LONG WINAPI
1127 RegCreateKeyA(HKEY hKey,
1128 LPCSTR lpSubKey,
1129 PHKEY phkResult)
1130 {
1131 return RegCreateKeyExA(hKey,
1132 lpSubKey,
1133 0,
1134 NULL,
1135 0,
1136 MAXIMUM_ALLOWED,
1137 NULL,
1138 phkResult,
1139 NULL);
1140 }
1141
1142
1143 /************************************************************************
1144 * RegCreateKeyW
1145 *
1146 * @implemented
1147 */
1148 LONG WINAPI
1149 RegCreateKeyW(HKEY hKey,
1150 LPCWSTR lpSubKey,
1151 PHKEY phkResult)
1152 {
1153 return RegCreateKeyExW(hKey,
1154 lpSubKey,
1155 0,
1156 NULL,
1157 0,
1158 MAXIMUM_ALLOWED,
1159 NULL,
1160 phkResult,
1161 NULL);
1162 }
1163
1164
1165 /************************************************************************
1166 * RegDeleteKeyA
1167 *
1168 * @implemented
1169 */
1170 LONG WINAPI
1171 RegDeleteKeyA(HKEY hKey,
1172 LPCSTR lpSubKey)
1173 {
1174 OBJECT_ATTRIBUTES ObjectAttributes;
1175 UNICODE_STRING SubKeyName;
1176 HANDLE ParentKey;
1177 HANDLE TargetKey;
1178 NTSTATUS Status;
1179
1180 /* Make sure we got a subkey */
1181 if (!lpSubKey)
1182 {
1183 /* Fail */
1184 return ERROR_INVALID_PARAMETER;
1185 }
1186
1187 Status = MapDefaultKey(&ParentKey,
1188 hKey);
1189 if (!NT_SUCCESS(Status))
1190 {
1191 return RtlNtStatusToDosError(Status);
1192 }
1193
1194 RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1195 (LPSTR)lpSubKey);
1196 InitializeObjectAttributes(&ObjectAttributes,
1197 &SubKeyName,
1198 OBJ_CASE_INSENSITIVE,
1199 ParentKey,
1200 NULL);
1201
1202 Status = NtOpenKey(&TargetKey,
1203 DELETE,
1204 &ObjectAttributes);
1205 RtlFreeUnicodeString(&SubKeyName);
1206 if (!NT_SUCCESS(Status))
1207 {
1208 goto Cleanup;
1209 }
1210
1211 Status = NtDeleteKey(TargetKey);
1212 NtClose (TargetKey);
1213
1214 Cleanup:
1215 ClosePredefKey(ParentKey);
1216
1217 if (!NT_SUCCESS(Status))
1218 {
1219 return RtlNtStatusToDosError(Status);
1220 }
1221
1222 return ERROR_SUCCESS;
1223 }
1224
1225
1226 /************************************************************************
1227 * RegDeleteKeyW
1228 *
1229 * @implemented
1230 */
1231 LONG WINAPI
1232 RegDeleteKeyW(HKEY hKey,
1233 LPCWSTR lpSubKey)
1234 {
1235 OBJECT_ATTRIBUTES ObjectAttributes;
1236 UNICODE_STRING SubKeyName;
1237 HANDLE ParentKey;
1238 HANDLE TargetKey;
1239 NTSTATUS Status;
1240
1241 /* Make sure we got a subkey */
1242 if (!lpSubKey)
1243 {
1244 /* Fail */
1245 return ERROR_INVALID_PARAMETER;
1246 }
1247
1248 Status = MapDefaultKey(&ParentKey,
1249 hKey);
1250 if (!NT_SUCCESS(Status))
1251 {
1252 return RtlNtStatusToDosError(Status);
1253 }
1254
1255 RtlInitUnicodeString(&SubKeyName,
1256 (LPWSTR)lpSubKey);
1257 InitializeObjectAttributes(&ObjectAttributes,
1258 &SubKeyName,
1259 OBJ_CASE_INSENSITIVE,
1260 ParentKey,
1261 NULL);
1262 Status = NtOpenKey(&TargetKey,
1263 DELETE,
1264 &ObjectAttributes);
1265 if (!NT_SUCCESS(Status))
1266 {
1267 goto Cleanup;
1268 }
1269
1270 Status = NtDeleteKey(TargetKey);
1271 NtClose(TargetKey);
1272
1273 Cleanup:
1274 ClosePredefKey(ParentKey);
1275
1276 if (!NT_SUCCESS(Status))
1277 {
1278 return RtlNtStatusToDosError(Status);
1279 }
1280
1281 return ERROR_SUCCESS;
1282 }
1283
1284
1285 /************************************************************************
1286 * RegDeleteKeyExA
1287 *
1288 * @implemented
1289 */
1290 LONG
1291 WINAPI
1292 RegDeleteKeyExA(HKEY hKey,
1293 LPCSTR lpSubKey,
1294 REGSAM samDesired,
1295 DWORD Reserved)
1296 {
1297 OBJECT_ATTRIBUTES ObjectAttributes;
1298 UNICODE_STRING SubKeyName;
1299 HANDLE ParentKey;
1300 HANDLE TargetKey;
1301 NTSTATUS Status;
1302
1303 /* Make sure we got a subkey */
1304 if (!lpSubKey)
1305 {
1306 /* Fail */
1307 return ERROR_INVALID_PARAMETER;
1308 }
1309
1310 Status = MapDefaultKey(&ParentKey,
1311 hKey);
1312 if (!NT_SUCCESS(Status))
1313 {
1314 return RtlNtStatusToDosError(Status);
1315 }
1316
1317 if (samDesired & KEY_WOW64_32KEY)
1318 ERR("Wow64 not yet supported!\n");
1319
1320 if (samDesired & KEY_WOW64_64KEY)
1321 ERR("Wow64 not yet supported!\n");
1322
1323 RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1324 (LPSTR)lpSubKey);
1325 InitializeObjectAttributes(&ObjectAttributes,
1326 &SubKeyName,
1327 OBJ_CASE_INSENSITIVE,
1328 ParentKey,
1329 NULL);
1330
1331 Status = NtOpenKey(&TargetKey,
1332 DELETE,
1333 &ObjectAttributes);
1334 RtlFreeUnicodeString(&SubKeyName);
1335 if (!NT_SUCCESS(Status))
1336 {
1337 goto Cleanup;
1338 }
1339
1340 Status = NtDeleteKey(TargetKey);
1341 NtClose (TargetKey);
1342
1343 Cleanup:
1344 ClosePredefKey(ParentKey);
1345
1346 if (!NT_SUCCESS(Status))
1347 {
1348 return RtlNtStatusToDosError(Status);
1349 }
1350
1351 return ERROR_SUCCESS;
1352 }
1353
1354
1355 /************************************************************************
1356 * RegDeleteKeyExW
1357 *
1358 * @implemented
1359 */
1360 LONG
1361 WINAPI
1362 RegDeleteKeyExW(HKEY hKey,
1363 LPCWSTR lpSubKey,
1364 REGSAM samDesired,
1365 DWORD Reserved)
1366 {
1367 OBJECT_ATTRIBUTES ObjectAttributes;
1368 UNICODE_STRING SubKeyName;
1369 HANDLE ParentKey;
1370 HANDLE TargetKey;
1371 NTSTATUS Status;
1372
1373 /* Make sure we got a subkey */
1374 if (!lpSubKey)
1375 {
1376 /* Fail */
1377 return ERROR_INVALID_PARAMETER;
1378 }
1379
1380 Status = MapDefaultKey(&ParentKey,
1381 hKey);
1382 if (!NT_SUCCESS(Status))
1383 {
1384 return RtlNtStatusToDosError(Status);
1385 }
1386
1387 if (samDesired & KEY_WOW64_32KEY)
1388 ERR("Wow64 not yet supported!\n");
1389
1390 if (samDesired & KEY_WOW64_64KEY)
1391 ERR("Wow64 not yet supported!\n");
1392
1393
1394 RtlInitUnicodeString(&SubKeyName,
1395 (LPWSTR)lpSubKey);
1396 InitializeObjectAttributes(&ObjectAttributes,
1397 &SubKeyName,
1398 OBJ_CASE_INSENSITIVE,
1399 ParentKey,
1400 NULL);
1401 Status = NtOpenKey(&TargetKey,
1402 DELETE,
1403 &ObjectAttributes);
1404 if (!NT_SUCCESS(Status))
1405 {
1406 goto Cleanup;
1407 }
1408
1409 Status = NtDeleteKey(TargetKey);
1410 NtClose(TargetKey);
1411
1412 Cleanup:
1413 ClosePredefKey(ParentKey);
1414
1415 if (!NT_SUCCESS(Status))
1416 {
1417 return RtlNtStatusToDosError(Status);
1418 }
1419
1420 return ERROR_SUCCESS;
1421 }
1422
1423
1424 /************************************************************************
1425 * RegDeleteKeyValueW
1426 *
1427 * @implemented
1428 */
1429 LONG WINAPI
1430 RegDeleteKeyValueW(IN HKEY hKey,
1431 IN LPCWSTR lpSubKey OPTIONAL,
1432 IN LPCWSTR lpValueName OPTIONAL)
1433 {
1434 UNICODE_STRING ValueName;
1435 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1436 NTSTATUS Status;
1437
1438 Status = MapDefaultKey(&KeyHandle,
1439 hKey);
1440 if (!NT_SUCCESS(Status))
1441 {
1442 return RtlNtStatusToDosError(Status);
1443 }
1444
1445 if (lpSubKey != NULL)
1446 {
1447 OBJECT_ATTRIBUTES ObjectAttributes;
1448 UNICODE_STRING SubKeyName;
1449
1450 RtlInitUnicodeString(&SubKeyName,
1451 (LPWSTR)lpSubKey);
1452
1453 InitializeObjectAttributes(&ObjectAttributes,
1454 &SubKeyName,
1455 OBJ_CASE_INSENSITIVE,
1456 KeyHandle,
1457 NULL);
1458
1459 Status = NtOpenKey(&SubKeyHandle,
1460 KEY_SET_VALUE,
1461 &ObjectAttributes);
1462 if (!NT_SUCCESS(Status))
1463 {
1464 goto Cleanup;
1465 }
1466
1467 CurKey = SubKeyHandle;
1468 }
1469 else
1470 CurKey = KeyHandle;
1471
1472 RtlInitUnicodeString(&ValueName,
1473 (LPWSTR)lpValueName);
1474
1475 Status = NtDeleteValueKey(CurKey,
1476 &ValueName);
1477
1478 if (SubKeyHandle != NULL)
1479 {
1480 NtClose(SubKeyHandle);
1481 }
1482
1483 Cleanup:
1484 ClosePredefKey(KeyHandle);
1485
1486 if (!NT_SUCCESS(Status))
1487 {
1488 return RtlNtStatusToDosError(Status);
1489 }
1490
1491 return ERROR_SUCCESS;
1492 }
1493
1494
1495 /************************************************************************
1496 * RegDeleteKeyValueA
1497 *
1498 * @implemented
1499 */
1500 LONG WINAPI
1501 RegDeleteKeyValueA(IN HKEY hKey,
1502 IN LPCSTR lpSubKey OPTIONAL,
1503 IN LPCSTR lpValueName OPTIONAL)
1504 {
1505 UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
1506 LONG Ret;
1507
1508 if (lpSubKey != NULL &&
1509 !RtlCreateUnicodeStringFromAsciiz(&SubKey,
1510 (LPSTR)lpSubKey))
1511 {
1512 return ERROR_NOT_ENOUGH_MEMORY;
1513 }
1514
1515 if (lpValueName != NULL &&
1516 !RtlCreateUnicodeStringFromAsciiz(&ValueName,
1517 (LPSTR)lpValueName))
1518 {
1519 RtlFreeUnicodeString(&SubKey);
1520 return ERROR_NOT_ENOUGH_MEMORY;
1521 }
1522
1523 Ret = RegDeleteKeyValueW(hKey,
1524 SubKey.Buffer,
1525 SubKey.Buffer);
1526
1527 RtlFreeUnicodeString(&SubKey);
1528 RtlFreeUnicodeString(&ValueName);
1529
1530 return Ret;
1531 }
1532
1533 #if 0
1534 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1535 static NTSTATUS
1536 RegpDeleteTree(IN HKEY hKey)
1537 {
1538 typedef struct
1539 {
1540 LIST_ENTRY ListEntry;
1541 HANDLE KeyHandle;
1542 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1543
1544 LIST_ENTRY delQueueHead;
1545 PREG_DEL_KEYS delKeys, newDelKeys;
1546 HANDLE ProcessHeap;
1547 ULONG BufferSize;
1548 PKEY_BASIC_INFORMATION BasicInfo;
1549 PREG_DEL_KEYS KeyDelRoot;
1550 NTSTATUS Status = STATUS_SUCCESS;
1551 NTSTATUS Status2 = STATUS_SUCCESS;
1552
1553 InitializeListHead(&delQueueHead);
1554
1555 ProcessHeap = RtlGetProcessHeap();
1556
1557 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1558 structure for the root key, we only do that for subkeys as we need to
1559 allocate REGP_DEL_KEYS structures anyway! */
1560 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1561 0,
1562 sizeof(REGP_DEL_KEYS));
1563 if (KeyDelRoot != NULL)
1564 {
1565 KeyDelRoot->KeyHandle = hKey;
1566 InsertTailList(&delQueueHead,
1567 &KeyDelRoot->ListEntry);
1568
1569 do
1570 {
1571 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1572 REGP_DEL_KEYS,
1573 ListEntry);
1574
1575 BufferSize = 0;
1576 BasicInfo = NULL;
1577 newDelKeys = NULL;
1578
1579 ReadFirstSubKey:
1580 /* check if this key contains subkeys and delete them first by queuing
1581 them at the head of the list */
1582 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1583 0,
1584 KeyBasicInformation,
1585 BasicInfo,
1586 BufferSize,
1587 &BufferSize);
1588
1589 if (NT_SUCCESS(Status2))
1590 {
1591 OBJECT_ATTRIBUTES ObjectAttributes;
1592 UNICODE_STRING SubKeyName;
1593
1594 ASSERT(newDelKeys != NULL);
1595 ASSERT(BasicInfo != NULL);
1596
1597 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1598 SubKeyName.Length = BasicInfo->NameLength;
1599 SubKeyName.MaximumLength = BasicInfo->NameLength;
1600 SubKeyName.Buffer = BasicInfo->Name;
1601
1602 InitializeObjectAttributes(&ObjectAttributes,
1603 &SubKeyName,
1604 OBJ_CASE_INSENSITIVE,
1605 delKeys->KeyHandle,
1606 NULL);
1607
1608 /* open the subkey */
1609 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1610 DELETE | KEY_ENUMERATE_SUB_KEYS,
1611 &ObjectAttributes);
1612 if (!NT_SUCCESS(Status2))
1613 {
1614 goto SubKeyFailure;
1615 }
1616
1617 /* enqueue this key to the head of the deletion queue */
1618 InsertHeadList(&delQueueHead,
1619 &newDelKeys->ListEntry);
1620
1621 /* try again from the head of the list */
1622 continue;
1623 }
1624 else
1625 {
1626 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1627 {
1628 newDelKeys = RtlAllocateHeap(ProcessHeap,
1629 0,
1630 BufferSize + sizeof(REGP_DEL_KEYS));
1631 if (newDelKeys != NULL)
1632 {
1633 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1634
1635 /* try again */
1636 goto ReadFirstSubKey;
1637 }
1638 else
1639 {
1640 /* don't break, let's try to delete as many keys as possible */
1641 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1642 goto SubKeyFailureNoFree;
1643 }
1644 }
1645 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1646 {
1647 PREG_DEL_KEYS newDelKeys2;
1648
1649 ASSERT(newDelKeys != NULL);
1650
1651 /* we need more memory to query the key name */
1652 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1653 0,
1654 newDelKeys,
1655 BufferSize + sizeof(REGP_DEL_KEYS));
1656 if (newDelKeys2 != NULL)
1657 {
1658 newDelKeys = newDelKeys2;
1659 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1660
1661 /* try again */
1662 goto ReadFirstSubKey;
1663 }
1664 else
1665 {
1666 /* don't break, let's try to delete as many keys as possible */
1667 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1668 }
1669 }
1670 else if (Status2 == STATUS_NO_MORE_ENTRIES)
1671 {
1672 /* in some race conditions where another thread would delete
1673 the same tree at the same time, newDelKeys could actually
1674 be != NULL! */
1675 if (newDelKeys != NULL)
1676 {
1677 RtlFreeHeap(ProcessHeap,
1678 0,
1679 newDelKeys);
1680 }
1681 break;
1682 }
1683
1684 SubKeyFailure:
1685 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1686 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1687 if (newDelKeys != NULL)
1688 {
1689 RtlFreeHeap(ProcessHeap,
1690 0,
1691 newDelKeys);
1692 }
1693
1694 SubKeyFailureNoFree:
1695 /* don't break, let's try to delete as many keys as possible */
1696 if (NT_SUCCESS(Status))
1697 {
1698 Status = Status2;
1699 }
1700 }
1701
1702 Status2 = NtDeleteKey(delKeys->KeyHandle);
1703
1704 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1705
1706 if (!NT_SUCCESS(Status2))
1707 {
1708 /* close the key handle so we don't leak handles for keys we were
1709 unable to delete. But only do this for handles not supplied
1710 by the caller! */
1711
1712 if (delKeys->KeyHandle != hKey)
1713 {
1714 NtClose(delKeys->KeyHandle);
1715 }
1716
1717 if (NT_SUCCESS(Status))
1718 {
1719 /* don't break, let's try to delete as many keys as possible */
1720 Status = Status2;
1721 }
1722 }
1723
1724 /* remove the entry from the list */
1725 RemoveEntryList(&delKeys->ListEntry);
1726
1727 RtlFreeHeap(ProcessHeap,
1728 0,
1729 delKeys);
1730 } while (!IsListEmpty(&delQueueHead));
1731 }
1732 else
1733 Status = STATUS_INSUFFICIENT_RESOURCES;
1734
1735 return Status;
1736 }
1737
1738
1739 /************************************************************************
1740 * RegDeleteTreeW
1741 *
1742 * @implemented
1743 */
1744 LONG WINAPI
1745 RegDeleteTreeW(IN HKEY hKey,
1746 IN LPCWSTR lpSubKey OPTIONAL)
1747 {
1748 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1749 NTSTATUS Status;
1750
1751 Status = MapDefaultKey(&KeyHandle,
1752 hKey);
1753 if (!NT_SUCCESS(Status))
1754 {
1755 return RtlNtStatusToDosError(Status);
1756 }
1757
1758 if (lpSubKey != NULL)
1759 {
1760 OBJECT_ATTRIBUTES ObjectAttributes;
1761 UNICODE_STRING SubKeyName;
1762
1763 RtlInitUnicodeString(&SubKeyName,
1764 (LPWSTR)lpSubKey);
1765
1766 InitializeObjectAttributes(&ObjectAttributes,
1767 &SubKeyName,
1768 OBJ_CASE_INSENSITIVE,
1769 KeyHandle,
1770 NULL);
1771
1772 Status = NtOpenKey(&SubKeyHandle,
1773 DELETE | KEY_ENUMERATE_SUB_KEYS,
1774 &ObjectAttributes);
1775 if (!NT_SUCCESS(Status))
1776 {
1777 goto Cleanup;
1778 }
1779
1780 CurKey = SubKeyHandle;
1781 }
1782 else
1783 CurKey = KeyHandle;
1784
1785 Status = RegpDeleteTree(CurKey);
1786
1787 if (NT_SUCCESS(Status))
1788 {
1789 /* make sure we only close hKey (KeyHandle) when the caller specified a
1790 subkey, because the handle would be invalid already! */
1791 if (CurKey != KeyHandle)
1792 {
1793 ClosePredefKey(KeyHandle);
1794 }
1795
1796 return ERROR_SUCCESS;
1797 }
1798 else
1799 {
1800 /* make sure we close all handles we created! */
1801 if (SubKeyHandle != NULL)
1802 {
1803 NtClose(SubKeyHandle);
1804 }
1805
1806 Cleanup:
1807 ClosePredefKey(KeyHandle);
1808
1809 return RtlNtStatusToDosError(Status);
1810 }
1811 }
1812 #endif
1813
1814
1815 /************************************************************************
1816 * RegDeleteTreeW
1817 *
1818 * @implemented
1819 */
1820 LSTATUS
1821 WINAPI
1822 RegDeleteTreeW(HKEY hKey,
1823 LPCWSTR lpszSubKey)
1824 {
1825 LONG ret;
1826 DWORD dwMaxSubkeyLen, dwMaxValueLen;
1827 DWORD dwMaxLen, dwSize;
1828 NTSTATUS Status;
1829 HANDLE KeyHandle;
1830 HKEY hSubKey;
1831 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1832
1833 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
1834
1835 Status = MapDefaultKey(&KeyHandle,
1836 hKey);
1837 if (!NT_SUCCESS(Status))
1838 {
1839 return RtlNtStatusToDosError(Status);
1840 }
1841
1842 hSubKey = KeyHandle;
1843
1844 if(lpszSubKey)
1845 {
1846 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
1847 if (ret)
1848 {
1849 ClosePredefKey(KeyHandle);
1850 return ret;
1851 }
1852 }
1853
1854 /* Get highest length for keys, values */
1855 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1856 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
1857 if (ret) goto cleanup;
1858
1859 dwMaxSubkeyLen++;
1860 dwMaxValueLen++;
1861 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
1862 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
1863 {
1864 /* Name too big: alloc a buffer for it */
1865 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
1866 {
1867 ret = ERROR_NOT_ENOUGH_MEMORY;
1868 goto cleanup;
1869 }
1870 }
1871
1872
1873 /* Recursively delete all the subkeys */
1874 while (TRUE)
1875 {
1876 dwSize = dwMaxLen;
1877 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
1878 NULL, NULL, NULL)) break;
1879
1880 ret = RegDeleteTreeW(hSubKey, lpszName);
1881 if (ret) goto cleanup;
1882 }
1883
1884 if (lpszSubKey)
1885 ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
1886 else
1887 while (TRUE)
1888 {
1889 dwSize = dwMaxLen;
1890 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
1891 NULL, NULL, NULL, NULL)) break;
1892
1893 ret = RegDeleteValueW(KeyHandle, lpszName);
1894 if (ret) goto cleanup;
1895 }
1896
1897 cleanup:
1898 /* Free buffer if allocated */
1899 if (lpszName != szNameBuf)
1900 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
1901 if(lpszSubKey)
1902 RegCloseKey(hSubKey);
1903
1904 ClosePredefKey(KeyHandle);
1905
1906 return ret;
1907 }
1908
1909
1910 /************************************************************************
1911 * RegDeleteTreeA
1912 *
1913 * @implemented
1914 */
1915 LONG WINAPI
1916 RegDeleteTreeA(IN HKEY hKey,
1917 IN LPCSTR lpSubKey OPTIONAL)
1918 {
1919 UNICODE_STRING SubKeyName = { 0, 0, NULL };
1920 LONG Ret;
1921
1922 if (lpSubKey != NULL &&
1923 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1924 (LPSTR)lpSubKey))
1925 {
1926 return ERROR_NOT_ENOUGH_MEMORY;
1927 }
1928
1929 Ret = RegDeleteTreeW(hKey,
1930 SubKeyName.Buffer);
1931
1932 RtlFreeUnicodeString(&SubKeyName);
1933
1934 return Ret;
1935 }
1936
1937
1938 /************************************************************************
1939 * RegDisableReflectionKey
1940 *
1941 * @unimplemented
1942 */
1943 LONG WINAPI
1944 RegDisableReflectionKey(IN HKEY hBase)
1945 {
1946 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1947 return ERROR_CALL_NOT_IMPLEMENTED;
1948 }
1949
1950
1951 /************************************************************************
1952 * RegEnableReflectionKey
1953 *
1954 * @unimplemented
1955 */
1956 LONG WINAPI
1957 RegEnableReflectionKey(IN HKEY hBase)
1958 {
1959 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1960 return ERROR_CALL_NOT_IMPLEMENTED;
1961 }
1962
1963
1964 /******************************************************************************
1965 * RegpApplyRestrictions [internal]
1966 *
1967 * Helper function for RegGetValueA/W.
1968 */
1969 static VOID
1970 RegpApplyRestrictions(DWORD dwFlags,
1971 DWORD dwType,
1972 DWORD cbData,
1973 PLONG ret)
1974 {
1975 /* Check if the type is restricted by the passed flags */
1976 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1977 {
1978 DWORD dwMask = 0;
1979
1980 switch (dwType)
1981 {
1982 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1983 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1984 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1985 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1986 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1987 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1988 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1989 }
1990
1991 if (dwFlags & dwMask)
1992 {
1993 /* Type is not restricted, check for size mismatch */
1994 if (dwType == REG_BINARY)
1995 {
1996 DWORD cbExpect = 0;
1997
1998 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1999 cbExpect = 4;
2000 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
2001 cbExpect = 8;
2002
2003 if (cbExpect && cbData != cbExpect)
2004 *ret = ERROR_DATATYPE_MISMATCH;
2005 }
2006 }
2007 else *ret = ERROR_UNSUPPORTED_TYPE;
2008 }
2009 }
2010
2011
2012 /******************************************************************************
2013 * RegGetValueW [ADVAPI32.@]
2014 *
2015 * Retrieves the type and data for a value name associated with a key,
2016 * optionally expanding its content and restricting its type.
2017 *
2018 * PARAMS
2019 * hKey [I] Handle to an open key.
2020 * pszSubKey [I] Name of the subkey of hKey.
2021 * pszValue [I] Name of value under hKey/szSubKey to query.
2022 * dwFlags [I] Flags restricting the value type to retrieve.
2023 * pdwType [O] Destination for the values type, may be NULL.
2024 * pvData [O] Destination for the values content, may be NULL.
2025 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2026 * retrieve the whole content, including the trailing '\0'
2027 * for strings.
2028 *
2029 * RETURNS
2030 * Success: ERROR_SUCCESS
2031 * Failure: nonzero error code from Winerror.h
2032 *
2033 * NOTES
2034 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2035 * expanded and pdwType is set to REG_SZ instead.
2036 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2037 * without RRF_NOEXPAND is thus not allowed.
2038 * An exception is the case where RRF_RT_ANY is specified, because then
2039 * RRF_NOEXPAND is allowed.
2040 */
2041 LSTATUS WINAPI
2042 RegGetValueW(HKEY hKey,
2043 LPCWSTR pszSubKey,
2044 LPCWSTR pszValue,
2045 DWORD dwFlags,
2046 LPDWORD pdwType,
2047 PVOID pvData,
2048 LPDWORD pcbData)
2049 {
2050 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2051 PVOID pvBuf = NULL;
2052 LONG ret;
2053
2054 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2055 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
2056 pvData, pcbData, cbData);
2057
2058 if (pvData && !pcbData)
2059 return ERROR_INVALID_PARAMETER;
2060 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2061 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2062 return ERROR_INVALID_PARAMETER;
2063
2064 if (pszSubKey && pszSubKey[0])
2065 {
2066 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2067 if (ret != ERROR_SUCCESS) return ret;
2068 }
2069
2070 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2071
2072 /* If we are going to expand we need to read in the whole the value even
2073 * if the passed buffer was too small as the expanded string might be
2074 * smaller than the unexpanded one and could fit into cbData bytes. */
2075 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2076 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
2077 {
2078 do
2079 {
2080 HeapFree(GetProcessHeap(), 0, pvBuf);
2081
2082 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2083 if (!pvBuf)
2084 {
2085 ret = ERROR_NOT_ENOUGH_MEMORY;
2086 break;
2087 }
2088
2089 if (ret == ERROR_MORE_DATA || !pvData)
2090 ret = RegQueryValueExW(hKey, pszValue, NULL,
2091 &dwType, pvBuf, &cbData);
2092 else
2093 {
2094 /* Even if cbData was large enough we have to copy the
2095 * string since ExpandEnvironmentStrings can't handle
2096 * overlapping buffers. */
2097 CopyMemory(pvBuf, pvData, cbData);
2098 }
2099
2100 /* Both the type or the value itself could have been modified in
2101 * between so we have to keep retrying until the buffer is large
2102 * enough or we no longer have to expand the value. */
2103 }
2104 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2105
2106 if (ret == ERROR_SUCCESS)
2107 {
2108 /* Recheck dwType in case it changed since the first call */
2109 if (dwType == REG_EXPAND_SZ)
2110 {
2111 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2112 pcbData ? *pcbData : 0) * sizeof(WCHAR);
2113 dwType = REG_SZ;
2114 if (pvData && pcbData && cbData > *pcbData)
2115 ret = ERROR_MORE_DATA;
2116 }
2117 else if (pvData)
2118 CopyMemory(pvData, pvBuf, *pcbData);
2119 }
2120
2121 HeapFree(GetProcessHeap(), 0, pvBuf);
2122 }
2123
2124 if (pszSubKey && pszSubKey[0])
2125 RegCloseKey(hKey);
2126
2127 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2128
2129 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2130 ZeroMemory(pvData, *pcbData);
2131
2132 if (pdwType)
2133 *pdwType = dwType;
2134
2135 if (pcbData)
2136 *pcbData = cbData;
2137
2138 return ret;
2139 }
2140
2141
2142 /******************************************************************************
2143 * RegGetValueA [ADVAPI32.@]
2144 *
2145 * See RegGetValueW.
2146 */
2147 LSTATUS WINAPI
2148 RegGetValueA(HKEY hKey,
2149 LPCSTR pszSubKey,
2150 LPCSTR pszValue,
2151 DWORD dwFlags,
2152 LPDWORD pdwType,
2153 PVOID pvData,
2154 LPDWORD pcbData)
2155 {
2156 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2157 PVOID pvBuf = NULL;
2158 LONG ret;
2159
2160 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2161 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2162 cbData);
2163
2164 if (pvData && !pcbData)
2165 return ERROR_INVALID_PARAMETER;
2166 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2167 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2168 return ERROR_INVALID_PARAMETER;
2169
2170 if (pszSubKey && pszSubKey[0])
2171 {
2172 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2173 if (ret != ERROR_SUCCESS) return ret;
2174 }
2175
2176 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2177
2178 /* If we are going to expand we need to read in the whole the value even
2179 * if the passed buffer was too small as the expanded string might be
2180 * smaller than the unexpanded one and could fit into cbData bytes. */
2181 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2182 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2183 {
2184 do {
2185 HeapFree(GetProcessHeap(), 0, pvBuf);
2186
2187 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2188 if (!pvBuf)
2189 {
2190 ret = ERROR_NOT_ENOUGH_MEMORY;
2191 break;
2192 }
2193
2194 if (ret == ERROR_MORE_DATA || !pvData)
2195 ret = RegQueryValueExA(hKey, pszValue, NULL,
2196 &dwType, pvBuf, &cbData);
2197 else
2198 {
2199 /* Even if cbData was large enough we have to copy the
2200 * string since ExpandEnvironmentStrings can't handle
2201 * overlapping buffers. */
2202 CopyMemory(pvBuf, pvData, cbData);
2203 }
2204
2205 /* Both the type or the value itself could have been modified in
2206 * between so we have to keep retrying until the buffer is large
2207 * enough or we no longer have to expand the value. */
2208 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2209
2210 if (ret == ERROR_SUCCESS)
2211 {
2212 /* Recheck dwType in case it changed since the first call */
2213 if (dwType == REG_EXPAND_SZ)
2214 {
2215 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2216 pcbData ? *pcbData : 0);
2217 dwType = REG_SZ;
2218 if(pvData && pcbData && cbData > *pcbData)
2219 ret = ERROR_MORE_DATA;
2220 }
2221 else if (pvData)
2222 CopyMemory(pvData, pvBuf, *pcbData);
2223 }
2224
2225 HeapFree(GetProcessHeap(), 0, pvBuf);
2226 }
2227
2228 if (pszSubKey && pszSubKey[0])
2229 RegCloseKey(hKey);
2230
2231 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2232
2233 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2234 ZeroMemory(pvData, *pcbData);
2235
2236 if (pdwType) *pdwType = dwType;
2237 if (pcbData) *pcbData = cbData;
2238
2239 return ret;
2240 }
2241
2242
2243 /************************************************************************
2244 * RegSetKeyValueW
2245 *
2246 * @implemented
2247 */
2248 LONG WINAPI
2249 RegSetKeyValueW(IN HKEY hKey,
2250 IN LPCWSTR lpSubKey OPTIONAL,
2251 IN LPCWSTR lpValueName OPTIONAL,
2252 IN DWORD dwType,
2253 IN LPCVOID lpData OPTIONAL,
2254 IN DWORD cbData)
2255 {
2256 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2257 NTSTATUS Status;
2258 LONG Ret;
2259
2260 Status = MapDefaultKey(&KeyHandle,
2261 hKey);
2262 if (!NT_SUCCESS(Status))
2263 {
2264 return RtlNtStatusToDosError(Status);
2265 }
2266
2267 if (lpSubKey != NULL)
2268 {
2269 OBJECT_ATTRIBUTES ObjectAttributes;
2270 UNICODE_STRING SubKeyName;
2271
2272 RtlInitUnicodeString(&SubKeyName,
2273 (LPWSTR)lpSubKey);
2274
2275 InitializeObjectAttributes(&ObjectAttributes,
2276 &SubKeyName,
2277 OBJ_CASE_INSENSITIVE,
2278 KeyHandle,
2279 NULL);
2280
2281 Status = NtOpenKey(&SubKeyHandle,
2282 KEY_SET_VALUE,
2283 &ObjectAttributes);
2284 if (!NT_SUCCESS(Status))
2285 {
2286 Ret = RtlNtStatusToDosError(Status);
2287 goto Cleanup;
2288 }
2289
2290 CurKey = SubKeyHandle;
2291 }
2292 else
2293 CurKey = KeyHandle;
2294
2295 Ret = RegSetValueExW(CurKey,
2296 lpValueName,
2297 0,
2298 dwType,
2299 lpData,
2300 cbData);
2301
2302 if (SubKeyHandle != NULL)
2303 {
2304 NtClose(SubKeyHandle);
2305 }
2306
2307 Cleanup:
2308 ClosePredefKey(KeyHandle);
2309
2310 return Ret;
2311 }
2312
2313
2314 /************************************************************************
2315 * RegSetKeyValueA
2316 *
2317 * @implemented
2318 */
2319 LONG WINAPI
2320 RegSetKeyValueA(IN HKEY hKey,
2321 IN LPCSTR lpSubKey OPTIONAL,
2322 IN LPCSTR lpValueName OPTIONAL,
2323 IN DWORD dwType,
2324 IN LPCVOID lpData OPTIONAL,
2325 IN DWORD cbData)
2326 {
2327 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2328 NTSTATUS Status;
2329 LONG Ret;
2330
2331 Status = MapDefaultKey(&KeyHandle,
2332 hKey);
2333 if (!NT_SUCCESS(Status))
2334 {
2335 return RtlNtStatusToDosError(Status);
2336 }
2337
2338 if (lpSubKey != NULL)
2339 {
2340 OBJECT_ATTRIBUTES ObjectAttributes;
2341 UNICODE_STRING SubKeyName;
2342
2343 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
2344 (LPSTR)lpSubKey))
2345 {
2346 Ret = ERROR_NOT_ENOUGH_MEMORY;
2347 goto Cleanup;
2348 }
2349
2350 InitializeObjectAttributes(&ObjectAttributes,
2351 &SubKeyName,
2352 OBJ_CASE_INSENSITIVE,
2353 KeyHandle,
2354 NULL);
2355
2356 Status = NtOpenKey(&SubKeyHandle,
2357 KEY_SET_VALUE,
2358 &ObjectAttributes);
2359
2360 RtlFreeUnicodeString(&SubKeyName);
2361
2362 if (!NT_SUCCESS(Status))
2363 {
2364 Ret = RtlNtStatusToDosError(Status);
2365 goto Cleanup;
2366 }
2367
2368 CurKey = SubKeyHandle;
2369 }
2370 else
2371 CurKey = KeyHandle;
2372
2373 Ret = RegSetValueExA(CurKey,
2374 lpValueName,
2375 0,
2376 dwType,
2377 lpData,
2378 cbData);
2379
2380 if (SubKeyHandle != NULL)
2381 {
2382 NtClose(SubKeyHandle);
2383 }
2384
2385 Cleanup:
2386 ClosePredefKey(KeyHandle);
2387
2388 return Ret;
2389 }
2390
2391
2392 /************************************************************************
2393 * RegDeleteValueA
2394 *
2395 * @implemented
2396 */
2397 LONG WINAPI
2398 RegDeleteValueA(HKEY hKey,
2399 LPCSTR lpValueName)
2400 {
2401 UNICODE_STRING ValueName;
2402 HANDLE KeyHandle;
2403 NTSTATUS Status;
2404
2405 Status = MapDefaultKey(&KeyHandle,
2406 hKey);
2407 if (!NT_SUCCESS(Status))
2408 {
2409 return RtlNtStatusToDosError(Status);
2410 }
2411
2412 RtlCreateUnicodeStringFromAsciiz(&ValueName,
2413 (LPSTR)lpValueName);
2414 Status = NtDeleteValueKey(KeyHandle,
2415 &ValueName);
2416 RtlFreeUnicodeString (&ValueName);
2417
2418 ClosePredefKey(KeyHandle);
2419
2420 if (!NT_SUCCESS(Status))
2421 {
2422 return RtlNtStatusToDosError(Status);
2423 }
2424
2425 return ERROR_SUCCESS;
2426 }
2427
2428
2429 /************************************************************************
2430 * RegDeleteValueW
2431 *
2432 * @implemented
2433 */
2434 LONG WINAPI
2435 RegDeleteValueW(HKEY hKey,
2436 LPCWSTR lpValueName)
2437 {
2438 UNICODE_STRING ValueName;
2439 NTSTATUS Status;
2440 HANDLE KeyHandle;
2441
2442 Status = MapDefaultKey(&KeyHandle,
2443 hKey);
2444 if (!NT_SUCCESS(Status))
2445 {
2446 return RtlNtStatusToDosError(Status);
2447 }
2448
2449 RtlInitUnicodeString(&ValueName,
2450 (LPWSTR)lpValueName);
2451
2452 Status = NtDeleteValueKey(KeyHandle,
2453 &ValueName);
2454
2455 ClosePredefKey(KeyHandle);
2456
2457 if (!NT_SUCCESS(Status))
2458 {
2459 return RtlNtStatusToDosError(Status);
2460 }
2461
2462 return ERROR_SUCCESS;
2463 }
2464
2465
2466 /************************************************************************
2467 * RegEnumKeyA
2468 *
2469 * @implemented
2470 */
2471 LONG WINAPI
2472 RegEnumKeyA(HKEY hKey,
2473 DWORD dwIndex,
2474 LPSTR lpName,
2475 DWORD cbName)
2476 {
2477 DWORD dwLength;
2478
2479 dwLength = cbName;
2480 return RegEnumKeyExA(hKey,
2481 dwIndex,
2482 lpName,
2483 &dwLength,
2484 NULL,
2485 NULL,
2486 NULL,
2487 NULL);
2488 }
2489
2490
2491 /************************************************************************
2492 * RegEnumKeyW
2493 *
2494 * @implemented
2495 */
2496 LONG WINAPI
2497 RegEnumKeyW(HKEY hKey,
2498 DWORD dwIndex,
2499 LPWSTR lpName,
2500 DWORD cbName)
2501 {
2502 DWORD dwLength;
2503
2504 dwLength = cbName;
2505 return RegEnumKeyExW(hKey,
2506 dwIndex,
2507 lpName,
2508 &dwLength,
2509 NULL,
2510 NULL,
2511 NULL,
2512 NULL);
2513 }
2514
2515
2516 /************************************************************************
2517 * RegEnumKeyExA
2518 *
2519 * @implemented
2520 */
2521 LONG WINAPI
2522 RegEnumKeyExA(HKEY hKey,
2523 DWORD dwIndex,
2524 LPSTR lpName,
2525 LPDWORD lpcbName,
2526 LPDWORD lpReserved,
2527 LPSTR lpClass,
2528 LPDWORD lpcbClass,
2529 PFILETIME lpftLastWriteTime)
2530 {
2531 union
2532 {
2533 KEY_NODE_INFORMATION Node;
2534 KEY_BASIC_INFORMATION Basic;
2535 } *KeyInfo;
2536
2537 UNICODE_STRING StringU;
2538 ANSI_STRING StringA;
2539 LONG ErrorCode = ERROR_SUCCESS;
2540 DWORD NameLength;
2541 DWORD ClassLength = 0;
2542 DWORD BufferSize;
2543 ULONG ResultSize;
2544 HANDLE KeyHandle;
2545 NTSTATUS Status;
2546
2547 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2548 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
2549
2550 if ((lpClass) && (!lpcbClass))
2551 {
2552 return ERROR_INVALID_PARAMETER;
2553 }
2554
2555 Status = MapDefaultKey(&KeyHandle, hKey);
2556 if (!NT_SUCCESS(Status))
2557 {
2558 return RtlNtStatusToDosError(Status);
2559 }
2560
2561 if (*lpcbName > 0)
2562 {
2563 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2564 }
2565 else
2566 {
2567 NameLength = 0;
2568 }
2569
2570 if (lpClass)
2571 {
2572 if (*lpcbClass > 0)
2573 {
2574 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2575 }
2576 else
2577 {
2578 ClassLength = 0;
2579 }
2580
2581 /* The class name should start at a dword boundary */
2582 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2583 }
2584 else
2585 {
2586 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2587 }
2588
2589 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
2590 if (KeyInfo == NULL)
2591 {
2592 ErrorCode = ERROR_OUTOFMEMORY;
2593 goto Cleanup;
2594 }
2595
2596 Status = NtEnumerateKey(KeyHandle,
2597 (ULONG)dwIndex,
2598 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
2599 KeyInfo,
2600 BufferSize,
2601 &ResultSize);
2602 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2603 if (!NT_SUCCESS(Status))
2604 {
2605 ErrorCode = RtlNtStatusToDosError (Status);
2606 }
2607 else
2608 {
2609 if (lpClass == NULL)
2610 {
2611 if (KeyInfo->Basic.NameLength > NameLength)
2612 {
2613 ErrorCode = ERROR_BUFFER_OVERFLOW;
2614 }
2615 else
2616 {
2617 StringU.Buffer = KeyInfo->Basic.Name;
2618 StringU.Length = KeyInfo->Basic.NameLength;
2619 StringU.MaximumLength = KeyInfo->Basic.NameLength;
2620 }
2621 }
2622 else
2623 {
2624 if (KeyInfo->Node.NameLength > NameLength ||
2625 KeyInfo->Node.ClassLength > ClassLength)
2626 {
2627 ErrorCode = ERROR_BUFFER_OVERFLOW;
2628 }
2629 else
2630 {
2631 StringA.Buffer = lpClass;
2632 StringA.Length = 0;
2633 StringA.MaximumLength = *lpcbClass;
2634 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
2635 StringU.Length = KeyInfo->Node.ClassLength;
2636 StringU.MaximumLength = KeyInfo->Node.ClassLength;
2637 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2638 lpClass[StringA.Length] = 0;
2639 *lpcbClass = StringA.Length;
2640 StringU.Buffer = KeyInfo->Node.Name;
2641 StringU.Length = KeyInfo->Node.NameLength;
2642 StringU.MaximumLength = KeyInfo->Node.NameLength;
2643 }
2644 }
2645
2646 if (ErrorCode == ERROR_SUCCESS)
2647 {
2648 StringA.Buffer = lpName;
2649 StringA.Length = 0;
2650 StringA.MaximumLength = *lpcbName;
2651 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2652 lpName[StringA.Length] = 0;
2653 *lpcbName = StringA.Length;
2654 if (lpftLastWriteTime != NULL)
2655 {
2656 if (lpClass == NULL)
2657 {
2658 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2659 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2660 }
2661 else
2662 {
2663 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2664 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2665 }
2666 }
2667 }
2668 }
2669
2670 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2671 TRACE("Key Name1 Length %d\n", NameLength);
2672 TRACE("Key Name Length %d\n", *lpcbName);
2673 TRACE("Key Name %s\n", lpName);
2674
2675 RtlFreeHeap(ProcessHeap,
2676 0,
2677 KeyInfo);
2678
2679 Cleanup:
2680 ClosePredefKey(KeyHandle);
2681
2682 return ErrorCode;
2683 }
2684
2685
2686 /************************************************************************
2687 * RegEnumKeyExW
2688 *
2689 * @implemented
2690 */
2691 LONG WINAPI
2692 RegEnumKeyExW(HKEY hKey,
2693 DWORD dwIndex,
2694 LPWSTR lpName,
2695 LPDWORD lpcbName,
2696 LPDWORD lpReserved,
2697 LPWSTR lpClass,
2698 LPDWORD lpcbClass,
2699 PFILETIME lpftLastWriteTime)
2700 {
2701 union
2702 {
2703 KEY_NODE_INFORMATION Node;
2704 KEY_BASIC_INFORMATION Basic;
2705 } *KeyInfo;
2706
2707 ULONG BufferSize;
2708 ULONG ResultSize;
2709 ULONG NameLength;
2710 ULONG ClassLength = 0;
2711 HANDLE KeyHandle;
2712 LONG ErrorCode = ERROR_SUCCESS;
2713 NTSTATUS Status;
2714
2715 Status = MapDefaultKey(&KeyHandle,
2716 hKey);
2717 if (!NT_SUCCESS(Status))
2718 {
2719 return RtlNtStatusToDosError(Status);
2720 }
2721
2722 if (*lpcbName > 0)
2723 {
2724 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2725 }
2726 else
2727 {
2728 NameLength = 0;
2729 }
2730
2731 if (lpClass)
2732 {
2733 if (*lpcbClass > 0)
2734 {
2735 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2736 }
2737 else
2738 {
2739 ClassLength = 0;
2740 }
2741
2742 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2743 }
2744 else
2745 {
2746 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2747 }
2748
2749 KeyInfo = RtlAllocateHeap(ProcessHeap,
2750 0,
2751 BufferSize);
2752 if (KeyInfo == NULL)
2753 {
2754 ErrorCode = ERROR_OUTOFMEMORY;
2755 goto Cleanup;
2756 }
2757
2758 Status = NtEnumerateKey(KeyHandle,
2759 (ULONG)dwIndex,
2760 lpClass ? KeyNodeInformation : KeyBasicInformation,
2761 KeyInfo,
2762 BufferSize,
2763 &ResultSize);
2764 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2765 if (!NT_SUCCESS(Status))
2766 {
2767 ErrorCode = RtlNtStatusToDosError (Status);
2768 }
2769 else
2770 {
2771 if (lpClass == NULL)
2772 {
2773 if (KeyInfo->Basic.NameLength > NameLength)
2774 {
2775 ErrorCode = ERROR_BUFFER_OVERFLOW;
2776 }
2777 else
2778 {
2779 RtlCopyMemory(lpName,
2780 KeyInfo->Basic.Name,
2781 KeyInfo->Basic.NameLength);
2782 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2783 lpName[*lpcbName] = 0;
2784 }
2785 }
2786 else
2787 {
2788 if (KeyInfo->Node.NameLength > NameLength ||
2789 KeyInfo->Node.ClassLength > ClassLength)
2790 {
2791 ErrorCode = ERROR_BUFFER_OVERFLOW;
2792 }
2793 else
2794 {
2795 RtlCopyMemory(lpName,
2796 KeyInfo->Node.Name,
2797 KeyInfo->Node.NameLength);
2798 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2799 lpName[*lpcbName] = 0;
2800 RtlCopyMemory(lpClass,
2801 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2802 KeyInfo->Node.ClassLength);
2803 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2804 lpClass[*lpcbClass] = 0;
2805 }
2806 }
2807
2808 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2809 {
2810 if (lpClass == NULL)
2811 {
2812 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2813 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2814 }
2815 else
2816 {
2817 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2818 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2819 }
2820 }
2821 }
2822
2823 RtlFreeHeap(ProcessHeap,
2824 0,
2825 KeyInfo);
2826
2827 Cleanup:
2828 ClosePredefKey(KeyHandle);
2829
2830 return ErrorCode;
2831 }
2832
2833
2834 /************************************************************************
2835 * RegEnumValueA
2836 *
2837 * @implemented
2838 */
2839 LONG WINAPI
2840 RegEnumValueA(HKEY hKey,
2841 DWORD index,
2842 LPSTR value,
2843 LPDWORD val_count,
2844 LPDWORD reserved,
2845 LPDWORD type,
2846 LPBYTE data,
2847 LPDWORD count)
2848 {
2849 HANDLE KeyHandle;
2850 NTSTATUS status;
2851 ULONG total_size;
2852 char buffer[256], *buf_ptr = buffer;
2853 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2854 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2855
2856 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2857 // hkey, index, value, val_count, reserved, type, data, count );
2858
2859 /* NT only checks count, not val_count */
2860 if ((data && !count) || reserved)
2861 return ERROR_INVALID_PARAMETER;
2862
2863 status = MapDefaultKey(&KeyHandle, hKey);
2864 if (!NT_SUCCESS(status))
2865 {
2866 return RtlNtStatusToDosError(status);
2867 }
2868
2869 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2870 if (data) total_size += *count;
2871 total_size = min( sizeof(buffer), total_size );
2872
2873 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2874 buffer, total_size, &total_size );
2875 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
2876
2877 /* we need to fetch the contents for a string type even if not requested,
2878 * because we need to compute the length of the ASCII string. */
2879 if (value || data || is_string(info->Type))
2880 {
2881 /* retry with a dynamically allocated buffer */
2882 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
2883 {
2884 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2885 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2886 {
2887 status = STATUS_INSUFFICIENT_RESOURCES;
2888 goto done;
2889 }
2890 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2891 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2892 buf_ptr, total_size, &total_size );
2893 }
2894
2895 if (status) goto done;
2896
2897 if (is_string(info->Type))
2898 {
2899 ULONG len;
2900 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2901 info->DataLength );
2902 if (data && len)
2903 {
2904 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2905 else
2906 {
2907 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2908 info->DataLength );
2909 /* if the type is REG_SZ and data is not 0-terminated
2910 * and there is enough space in the buffer NT appends a \0 */
2911 if (len < *count && data[len-1]) data[len] = 0;
2912 }
2913 }
2914 info->DataLength = len;
2915 }
2916 else if (data)
2917 {
2918 if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
2919 else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
2920 }
2921
2922 if (value && !status)
2923 {
2924 ULONG len;
2925
2926 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2927 if (len >= *val_count)
2928 {
2929 status = STATUS_BUFFER_OVERFLOW;
2930 if (*val_count)
2931 {
2932 len = *val_count - 1;
2933 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2934 value[len] = 0;
2935 }
2936 }
2937 else
2938 {
2939 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2940 value[len] = 0;
2941 *val_count = len;
2942 }
2943 }
2944 }
2945 else status = STATUS_SUCCESS;
2946
2947 if (type) *type = info->Type;
2948 if (count) *count = info->DataLength;
2949
2950 done:
2951 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2952 ClosePredefKey(KeyHandle);
2953 return RtlNtStatusToDosError(status);
2954 }
2955
2956
2957 /******************************************************************************
2958 * RegEnumValueW [ADVAPI32.@]
2959 * @implemented
2960 *
2961 * PARAMS
2962 * hkey [I] Handle to key to query
2963 * index [I] Index of value to query
2964 * value [O] Value string
2965 * val_count [I/O] Size of value buffer (in wchars)
2966 * reserved [I] Reserved
2967 * type [O] Type code
2968 * data [O] Value data
2969 * count [I/O] Size of data buffer (in bytes)
2970 *
2971 * RETURNS
2972 * Success: ERROR_SUCCESS
2973 * Failure: nonzero error code from Winerror.h
2974 */
2975 LONG WINAPI
2976 RegEnumValueW(HKEY hKey,
2977 DWORD index,
2978 LPWSTR value,
2979 PDWORD val_count,
2980 PDWORD reserved,
2981 PDWORD type,
2982 LPBYTE data,
2983 PDWORD count)
2984 {
2985 HANDLE KeyHandle;
2986 NTSTATUS status;
2987 ULONG total_size;
2988 char buffer[256], *buf_ptr = buffer;
2989 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2990 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2991
2992 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2993 // hkey, index, value, val_count, reserved, type, data, count );
2994
2995 /* NT only checks count, not val_count */
2996 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2997
2998 status = MapDefaultKey(&KeyHandle, hKey);
2999 if (!NT_SUCCESS(status))
3000 {
3001 return RtlNtStatusToDosError(status);
3002 }
3003
3004 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
3005 if (data) total_size += *count;
3006 total_size = min( sizeof(buffer), total_size );
3007
3008 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
3009 buffer, total_size, &total_size );
3010 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
3011
3012 if (value || data)
3013 {
3014 /* retry with a dynamically allocated buffer */
3015 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
3016 {
3017 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
3018 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
3019 {
3020 status = ERROR_NOT_ENOUGH_MEMORY;
3021 goto done;
3022 }
3023 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
3024 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
3025 buf_ptr, total_size, &total_size );
3026 }
3027
3028 if (status) goto done;
3029
3030 if (value)
3031 {
3032 if (info->NameLength/sizeof(WCHAR) >= *val_count)
3033 {
3034 status = STATUS_BUFFER_OVERFLOW;
3035 goto overflow;
3036 }
3037 memcpy( value, info->Name, info->NameLength );
3038 *val_count = info->NameLength / sizeof(WCHAR);
3039 value[*val_count] = 0;
3040 }
3041
3042 if (data)
3043 {
3044 if (info->DataLength > *count)
3045 {
3046 status = STATUS_BUFFER_OVERFLOW;
3047 goto overflow;
3048 }
3049 memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
3050 if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
3051 {
3052 /* if the type is REG_SZ and data is not 0-terminated
3053 * and there is enough space in the buffer NT appends a \0 */
3054 WCHAR *ptr = (WCHAR *)(data + info->DataLength);
3055 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
3056 }
3057 }
3058 }
3059 else status = STATUS_SUCCESS;
3060
3061 overflow:
3062 if (type) *type = info->Type;
3063 if (count) *count = info->DataLength;
3064
3065 done:
3066 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
3067 ClosePredefKey(KeyHandle);
3068 return RtlNtStatusToDosError(status);
3069 }
3070
3071
3072 /************************************************************************
3073 * RegFlushKey
3074 *
3075 * @implemented
3076 */
3077 LONG WINAPI
3078 RegFlushKey(HKEY hKey)
3079 {
3080 HANDLE KeyHandle;
3081 NTSTATUS Status;
3082
3083 if (hKey == HKEY_PERFORMANCE_DATA)
3084 {
3085 return ERROR_SUCCESS;
3086 }
3087
3088 Status = MapDefaultKey(&KeyHandle,
3089 hKey);
3090 if (!NT_SUCCESS(Status))
3091 {
3092 return RtlNtStatusToDosError(Status);
3093 }
3094
3095 Status = NtFlushKey(KeyHandle);
3096
3097 ClosePredefKey(KeyHandle);
3098
3099 if (!NT_SUCCESS(Status))
3100 {
3101 return RtlNtStatusToDosError(Status);
3102 }
3103
3104 return ERROR_SUCCESS;
3105 }
3106
3107
3108 /************************************************************************
3109 * RegGetKeySecurity
3110 *
3111 * @implemented
3112 */
3113 LONG WINAPI
3114 RegGetKeySecurity(HKEY hKey,
3115 SECURITY_INFORMATION SecurityInformation,
3116 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3117 LPDWORD lpcbSecurityDescriptor)
3118 {
3119 HANDLE KeyHandle;
3120 NTSTATUS Status;
3121
3122 if (hKey == HKEY_PERFORMANCE_DATA)
3123 {
3124 return ERROR_INVALID_HANDLE;
3125 }
3126
3127 Status = MapDefaultKey(&KeyHandle,
3128 hKey);
3129 if (!NT_SUCCESS(Status))
3130 {
3131 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3132 return RtlNtStatusToDosError(Status);
3133 }
3134
3135 Status = NtQuerySecurityObject(KeyHandle,
3136 SecurityInformation,
3137 pSecurityDescriptor,
3138 *lpcbSecurityDescriptor,
3139 lpcbSecurityDescriptor);
3140
3141 ClosePredefKey(KeyHandle);
3142
3143 if (!NT_SUCCESS(Status))
3144 {
3145 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3146 return RtlNtStatusToDosError(Status);
3147 }
3148
3149 return ERROR_SUCCESS;
3150 }
3151
3152
3153 /************************************************************************
3154 * RegLoadKeyA
3155 *
3156 * @implemented
3157 */
3158 LONG WINAPI
3159 RegLoadKeyA(HKEY hKey,
3160 LPCSTR lpSubKey,
3161 LPCSTR lpFile)
3162 {
3163 UNICODE_STRING FileName;
3164 UNICODE_STRING KeyName;
3165 LONG ErrorCode;
3166
3167 RtlCreateUnicodeStringFromAsciiz(&KeyName,
3168 (LPSTR)lpSubKey);
3169 RtlCreateUnicodeStringFromAsciiz(&FileName,
3170 (LPSTR)lpFile);
3171
3172 ErrorCode = RegLoadKeyW(hKey,
3173 KeyName.Buffer,
3174 FileName.Buffer);
3175
3176 RtlFreeUnicodeString(&FileName);
3177 RtlFreeUnicodeString(&KeyName);
3178
3179 return ErrorCode;
3180 }
3181
3182
3183 /************************************************************************
3184 * RegLoadKeyW
3185 *
3186 * @implemented
3187 */
3188 LONG WINAPI
3189 RegLoadKeyW(HKEY hKey,
3190 LPCWSTR lpSubKey,
3191 LPCWSTR lpFile)
3192 {
3193 OBJECT_ATTRIBUTES FileObjectAttributes;
3194 OBJECT_ATTRIBUTES KeyObjectAttributes;
3195 UNICODE_STRING FileName;
3196 UNICODE_STRING KeyName;
3197 HANDLE KeyHandle;
3198 NTSTATUS Status;
3199 LONG ErrorCode = ERROR_SUCCESS;
3200
3201 if (hKey == HKEY_PERFORMANCE_DATA)
3202 {
3203 return ERROR_INVALID_HANDLE;
3204 }
3205
3206 Status = MapDefaultKey(&KeyHandle,
3207 hKey);
3208 if (!NT_SUCCESS(Status))
3209 {
3210 return RtlNtStatusToDosError(Status);
3211 }
3212
3213 if (!RtlDosPathNameToNtPathName_U(lpFile,
3214 &FileName,
3215 NULL,
3216 NULL))
3217 {
3218 ErrorCode = ERROR_BAD_PATHNAME;
3219 goto Cleanup;
3220 }
3221
3222 InitializeObjectAttributes(&FileObjectAttributes,
3223 &FileName,
3224 OBJ_CASE_INSENSITIVE,
3225 NULL,
3226 NULL);
3227
3228 RtlInitUnicodeString(&KeyName,
3229 (LPWSTR)lpSubKey);
3230
3231 InitializeObjectAttributes(&KeyObjectAttributes,
3232 &KeyName,
3233 OBJ_CASE_INSENSITIVE,
3234 KeyHandle,
3235 NULL);
3236
3237 Status = NtLoadKey(&KeyObjectAttributes,
3238 &FileObjectAttributes);
3239
3240 RtlFreeHeap(RtlGetProcessHeap(),
3241 0,
3242 FileName.Buffer);
3243
3244 if (!NT_SUCCESS(Status))
3245 {
3246 ErrorCode = RtlNtStatusToDosError(Status);
3247 goto Cleanup;
3248 }
3249
3250 Cleanup:
3251 ClosePredefKey(KeyHandle);
3252
3253 return ErrorCode;
3254 }
3255
3256
3257 /************************************************************************
3258 * RegNotifyChangeKeyValue
3259 *
3260 * @unimplemented
3261 */
3262 LONG WINAPI
3263 RegNotifyChangeKeyValue(HKEY hKey,
3264 BOOL bWatchSubtree,
3265 DWORD dwNotifyFilter,
3266 HANDLE hEvent,
3267 BOOL fAsynchronous)
3268 {
3269 IO_STATUS_BLOCK IoStatusBlock;
3270 HANDLE KeyHandle;
3271 NTSTATUS Status;
3272 LONG ErrorCode = ERROR_SUCCESS;
3273
3274 if (hKey == HKEY_PERFORMANCE_DATA)
3275 {
3276 return ERROR_INVALID_HANDLE;
3277 }
3278
3279 if (fAsynchronous == TRUE && hEvent == NULL)
3280 {
3281 return ERROR_INVALID_PARAMETER;
3282 }
3283
3284 Status = MapDefaultKey(&KeyHandle,
3285 hKey);
3286 if (!NT_SUCCESS(Status))
3287 {
3288 return RtlNtStatusToDosError(Status);
3289 }
3290
3291 /* FIXME: Remote key handles must fail */
3292
3293 Status = NtNotifyChangeKey(KeyHandle,
3294 hEvent,
3295 0,
3296 0,
3297 &IoStatusBlock,
3298 dwNotifyFilter,
3299 bWatchSubtree,
3300 0,
3301 0,
3302 fAsynchronous);
3303 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3304 {
3305 ErrorCode = RtlNtStatusToDosError(Status);
3306 }
3307
3308 ClosePredefKey(KeyHandle);
3309
3310 return ErrorCode;
3311 }
3312
3313
3314 /************************************************************************
3315 * RegOpenCurrentUser
3316 *
3317 * @implemented
3318 */
3319 LONG WINAPI
3320 RegOpenCurrentUser(IN REGSAM samDesired,
3321 OUT PHKEY phkResult)
3322 {
3323 NTSTATUS Status;
3324
3325 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3326 (PHANDLE)phkResult);
3327 if (!NT_SUCCESS(Status))
3328 {
3329 /* NOTE - don't set the last error code! just return the error! */
3330 return RtlNtStatusToDosError(Status);
3331 }
3332
3333 return ERROR_SUCCESS;
3334 }
3335
3336
3337 /************************************************************************
3338 * RegOpenKeyA
3339 *
3340 * 20050503 Fireball - imported from WINE
3341 *
3342 * @implemented
3343 */
3344 LONG WINAPI
3345 RegOpenKeyA(HKEY hKey,
3346 LPCSTR lpSubKey,
3347 PHKEY phkResult)
3348 {
3349 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3350 hKey, lpSubKey, phkResult);
3351
3352 if (!phkResult)
3353 return ERROR_INVALID_PARAMETER;
3354
3355 if (!hKey && lpSubKey && phkResult)
3356 {
3357 return ERROR_INVALID_HANDLE;
3358 }
3359
3360 if (!lpSubKey || !*lpSubKey)
3361 {
3362 *phkResult = hKey;
3363 return ERROR_SUCCESS;
3364 }
3365
3366 return RegOpenKeyExA(hKey,
3367 lpSubKey,
3368 0,
3369 MAXIMUM_ALLOWED,
3370 phkResult);
3371 }
3372
3373
3374 /************************************************************************
3375 * RegOpenKeyW
3376 *
3377 * 19981101 Ariadne
3378 * 19990525 EA
3379 * 20050503 Fireball - imported from WINE
3380 *
3381 * @implemented
3382 */
3383 LONG WINAPI
3384 RegOpenKeyW(HKEY hKey,
3385 LPCWSTR lpSubKey,
3386 PHKEY phkResult)
3387 {
3388 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3389 hKey, lpSubKey, phkResult);
3390
3391 if (!phkResult)
3392 return ERROR_INVALID_PARAMETER;
3393
3394 if (!hKey && lpSubKey && phkResult)
3395 {
3396 return ERROR_INVALID_HANDLE;
3397 }
3398
3399 if (!lpSubKey || !*lpSubKey)
3400 {
3401 *phkResult = hKey;
3402 return ERROR_SUCCESS;
3403 }
3404
3405 return RegOpenKeyExW(hKey,
3406 lpSubKey,
3407 0,
3408 MAXIMUM_ALLOWED,
3409 phkResult);
3410 }
3411
3412
3413 /************************************************************************
3414 * RegOpenKeyExA
3415 *
3416 * @implemented
3417 */
3418 LONG WINAPI
3419 RegOpenKeyExA(
3420 _In_ HKEY hKey,
3421 _In_ LPCSTR lpSubKey,
3422 _In_ DWORD ulOptions,
3423 _In_ REGSAM samDesired,
3424 _Out_ PHKEY phkResult)
3425 {
3426 UNICODE_STRING SubKeyString;
3427 LONG ErrorCode;
3428
3429 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3430 hKey, lpSubKey, ulOptions, samDesired, phkResult);