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