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