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