ReactOS 0.4.15-dev-6657-ged9973f
reg.c
Go to the documentation of this file.
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
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
38static BOOLEAN DllInitialized = FALSE; /* HACK */
39
40/* PROTOTYPES ***************************************************************/
41
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
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 */
69BOOL
71{
72 TRACE("RegInitialize()\n");
73
74 /* Lazy init hack */
75 if (!DllInitialized)
76 {
77 ProcessHeap = RtlGetProcessHeap();
79 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
81
83 }
84
85 return TRUE;
86}
87
88
89/************************************************************************
90 * RegInit
91 */
92BOOL
94{
95 TRACE("RegCleanup()\n");
96
99
100 return TRUE;
101}
102
103
104static NTSTATUS
107{
109
110 switch (Index)
111 {
112 case 0: /* HKEY_CLASSES_ROOT */
114 break;
115
116 case 1: /* HKEY_CURRENT_USER */
118 Handle);
119 break;
120
121 case 2: /* HKEY_LOCAL_MACHINE */
123 break;
124
125 case 3: /* HKEY_USERS */
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 */
136 break;
137
138 case 6: /* HKEY_DYN_DATA */
140 break;
141
142 default:
143 WARN("MapDefaultHandle() no handle creator\n");
145 break;
146 }
147
148 return Status;
149}
150
151
152static NTSTATUS
154 IN HKEY Key)
155{
157 ULONG Index;
158 BOOLEAN DoOpen, DefDisabled;
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 */
172 {
174 }
175 RegInitialize(); /* HACK until delay-loading is implemented */
177
178 if (Key == HKEY_CURRENT_USER)
179 DefDisabled = DefaultHandleHKUDisabled;
180 else
181 DefDisabled = DefaultHandlesDisabled;
182
183 if (!DefDisabled)
184 {
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 */
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
210
211 return Status;
212}
213
214
215static VOID
217{
218 ULONG i;
219 RegInitialize(); /* HACK until delay-loading is implemented */
221
222 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
223 {
224 if (DefaultHandleTable[i] != NULL)
225 {
228 }
229 }
230
232}
233
234
235static NTSTATUS
237{
239 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
241
242 TRACE("OpenClassesRootKey()\n");
243
245 &KeyName,
247 NULL,
248 NULL);
251 &Attributes);
252
253 if (!NT_SUCCESS(Status))
254 return Status;
255
256 /* Mark it as HKCR */
258
259 return Status;
260}
261
262
263static NTSTATUS
265{
267 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
269
270 TRACE("OpenLocalMachineKey()\n");
271
273 &KeyName,
275 NULL,
276 NULL);
279 &Attributes);
280
281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
282
283 return Status;
284}
285
286
287static NTSTATUS
289{
291 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
292
293 TRACE("OpenUsersKey()\n");
294
296 &KeyName,
298 NULL,
299 NULL);
300 return NtOpenKey(KeyHandle,
302 &Attributes);
303}
304
305
306static NTSTATUS
308{
311 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
312
313 TRACE("OpenCurrentConfigKey()\n");
314
316 &KeyName,
318 NULL,
319 NULL);
320 return NtOpenKey(KeyHandle,
322 &Attributes);
323}
324
325
326/************************************************************************
327 * RegDisablePredefinedCache
328 *
329 * @implemented
330 */
333{
334 RegInitialize(); /* HACK until delay-loading is implemented */
338 return ERROR_SUCCESS;
339}
340
341
342/************************************************************************
343 * RegDisablePredefinedCacheEx
344 *
345 * @implemented
346 */
349{
350 RegInitialize(); /* HACK until delay-loading is implemented */
355 return ERROR_SUCCESS;
356}
357
358
359/************************************************************************
360 * RegOverridePredefKey
361 *
362 * @implemented
363 */
366 IN HKEY hNewHKey OPTIONAL)
367{
369
370 if ((hKey == HKEY_CLASSES_ROOT ||
375 hKey == HKEY_USERS) &&
376 !IsPredefKey(hNewHKey))
377 {
379 ULONG Index;
380
383
384 if (hNewHKey == NULL)
385 {
386 /* restore the default mapping */
388 &hNewHKey);
389 if (!NT_SUCCESS(Status))
390 {
392 }
393
394 ASSERT(hNewHKey != NULL);
395 }
396 RegInitialize(); /* HACK until delay-loading is implemented */
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
409 }
410 else
412
413 return ErrorCode;
414}
415
416
417/************************************************************************
418 * RegCloseKey
419 *
420 * @implemented
421 */
424{
426
427 /* don't close null handle or a pseudo handle */
428 if (!hKey)
429 {
431 }
432
433 if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)
434 {
435 return ERROR_SUCCESS;
436 }
437
439 if (!NT_SUCCESS(Status))
440 {
442 }
443
444 return ERROR_SUCCESS;
445}
446
447
448static NTSTATUS
450 IN HKEY hKeyDest)
451{
452 typedef struct
453 {
454 LIST_ENTRY ListEntry;
455 HANDLE hKeySrc;
456 HANDLE hKeyDest;
457 } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
458
459 LIST_ENTRY copyQueueHead;
460 PREGP_COPY_KEYS copyKeys, newCopyKeys;
461 union
462 {
464 KEY_NODE_INFORMATION *KeyNode;
466 } Info;
467 ULONG Index, BufferSizeRequired, BufferSize = 0x200;
469 NTSTATUS Status2 = STATUS_SUCCESS;
470
471 InitializeListHead(&copyQueueHead);
472
474 0,
475 BufferSize);
476 if (Info.Buffer == NULL)
477 {
479 }
480
481 copyKeys = RtlAllocateHeap(ProcessHeap,
482 0,
483 sizeof(REGP_COPY_KEYS));
484 if (copyKeys != NULL)
485 {
486 copyKeys->hKeySrc = hKeySrc;
487 copyKeys->hKeyDest = hKeyDest;
488 InsertHeadList(&copyQueueHead,
489 &copyKeys->ListEntry);
490
491 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
492
493 do
494 {
495 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
496 REGP_COPY_KEYS,
497 ListEntry);
498
499 /* enumerate all values and copy them */
500 Index = 0;
501 for (;;)
502 {
503 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
504 Index,
506 Info.KeyValue,
508 &BufferSizeRequired);
509 if (NT_SUCCESS(Status2))
510 {
512 PVOID Data;
513
514 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
515 ValueName.Length = Info.KeyValue->NameLength;
516 ValueName.MaximumLength = ValueName.Length;
517 ValueName.Buffer = Info.KeyValue->Name;
518
519 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
520
521 Status2 = NtSetValueKey(copyKeys->hKeyDest,
522 &ValueName,
523 Info.KeyValue->TitleIndex,
524 Info.KeyValue->Type,
525 Data,
526 Info.KeyValue->DataLength);
527
528 /* don't break, let's try to copy as many values as possible */
529 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
530 {
531 Status = Status2;
532 }
533
534 Index++;
535 }
536 else if (Status2 == STATUS_BUFFER_OVERFLOW)
537 {
539
540 ASSERT(BufferSize < BufferSizeRequired);
541
543 0,
544 Info.Buffer,
545 BufferSizeRequired);
546 if (Buffer != NULL)
547 {
548 Info.Buffer = Buffer;
549 /* try again */
550 }
551 else
552 {
553 /* don't break, let's try to copy as many values as possible */
555 Index++;
556
557 if (NT_SUCCESS(Status))
558 {
559 Status = Status2;
560 }
561 }
562 }
563 else
564 {
565 /* break to avoid an infinite loop in case of denied access or
566 other errors! */
567 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
568 {
569 Status = Status2;
570 }
571
572 break;
573 }
574 }
575
576 /* enumerate all subkeys and open and enqueue them */
577 Index = 0;
578 for (;;)
579 {
580 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
581 Index,
583 Info.KeyNode,
585 &BufferSizeRequired);
586 if (NT_SUCCESS(Status2))
587 {
588 HANDLE KeyHandle, NewKeyHandle;
590 UNICODE_STRING SubKeyName, ClassName;
591
592 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
593 SubKeyName.Length = Info.KeyNode->NameLength;
594 SubKeyName.MaximumLength = SubKeyName.Length;
595 SubKeyName.Buffer = Info.KeyNode->Name;
596 ClassName.Length = Info.KeyNode->ClassLength;
597 ClassName.MaximumLength = ClassName.Length;
598 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
599
600 /* open the subkey with sufficient rights */
601
603 &SubKeyName,
605 copyKeys->hKeySrc,
606 NULL);
607
608 Status2 = NtOpenKey(&KeyHandle,
611 if (NT_SUCCESS(Status2))
612 {
613 /* FIXME - attempt to query the security information */
614
616 &SubKeyName,
618 copyKeys->hKeyDest,
619 NULL);
620
621 Status2 = NtCreateKey(&NewKeyHandle,
624 Info.KeyNode->TitleIndex,
625 &ClassName,
626 0,
627 NULL);
628 if (NT_SUCCESS(Status2))
629 {
630 newCopyKeys = RtlAllocateHeap(ProcessHeap,
631 0,
632 sizeof(REGP_COPY_KEYS));
633 if (newCopyKeys != NULL)
634 {
635 /* save the handles and enqueue the subkey */
636 newCopyKeys->hKeySrc = KeyHandle;
637 newCopyKeys->hKeyDest = NewKeyHandle;
638 InsertTailList(&copyQueueHead,
639 &newCopyKeys->ListEntry);
640 }
641 else
642 {
644 NtClose(NewKeyHandle);
645
647 }
648 }
649 else
650 {
652 }
653 }
654
655 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
656 {
657 Status = Status2;
658 }
659
660 Index++;
661 }
662 else if (Status2 == STATUS_BUFFER_OVERFLOW)
663 {
665
666 ASSERT(BufferSize < BufferSizeRequired);
667
669 0,
670 Info.Buffer,
671 BufferSizeRequired);
672 if (Buffer != NULL)
673 {
674 Info.Buffer = Buffer;
675 /* try again */
676 }
677 else
678 {
679 /* don't break, let's try to copy as many keys as possible */
681 Index++;
682
683 if (NT_SUCCESS(Status))
684 {
685 Status = Status2;
686 }
687 }
688 }
689 else
690 {
691 /* break to avoid an infinite loop in case of denied access or
692 other errors! */
693 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
694 {
695 Status = Status2;
696 }
697
698 break;
699 }
700 }
701
702 /* close the handles and remove the entry from the list */
703 if (copyKeys->hKeySrc != hKeySrc)
704 {
705 NtClose(copyKeys->hKeySrc);
706 }
707 if (copyKeys->hKeyDest != hKeyDest)
708 {
709 NtClose(copyKeys->hKeyDest);
710 }
711
712 RemoveEntryList(&copyKeys->ListEntry);
713
715 0,
716 copyKeys);
717 } while (!IsListEmpty(&copyQueueHead));
718 }
719 else
721
723 0,
724 Info.Buffer);
725
726 return Status;
727}
728
729
730/************************************************************************
731 * RegCopyTreeW
732 *
733 * @implemented
734 */
737 IN LPCWSTR lpSubKey OPTIONAL,
738 IN HKEY hKeyDest)
739{
740 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
742
744 hKeySrc);
745 if (!NT_SUCCESS(Status))
746 {
748 }
749
750 Status = MapDefaultKey(&DestKeyHandle,
751 hKeyDest);
752 if (!NT_SUCCESS(Status))
753 {
754 goto Cleanup2;
755 }
756
757 if (lpSubKey != NULL)
758 {
761
763
765 &SubKeyName,
767 KeyHandle,
768 NULL);
769
773 if (!NT_SUCCESS(Status))
774 {
775 goto Cleanup;
776 }
777
778 CurKey = SubKeyHandle;
779 }
780 else
781 CurKey = KeyHandle;
782
783 Status = RegpCopyTree(CurKey,
784 hKeyDest);
785
786 if (SubKeyHandle != NULL)
787 {
789 }
790
791Cleanup:
792 ClosePredefKey(DestKeyHandle);
793Cleanup2:
795
796 if (!NT_SUCCESS(Status))
797 {
799 }
800
801 return ERROR_SUCCESS;
802}
803
804
805/************************************************************************
806 * RegCopyTreeA
807 *
808 * @implemented
809 */
812 IN LPCSTR lpSubKey OPTIONAL,
813 IN HKEY hKeyDest)
814{
815 UNICODE_STRING SubKeyName = { 0, 0, NULL };
816 LONG Ret;
817
818 if (lpSubKey != NULL &&
820 {
822 }
823
824 Ret = RegCopyTreeW(hKeySrc,
825 SubKeyName.Buffer,
826 hKeyDest);
827
829
830 return Ret;
831}
832
833
834/************************************************************************
835 * RegConnectRegistryA
836 *
837 * @implemented
838 */
841 IN HKEY hKey,
842 OUT PHKEY phkResult)
843{
844 UNICODE_STRING MachineName = { 0, 0, NULL };
845 LONG Ret;
846
847 if (lpMachineName != NULL &&
849 {
851 }
852
853 Ret = RegConnectRegistryW(MachineName.Buffer,
854 hKey,
855 phkResult);
856
858
859 return Ret;
860}
861
862
863/************************************************************************
864 * RegConnectRegistryW
865 *
866 * @unimplemented
867 */
870 HKEY hKey,
871 PHKEY phkResult)
872{
873 LONG ret;
874
875 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
876
877 if (!lpMachineName || !*lpMachineName)
878 {
879 /* Use the local machine name */
880 ret = RegOpenKeyW( hKey, NULL, phkResult );
881 }
882 else
883 {
884 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
885 DWORD len = sizeof(compName) / sizeof(WCHAR);
886
887 /* MSDN says lpMachineName must start with \\ : not so */
888 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
889 lpMachineName += 2;
890
891 if (GetComputerNameW(compName, &len))
892 {
893 if (!_wcsicmp(lpMachineName, compName))
894 ret = RegOpenKeyW(hKey, NULL, phkResult);
895 else
896 {
897 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
899 }
900 }
901 else
902 ret = GetLastError();
903 }
904
905 return ret;
906}
907
908
909/************************************************************************
910 * CreateNestedKey
911 *
912 * Create key and all necessary intermediate keys
913 */
914static NTSTATUS
917 PUNICODE_STRING ClassString,
919 REGSAM samDesired,
920 DWORD *lpdwDisposition)
921{
922 OBJECT_ATTRIBUTES LocalObjectAttributes;
923 UNICODE_STRING LocalKeyName;
926 ULONG FullNameLength;
928 PWCHAR Ptr;
929 HANDLE LocalKeyHandle;
930
932 samDesired,
934 0,
935 ClassString,
936 dwOptions,
937 (PULONG)lpdwDisposition);
938 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
940 return Status;
941
942 /* Copy object attributes */
943 RtlCopyMemory(&LocalObjectAttributes,
945 sizeof(OBJECT_ATTRIBUTES));
946 RtlCreateUnicodeString(&LocalKeyName,
947 ObjectAttributes->ObjectName->Buffer);
948 LocalObjectAttributes.ObjectName = &LocalKeyName;
949 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
950
951 LocalKeyHandle = NULL;
952
953 /* Remove the last part of the key name and try to create the key again. */
955 {
956 Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
957 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
958 {
960 break;
961 }
962
963 *Ptr = (WCHAR)0;
964 LocalKeyName.Length = (USHORT)wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
965
966 Status = NtCreateKey(&LocalKeyHandle,
968 &LocalObjectAttributes,
969 0,
970 NULL,
971 0,
972 &Disposition);
973 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
974 }
975
976 if (!NT_SUCCESS(Status))
977 {
978 RtlFreeUnicodeString(&LocalKeyName);
979 return Status;
980 }
981
982 /* Add removed parts of the key name and create them too. */
983 Length = wcslen(LocalKeyName.Buffer);
984 while (TRUE)
985 {
986 if (LocalKeyHandle)
987 NtClose (LocalKeyHandle);
988
989 LocalKeyName.Buffer[Length] = L'\\';
990 Length = wcslen (LocalKeyName.Buffer);
991 LocalKeyName.Length = Length * sizeof(WCHAR);
992
993 if (Length == FullNameLength)
994 {
996 samDesired,
998 0,
999 ClassString,
1000 dwOptions,
1001 (PULONG)lpdwDisposition);
1002 break;
1003 }
1004
1005 Status = NtCreateKey(&LocalKeyHandle,
1007 &LocalObjectAttributes,
1008 0,
1009 NULL,
1010 0,
1011 &Disposition);
1012 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
1013 if (!NT_SUCCESS(Status))
1014 break;
1015 }
1016
1017 RtlFreeUnicodeString(&LocalKeyName);
1018
1019 return Status;
1020}
1021
1022
1023/************************************************************************
1024 * RegCreateKeyExA
1025 *
1026 * @implemented
1027 */
1030 _In_ HKEY hKey,
1031 _In_ LPCSTR lpSubKey,
1033 _In_ LPSTR lpClass,
1035 _In_ REGSAM samDesired,
1036 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1037 _Out_ PHKEY phkResult,
1038 _Out_ LPDWORD lpdwDisposition)
1039{
1040 UNICODE_STRING SubKeyString;
1041 UNICODE_STRING ClassString;
1043
1044 RtlInitEmptyUnicodeString(&ClassString, NULL, 0);
1045 RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
1046
1047 if (lpClass)
1048 {
1049 if (!RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass))
1050 {
1052 goto Exit;
1053 }
1054 }
1055
1056 if (lpSubKey)
1057 {
1058 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
1059 {
1061 goto Exit;
1062 }
1063 }
1064
1066 hKey,
1067 SubKeyString.Buffer,
1068 Reserved,
1069 ClassString.Buffer,
1070 dwOptions,
1071 samDesired,
1072 lpSecurityAttributes,
1073 phkResult,
1074 lpdwDisposition);
1075
1076Exit:
1077 RtlFreeUnicodeString(&SubKeyString);
1078 RtlFreeUnicodeString(&ClassString);
1079
1080 return ErrorCode;
1081}
1082
1083
1084/************************************************************************
1085 * RegCreateKeyExW
1086 *
1087 * @implemented
1088 */
1089LONG
1090WINAPI
1092 _In_ HKEY hKey,
1093 _In_ LPCWSTR lpSubKey,
1095 _In_opt_ LPWSTR lpClass,
1097 _In_ REGSAM samDesired,
1098 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1099 _Out_ PHKEY phkResult,
1100 _Out_opt_ LPDWORD lpdwDisposition)
1101{
1102 UNICODE_STRING SubKeyString;
1103 UNICODE_STRING ClassString;
1108
1109 TRACE("RegCreateKeyExW() called\n");
1110
1111 /* get the real parent key */
1113 hKey);
1114 if (!NT_SUCCESS(Status))
1115 {
1117 }
1118
1119 TRACE("ParentKey %p\n", ParentKey);
1120
1121 if (IsHKCRKey(ParentKey))
1122 {
1124 ParentKey,
1125 lpSubKey,
1126 Reserved,
1127 lpClass,
1128 dwOptions,
1129 samDesired,
1130 lpSecurityAttributes,
1131 phkResult,
1132 lpdwDisposition);
1134 return ErrorCode;
1135 }
1136
1139
1140 RtlInitUnicodeString(&ClassString,
1141 lpClass);
1142 RtlInitUnicodeString(&SubKeyString,
1143 lpSubKey);
1145 &SubKeyString,
1146 Attributes,
1148 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1149 Status = CreateNestedKey(phkResult,
1151 (lpClass == NULL)? NULL : &ClassString,
1152 dwOptions,
1153 samDesired,
1154 lpdwDisposition);
1155
1157
1158 TRACE("Status %x\n", Status);
1159 if (!NT_SUCCESS(Status))
1160 {
1162 }
1163
1164 return ERROR_SUCCESS;
1165}
1166
1167
1168/************************************************************************
1169 * RegCreateKeyA
1170 *
1171 * @implemented
1172 */
1175 LPCSTR lpSubKey,
1176 PHKEY phkResult)
1177{
1178 return RegCreateKeyExA(hKey,
1179 lpSubKey,
1180 0,
1181 NULL,
1182 0,
1184 NULL,
1185 phkResult,
1186 NULL);
1187}
1188
1189
1190/************************************************************************
1191 * RegCreateKeyW
1192 *
1193 * @implemented
1194 */
1197 LPCWSTR lpSubKey,
1198 PHKEY phkResult)
1199{
1200 return RegCreateKeyExW(hKey,
1201 lpSubKey,
1202 0,
1203 NULL,
1204 0,
1206 NULL,
1207 phkResult,
1208 NULL);
1209}
1210
1211
1212/************************************************************************
1213 * RegDeleteKeyA
1214 *
1215 * @implemented
1216 */
1217LONG
1218WINAPI
1220 _In_ HKEY hKey,
1221 _In_ LPCSTR lpSubKey)
1222{
1223 return RegDeleteKeyExA(hKey, lpSubKey, 0, 0);
1224}
1225
1226
1227/************************************************************************
1228 * RegDeleteKeyW
1229 *
1230 * @implemented
1231 */
1232LONG
1233WINAPI
1235 _In_ HKEY hKey,
1236 _In_ LPCWSTR lpSubKey)
1237{
1238 return RegDeleteKeyExW(hKey, lpSubKey, 0, 0);
1239}
1240
1241
1242/************************************************************************
1243 * RegDeleteKeyExA
1244 *
1245 * @implemented
1246 */
1247LONG
1248WINAPI
1250 _In_ HKEY hKey,
1251 _In_ LPCSTR lpSubKey,
1252 _In_ REGSAM samDesired,
1254{
1257
1258 if (lpSubKey)
1259 {
1262 }
1263 else
1264 RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0);
1265
1266 ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved);
1267
1269
1270 return ErrorCode;
1271}
1272
1273
1274/************************************************************************
1275 * RegDeleteKeyExW
1276 *
1277 * @implemented
1278 */
1279LONG
1280WINAPI
1282 _In_ HKEY hKey,
1283 _In_ LPCWSTR lpSubKey,
1284 _In_ REGSAM samDesired,
1286{
1290 HANDLE TargetKey;
1292
1293 /* Make sure we got a subkey */
1294 if (!lpSubKey)
1295 {
1296 /* Fail */
1298 }
1299
1301 hKey);
1302 if (!NT_SUCCESS(Status))
1303 {
1305 }
1306
1307 if (IsHKCRKey(ParentKey))
1308 {
1309 LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
1311 return ErrorCode;
1312 }
1313
1314 if (samDesired & KEY_WOW64_32KEY)
1315 ERR("Wow64 not yet supported!\n");
1316
1317 if (samDesired & KEY_WOW64_64KEY)
1318 ERR("Wow64 not yet supported!\n");
1319
1320
1321 RtlInitUnicodeString(&SubKeyName, lpSubKey);
1323 &SubKeyName,
1325 ParentKey,
1326 NULL);
1327 Status = NtOpenKey(&TargetKey,
1328 DELETE,
1330 if (!NT_SUCCESS(Status))
1331 {
1332 goto Cleanup;
1333 }
1334
1335 Status = NtDeleteKey(TargetKey);
1336 NtClose(TargetKey);
1337
1338Cleanup:
1340
1341 if (!NT_SUCCESS(Status))
1342 {
1344 }
1345
1346 return ERROR_SUCCESS;
1347}
1348
1349
1350/************************************************************************
1351 * RegDeleteKeyValueW
1352 *
1353 * @implemented
1354 */
1357 IN LPCWSTR lpSubKey OPTIONAL,
1358 IN LPCWSTR lpValueName OPTIONAL)
1359{
1361 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1363
1365 hKey);
1366 if (!NT_SUCCESS(Status))
1367 {
1369 }
1370
1371 if (lpSubKey != NULL)
1372 {
1375
1376 RtlInitUnicodeString(&SubKeyName, lpSubKey);
1377
1379 &SubKeyName,
1381 KeyHandle,
1382 NULL);
1383
1387 if (!NT_SUCCESS(Status))
1388 {
1389 goto Cleanup;
1390 }
1391
1392 CurKey = SubKeyHandle;
1393 }
1394 else
1395 CurKey = KeyHandle;
1396
1397 RtlInitUnicodeString(&ValueName, lpValueName);
1398
1399 Status = NtDeleteValueKey(CurKey,
1400 &ValueName);
1401
1402 if (SubKeyHandle != NULL)
1403 {
1405 }
1406
1407Cleanup:
1409
1410 if (!NT_SUCCESS(Status))
1411 {
1413 }
1414
1415 return ERROR_SUCCESS;
1416}
1417
1418
1419/************************************************************************
1420 * RegDeleteKeyValueA
1421 *
1422 * @implemented
1423 */
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, lpSubKey))
1434 {
1436 }
1437
1438 if (lpValueName != NULL &&
1440 {
1441 RtlFreeUnicodeString(&SubKey);
1443 }
1444
1446 SubKey.Buffer,
1447 SubKey.Buffer);
1448
1449 RtlFreeUnicodeString(&SubKey);
1451
1452 return Ret;
1453}
1454
1455#if 0
1456// Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1457static NTSTATUS
1458RegpDeleteTree(IN HKEY hKey)
1459{
1460 typedef struct
1461 {
1462 LIST_ENTRY ListEntry;
1464 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1465
1466 LIST_ENTRY delQueueHead;
1467 PREG_DEL_KEYS delKeys, newDelKeys;
1470 PKEY_BASIC_INFORMATION BasicInfo;
1471 PREG_DEL_KEYS KeyDelRoot;
1473 NTSTATUS Status2 = STATUS_SUCCESS;
1474
1475 InitializeListHead(&delQueueHead);
1476
1477 ProcessHeap = RtlGetProcessHeap();
1478
1479 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1480 structure for the root key, we only do that for subkeys as we need to
1481 allocate REGP_DEL_KEYS structures anyway! */
1482 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1483 0,
1484 sizeof(REGP_DEL_KEYS));
1485 if (KeyDelRoot != NULL)
1486 {
1487 KeyDelRoot->KeyHandle = hKey;
1488 InsertTailList(&delQueueHead,
1489 &KeyDelRoot->ListEntry);
1490
1491 do
1492 {
1493 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1494 REGP_DEL_KEYS,
1495 ListEntry);
1496
1497 BufferSize = 0;
1498 BasicInfo = NULL;
1499 newDelKeys = NULL;
1500
1501ReadFirstSubKey:
1502 /* check if this key contains subkeys and delete them first by queuing
1503 them at the head of the list */
1504 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1505 0,
1507 BasicInfo,
1508 BufferSize,
1509 &BufferSize);
1510
1511 if (NT_SUCCESS(Status2))
1512 {
1515
1516 ASSERT(newDelKeys != NULL);
1517 ASSERT(BasicInfo != NULL);
1518
1519 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1520 SubKeyName.Length = BasicInfo->NameLength;
1521 SubKeyName.MaximumLength = BasicInfo->NameLength;
1522 SubKeyName.Buffer = BasicInfo->Name;
1523
1525 &SubKeyName,
1527 delKeys->KeyHandle,
1528 NULL);
1529
1530 /* open the subkey */
1531 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1534 if (!NT_SUCCESS(Status2))
1535 {
1536 goto SubKeyFailure;
1537 }
1538
1539 /* enqueue this key to the head of the deletion queue */
1540 InsertHeadList(&delQueueHead,
1541 &newDelKeys->ListEntry);
1542
1543 /* try again from the head of the list */
1544 continue;
1545 }
1546 else
1547 {
1548 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1549 {
1550 newDelKeys = RtlAllocateHeap(ProcessHeap,
1551 0,
1552 BufferSize + sizeof(REGP_DEL_KEYS));
1553 if (newDelKeys != NULL)
1554 {
1555 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1556
1557 /* try again */
1558 goto ReadFirstSubKey;
1559 }
1560 else
1561 {
1562 /* don't break, let's try to delete as many keys as possible */
1564 goto SubKeyFailureNoFree;
1565 }
1566 }
1567 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1568 {
1569 PREG_DEL_KEYS newDelKeys2;
1570
1571 ASSERT(newDelKeys != NULL);
1572
1573 /* we need more memory to query the key name */
1574 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1575 0,
1576 newDelKeys,
1577 BufferSize + sizeof(REGP_DEL_KEYS));
1578 if (newDelKeys2 != NULL)
1579 {
1580 newDelKeys = newDelKeys2;
1581 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1582
1583 /* try again */
1584 goto ReadFirstSubKey;
1585 }
1586 else
1587 {
1588 /* don't break, let's try to delete as many keys as possible */
1590 }
1591 }
1592 else if (Status2 == STATUS_NO_MORE_ENTRIES)
1593 {
1594 /* in some race conditions where another thread would delete
1595 the same tree at the same time, newDelKeys could actually
1596 be != NULL! */
1597 if (newDelKeys != NULL)
1598 {
1600 0,
1601 newDelKeys);
1602 }
1603 break;
1604 }
1605
1606SubKeyFailure:
1607 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1608 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1609 if (newDelKeys != NULL)
1610 {
1612 0,
1613 newDelKeys);
1614 }
1615
1616SubKeyFailureNoFree:
1617 /* don't break, let's try to delete as many keys as possible */
1618 if (NT_SUCCESS(Status))
1619 {
1620 Status = Status2;
1621 }
1622 }
1623
1624 Status2 = NtDeleteKey(delKeys->KeyHandle);
1625
1626 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1627
1628 if (!NT_SUCCESS(Status2))
1629 {
1630 /* close the key handle so we don't leak handles for keys we were
1631 unable to delete. But only do this for handles not supplied
1632 by the caller! */
1633
1634 if (delKeys->KeyHandle != hKey)
1635 {
1636 NtClose(delKeys->KeyHandle);
1637 }
1638
1639 if (NT_SUCCESS(Status))
1640 {
1641 /* don't break, let's try to delete as many keys as possible */
1642 Status = Status2;
1643 }
1644 }
1645
1646 /* remove the entry from the list */
1647 RemoveEntryList(&delKeys->ListEntry);
1648
1650 0,
1651 delKeys);
1652 } while (!IsListEmpty(&delQueueHead));
1653 }
1654 else
1656
1657 return Status;
1658}
1659
1660
1661/************************************************************************
1662 * RegDeleteTreeW
1663 *
1664 * @implemented
1665 */
1668 IN LPCWSTR lpSubKey OPTIONAL)
1669{
1670 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1672
1674 hKey);
1675 if (!NT_SUCCESS(Status))
1676 {
1678 }
1679
1680 if (lpSubKey != NULL)
1681 {
1684
1685 RtlInitUnicodeString(&SubKeyName, lpSubKey);
1686
1688 &SubKeyName,
1690 KeyHandle,
1691 NULL);
1692
1696 if (!NT_SUCCESS(Status))
1697 {
1698 goto Cleanup;
1699 }
1700
1701 CurKey = SubKeyHandle;
1702 }
1703 else
1704 CurKey = KeyHandle;
1705
1706 Status = RegpDeleteTree(CurKey);
1707
1708 if (NT_SUCCESS(Status))
1709 {
1710 /* make sure we only close hKey (KeyHandle) when the caller specified a
1711 subkey, because the handle would be invalid already! */
1712 if (CurKey != KeyHandle)
1713 {
1715 }
1716
1717 return ERROR_SUCCESS;
1718 }
1719 else
1720 {
1721 /* make sure we close all handles we created! */
1722 if (SubKeyHandle != NULL)
1723 {
1725 }
1726
1727Cleanup:
1729
1731 }
1732}
1733#endif
1734
1735
1736/************************************************************************
1737 * RegDeleteTreeW
1738 *
1739 * @implemented
1740 */
1741LSTATUS
1742WINAPI
1744 LPCWSTR lpszSubKey)
1745{
1746 LONG ret;
1747 DWORD dwMaxSubkeyLen, dwMaxValueLen;
1748 DWORD dwMaxLen, dwSize;
1751 HKEY hSubKey;
1752 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1753
1754 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
1755
1757 hKey);
1758 if (!NT_SUCCESS(Status))
1759 {
1761 }
1762
1763 hSubKey = KeyHandle;
1764
1765 if(lpszSubKey)
1766 {
1767 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
1768 if (ret)
1769 {
1771 return ret;
1772 }
1773 }
1774
1775 /* Get highest length for keys, values */
1776 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1777 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
1778 if (ret) goto cleanup;
1779
1780 dwMaxSubkeyLen++;
1781 dwMaxValueLen++;
1782 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
1783 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
1784 {
1785 /* Name too big: alloc a buffer for it */
1786 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
1787 {
1789 goto cleanup;
1790 }
1791 }
1792
1793
1794 /* Recursively delete all the subkeys */
1795 while (TRUE)
1796 {
1797 dwSize = dwMaxLen;
1798 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
1799 NULL, NULL, NULL)) break;
1800
1801 ret = RegDeleteTreeW(hSubKey, lpszName);
1802 if (ret) goto cleanup;
1803 }
1804
1805 if (lpszSubKey)
1806 ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
1807 else
1808 while (TRUE)
1809 {
1810 dwSize = dwMaxLen;
1811 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
1812 NULL, NULL, NULL, NULL)) break;
1813
1814 ret = RegDeleteValueW(KeyHandle, lpszName);
1815 if (ret) goto cleanup;
1816 }
1817
1818cleanup:
1819 /* Free buffer if allocated */
1820 if (lpszName != szNameBuf)
1821 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
1822 if(lpszSubKey)
1823 RegCloseKey(hSubKey);
1824
1826
1827 return ret;
1828}
1829
1830
1831/************************************************************************
1832 * RegDeleteTreeA
1833 *
1834 * @implemented
1835 */
1838 IN LPCSTR lpSubKey OPTIONAL)
1839{
1840 UNICODE_STRING SubKeyName = { 0, 0, NULL };
1841 LONG Ret;
1842
1843 if (lpSubKey != NULL &&
1845 {
1847 }
1848
1849 Ret = RegDeleteTreeW(hKey,
1850 SubKeyName.Buffer);
1851
1853
1854 return Ret;
1855}
1856
1857
1858/************************************************************************
1859 * RegDisableReflectionKey
1860 *
1861 * @unimplemented
1862 */
1865{
1866 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1868}
1869
1870
1871/************************************************************************
1872 * RegEnableReflectionKey
1873 *
1874 * @unimplemented
1875 */
1878{
1879 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1881}
1882
1883
1884/******************************************************************************
1885 * RegpApplyRestrictions [internal]
1886 *
1887 * Helper function for RegGetValueA/W.
1888 */
1889static VOID
1891 DWORD dwType,
1892 DWORD cbData,
1893 PLONG ret)
1894{
1895 /* Check if the type is restricted by the passed flags */
1896 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1897 {
1898 DWORD dwMask = 0;
1899
1900 switch (dwType)
1901 {
1902 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1903 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1904 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1905 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1906 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1907 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1908 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1909 }
1910
1911 if (dwFlags & dwMask)
1912 {
1913 /* Type is not restricted, check for size mismatch */
1914 if (dwType == REG_BINARY)
1915 {
1916 DWORD cbExpect = 0;
1917
1918 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1919 cbExpect = 4;
1920 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1921 cbExpect = 8;
1922
1923 if (cbExpect && cbData != cbExpect)
1925 }
1926 }
1928 }
1929}
1930
1931
1932/******************************************************************************
1933 * RegGetValueW [ADVAPI32.@]
1934 *
1935 * Retrieves the type and data for a value name associated with a key,
1936 * optionally expanding its content and restricting its type.
1937 *
1938 * PARAMS
1939 * hKey [I] Handle to an open key.
1940 * pszSubKey [I] Name of the subkey of hKey.
1941 * pszValue [I] Name of value under hKey/szSubKey to query.
1942 * dwFlags [I] Flags restricting the value type to retrieve.
1943 * pdwType [O] Destination for the values type, may be NULL.
1944 * pvData [O] Destination for the values content, may be NULL.
1945 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1946 * retrieve the whole content, including the trailing '\0'
1947 * for strings.
1948 *
1949 * RETURNS
1950 * Success: ERROR_SUCCESS
1951 * Failure: nonzero error code from Winerror.h
1952 *
1953 * NOTES
1954 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1955 * expanded and pdwType is set to REG_SZ instead.
1956 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1957 * without RRF_NOEXPAND is thus not allowed.
1958 * An exception is the case where RRF_RT_ANY is specified, because then
1959 * RRF_NOEXPAND is allowed.
1960 */
1963 LPCWSTR pszSubKey,
1964 LPCWSTR pszValue,
1965 DWORD dwFlags,
1966 LPDWORD pdwType,
1967 PVOID pvData,
1969{
1970 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1971 PVOID pvBuf = NULL;
1972 LONG ret;
1973
1974 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1975 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1976 pvData, pcbData, cbData);
1977
1978 if (pvData && !pcbData)
1981 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1983
1984 if (pszSubKey && pszSubKey[0])
1985 {
1986 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1987 if (ret != ERROR_SUCCESS) return ret;
1988 }
1989
1990 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1991
1992 /* If we are going to expand we need to read in the whole the value even
1993 * if the passed buffer was too small as the expanded string might be
1994 * smaller than the unexpanded one and could fit into cbData bytes. */
1995 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1996 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1997 {
1998 do
1999 {
2000 HeapFree(GetProcessHeap(), 0, pvBuf);
2001
2002 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2003 if (!pvBuf)
2004 {
2006 break;
2007 }
2008
2009 if (ret == ERROR_MORE_DATA || !pvData)
2010 ret = RegQueryValueExW(hKey, pszValue, NULL,
2011 &dwType, pvBuf, &cbData);
2012 else
2013 {
2014 /* Even if cbData was large enough we have to copy the
2015 * string since ExpandEnvironmentStrings can't handle
2016 * overlapping buffers. */
2017 CopyMemory(pvBuf, pvData, cbData);
2018 }
2019
2020 /* Both the type or the value itself could have been modified in
2021 * between so we have to keep retrying until the buffer is large
2022 * enough or we no longer have to expand the value. */
2023 }
2024 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2025
2026 if (ret == ERROR_SUCCESS)
2027 {
2028 /* Recheck dwType in case it changed since the first call */
2029 if (dwType == REG_EXPAND_SZ)
2030 {
2031 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2032 pcbData ? *pcbData : 0) * sizeof(WCHAR);
2033 dwType = REG_SZ;
2034 if (pvData && pcbData && cbData > *pcbData)
2036 }
2037 else if (pvData)
2038 CopyMemory(pvData, pvBuf, *pcbData);
2039 }
2040
2041 HeapFree(GetProcessHeap(), 0, pvBuf);
2042 }
2043
2044 if (pszSubKey && pszSubKey[0])
2046
2047 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2048
2051
2052 if (pdwType)
2053 *pdwType = dwType;
2054
2055 if (pcbData)
2056 *pcbData = cbData;
2057
2058 return ret;
2059}
2060
2061
2062/******************************************************************************
2063 * RegGetValueA [ADVAPI32.@]
2064 *
2065 * See RegGetValueW.
2066 */
2069 LPCSTR pszSubKey,
2070 LPCSTR pszValue,
2071 DWORD dwFlags,
2072 LPDWORD pdwType,
2073 PVOID pvData,
2075{
2076 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2077 PVOID pvBuf = NULL;
2078 LONG ret;
2079
2080 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2081 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2082 cbData);
2083
2084 if (pvData && !pcbData)
2087 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2089
2090 if (pszSubKey && pszSubKey[0])
2091 {
2092 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2093 if (ret != ERROR_SUCCESS) return ret;
2094 }
2095
2096 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2097
2098 /* If we are going to expand we need to read in the whole the value even
2099 * if the passed buffer was too small as the expanded string might be
2100 * smaller than the unexpanded one and could fit into cbData bytes. */
2101 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2102 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2103 {
2104 do {
2105 HeapFree(GetProcessHeap(), 0, pvBuf);
2106
2107 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2108 if (!pvBuf)
2109 {
2111 break;
2112 }
2113
2114 if (ret == ERROR_MORE_DATA || !pvData)
2115 ret = RegQueryValueExA(hKey, pszValue, NULL,
2116 &dwType, pvBuf, &cbData);
2117 else
2118 {
2119 /* Even if cbData was large enough we have to copy the
2120 * string since ExpandEnvironmentStrings can't handle
2121 * overlapping buffers. */
2122 CopyMemory(pvBuf, pvData, cbData);
2123 }
2124
2125 /* Both the type or the value itself could have been modified in
2126 * between so we have to keep retrying until the buffer is large
2127 * enough or we no longer have to expand the value. */
2128 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2129
2130 if (ret == ERROR_SUCCESS)
2131 {
2132 /* Recheck dwType in case it changed since the first call */
2133 if (dwType == REG_EXPAND_SZ)
2134 {
2135 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2136 pcbData ? *pcbData : 0);
2137 dwType = REG_SZ;
2138 if(pvData && pcbData && cbData > *pcbData)
2140 }
2141 else if (pvData)
2142 CopyMemory(pvData, pvBuf, *pcbData);
2143 }
2144
2145 HeapFree(GetProcessHeap(), 0, pvBuf);
2146 }
2147
2148 if (pszSubKey && pszSubKey[0])
2150
2151 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2152
2155
2156 if (pdwType) *pdwType = dwType;
2157 if (pcbData) *pcbData = cbData;
2158
2159 return ret;
2160}
2161
2162
2163/************************************************************************
2164 * RegSetKeyValueW
2165 *
2166 * @implemented
2167 */
2170 IN LPCWSTR lpSubKey OPTIONAL,
2171 IN LPCWSTR lpValueName OPTIONAL,
2172 IN DWORD dwType,
2173 IN LPCVOID lpData OPTIONAL,
2174 IN DWORD cbData)
2175{
2176 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2178 LONG Ret;
2179
2181 hKey);
2182 if (!NT_SUCCESS(Status))
2183 {
2185 }
2186
2187 if (lpSubKey != NULL)
2188 {
2191
2192 RtlInitUnicodeString(&SubKeyName, lpSubKey);
2193
2195 &SubKeyName,
2197 KeyHandle,
2198 NULL);
2199
2203 if (!NT_SUCCESS(Status))
2204 {
2206 goto Cleanup;
2207 }
2208
2209 CurKey = SubKeyHandle;
2210 }
2211 else
2212 CurKey = KeyHandle;
2213
2214 Ret = RegSetValueExW(CurKey,
2215 lpValueName,
2216 0,
2217 dwType,
2218 lpData,
2219 cbData);
2220
2221 if (SubKeyHandle != NULL)
2222 {
2224 }
2225
2226Cleanup:
2228
2229 return Ret;
2230}
2231
2232
2233/************************************************************************
2234 * RegSetKeyValueA
2235 *
2236 * @implemented
2237 */
2240 IN LPCSTR lpSubKey OPTIONAL,
2241 IN LPCSTR lpValueName OPTIONAL,
2242 IN DWORD dwType,
2243 IN LPCVOID lpData OPTIONAL,
2244 IN DWORD cbData)
2245{
2246 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2248 LONG Ret;
2249
2251 hKey);
2252 if (!NT_SUCCESS(Status))
2253 {
2255 }
2256
2257 if (lpSubKey != NULL)
2258 {
2261
2263 {
2265 goto Cleanup;
2266 }
2267
2269 &SubKeyName,
2271 KeyHandle,
2272 NULL);
2273
2277
2279
2280 if (!NT_SUCCESS(Status))
2281 {
2283 goto Cleanup;
2284 }
2285
2286 CurKey = SubKeyHandle;
2287 }
2288 else
2289 CurKey = KeyHandle;
2290
2291 Ret = RegSetValueExA(CurKey,
2292 lpValueName,
2293 0,
2294 dwType,
2295 lpData,
2296 cbData);
2297
2298 if (SubKeyHandle != NULL)
2299 {
2301 }
2302
2303Cleanup:
2305
2306 return Ret;
2307}
2308
2309
2310/************************************************************************
2311 * RegDeleteValueA
2312 *
2313 * @implemented
2314 */
2317 LPCSTR lpValueName)
2318{
2322
2324 hKey);
2325 if (!NT_SUCCESS(Status))
2326 {
2328 }
2329
2332 &ValueName);
2334
2336
2337 if (!NT_SUCCESS(Status))
2338 {
2340 }
2341
2342 return ERROR_SUCCESS;
2343}
2344
2345
2346/************************************************************************
2347 * RegDeleteValueW
2348 *
2349 * @implemented
2350 */
2353 LPCWSTR lpValueName)
2354{
2358
2360 hKey);
2361 if (!NT_SUCCESS(Status))
2362 {
2364 }
2365
2366 RtlInitUnicodeString(&ValueName, lpValueName);
2367
2369 &ValueName);
2370
2372
2373 if (!NT_SUCCESS(Status))
2374 {
2376 }
2377
2378 return ERROR_SUCCESS;
2379}
2380
2381
2382/************************************************************************
2383 * RegEnumKeyA
2384 *
2385 * @implemented
2386 */
2389 DWORD dwIndex,
2390 LPSTR lpName,
2391 DWORD cbName)
2392{
2394
2395 dwLength = cbName;
2396 return RegEnumKeyExA(hKey,
2397 dwIndex,
2398 lpName,
2399 &dwLength,
2400 NULL,
2401 NULL,
2402 NULL,
2403 NULL);
2404}
2405
2406
2407/************************************************************************
2408 * RegEnumKeyW
2409 *
2410 * @implemented
2411 */
2414 DWORD dwIndex,
2415 LPWSTR lpName,
2416 DWORD cbName)
2417{
2419
2420 dwLength = cbName;
2421 return RegEnumKeyExW(hKey,
2422 dwIndex,
2423 lpName,
2424 &dwLength,
2425 NULL,
2426 NULL,
2427 NULL,
2428 NULL);
2429}
2430
2431
2432/************************************************************************
2433 * RegEnumKeyExA
2434 *
2435 * @implemented
2436 */
2437LONG
2438WINAPI
2440 _In_ HKEY hKey,
2441 _In_ DWORD dwIndex,
2443 _Inout_ LPDWORD lpcbName,
2444 _Reserved_ LPDWORD lpReserved,
2445 _Out_opt_ LPSTR lpClass,
2446 _Inout_opt_ LPDWORD lpcbClass,
2447 _Out_opt_ PFILETIME lpftLastWriteTime)
2448{
2449 WCHAR* NameBuffer = NULL;
2450 WCHAR* ClassBuffer = NULL;
2451 DWORD NameLength, ClassLength;
2453
2454 /* Allocate our buffers */
2455 if (*lpcbName > 0)
2456 {
2457 NameLength = *lpcbName;
2458 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR));
2459 if (NameBuffer == NULL)
2460 {
2462 goto Exit;
2463 }
2464 }
2465
2466 if (lpClass)
2467 {
2468 if (*lpcbClass > 0)
2469 {
2470 ClassLength = *lpcbClass;
2471 ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR));
2472 if (ClassBuffer == NULL)
2473 {
2475 goto Exit;
2476 }
2477 }
2478 }
2479
2480 /* Do the actual call */
2482 hKey,
2483 dwIndex,
2484 NameBuffer,
2485 lpcbName,
2486 lpReserved,
2487 ClassBuffer,
2488 lpcbClass,
2489 lpftLastWriteTime);
2490
2491 if (ErrorCode != ERROR_SUCCESS)
2492 goto Exit;
2493
2494 /* Convert the strings */
2495 RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR));
2496 /* NULL terminate if we can */
2497 if (NameLength > *lpcbName)
2498 lpName[*lpcbName] = '\0';
2499
2500 if (lpClass)
2501 {
2502 RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR));
2503 if (ClassLength > *lpcbClass)
2504 lpClass[*lpcbClass] = '\0';
2505 }
2506
2507Exit:
2508 if (NameBuffer)
2509 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2510 if (ClassBuffer)
2511 RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
2512
2513 return ErrorCode;
2514}
2515
2516
2517/************************************************************************
2518 * RegEnumKeyExW
2519 *
2520 * @implemented
2521 */
2522LONG
2523WINAPI
2525 _In_ HKEY hKey,
2526 _In_ DWORD dwIndex,
2528 _Inout_ LPDWORD lpcbName,
2529 _Reserved_ LPDWORD lpReserved,
2530 _Out_opt_ LPWSTR lpClass,
2531 _Inout_opt_ LPDWORD lpcbClass,
2532 _Out_opt_ PFILETIME lpftLastWriteTime)
2533{
2534 union
2535 {
2538 } *KeyInfo;
2539
2541 ULONG ResultSize;
2542 ULONG NameLength;
2543 ULONG ClassLength = 0;
2547
2549 hKey);
2550 if (!NT_SUCCESS(Status))
2551 {
2553 }
2554
2555 if (IsHKCRKey(KeyHandle))
2556 {
2558 KeyHandle,
2559 dwIndex,
2560 lpName,
2561 lpcbName,
2562 lpReserved,
2563 lpClass,
2564 lpcbClass,
2565 lpftLastWriteTime);
2567 return ErrorCode;
2568 }
2569
2570 if (*lpcbName > 0)
2571 {
2572 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2573 }
2574 else
2575 {
2576 NameLength = 0;
2577 }
2578
2579 if (lpClass)
2580 {
2581 if (*lpcbClass > 0)
2582 {
2583 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2584 }
2585 else
2586 {
2587 ClassLength = 0;
2588 }
2589
2590 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2591 }
2592 else
2593 {
2594 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2595 }
2596
2597 KeyInfo = RtlAllocateHeap(ProcessHeap,
2598 0,
2599 BufferSize);
2600 if (KeyInfo == NULL)
2601 {
2603 goto Cleanup;
2604 }
2605
2607 (ULONG)dwIndex,
2609 KeyInfo,
2610 BufferSize,
2611 &ResultSize);
2612 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2613 if (!NT_SUCCESS(Status))
2614 {
2616 }
2617 else
2618 {
2619 if (lpClass == NULL)
2620 {
2621 if (KeyInfo->Basic.NameLength > NameLength)
2622 {
2624 }
2625 else
2626 {
2628 KeyInfo->Basic.Name,
2629 KeyInfo->Basic.NameLength);
2630 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2631 lpName[*lpcbName] = 0;
2632 }
2633 }
2634 else
2635 {
2636 if (KeyInfo->Node.NameLength > NameLength ||
2637 KeyInfo->Node.ClassLength > ClassLength)
2638 {
2640 }
2641 else
2642 {
2644 KeyInfo->Node.Name,
2645 KeyInfo->Node.NameLength);
2646 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2647 lpName[*lpcbName] = 0;
2648 RtlCopyMemory(lpClass,
2649 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2650 KeyInfo->Node.ClassLength);
2651 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2652 lpClass[*lpcbClass] = 0;
2653 }
2654 }
2655
2656 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2657 {
2658 if (lpClass == NULL)
2659 {
2660 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2661 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2662 }
2663 else
2664 {
2665 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2666 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2667 }
2668 }
2669 }
2670
2672 0,
2673 KeyInfo);
2674
2675Cleanup:
2677
2678 return ErrorCode;
2679}
2680
2681
2682/************************************************************************
2683 * RegEnumValueA
2684 *
2685 * @implemented
2686 */
2689 _In_ HKEY hKey,
2690 _In_ DWORD dwIndex,
2692 _Inout_ LPDWORD lpcbName,
2693 _Reserved_ LPDWORD lpdwReserved,
2694 _Out_opt_ LPDWORD lpdwType,
2695 _Out_opt_ LPBYTE lpData,
2696 _Inout_opt_ LPDWORD lpcbData)
2697{
2698 WCHAR* NameBuffer;
2699 DWORD NameBufferSize, NameLength;
2701 DWORD LocalType = REG_NONE;
2702 BOOL NameOverflow = FALSE;
2703
2704 /* Do parameter checks now, once and for all. */
2705 if (!lpName || !lpcbName)
2707
2708 if ((lpData && !lpcbData) || lpdwReserved)
2710
2711 /* Get the size of the buffer we must use for the first call to RegEnumValueW */
2713 hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
2714 if (ErrorCode != ERROR_SUCCESS)
2715 return ErrorCode;
2716
2717 /* Add space for the null terminator */
2718 NameBufferSize++;
2719
2720 /* Allocate the buffer for the unicode name */
2721 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR));
2722 if (NameBuffer == NULL)
2723 {
2725 }
2726
2727 /*
2728 * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
2729 * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
2730 * is an overflow on the data or on the name during the the second call. So the first time, we make the
2731 * call with the supplied value. This is merdique, but this is how it is.
2732 */
2733 NameLength = *lpcbName;
2735 hKey,
2736 dwIndex,
2737 NameBuffer,
2738 &NameLength,
2739 NULL,
2740 &LocalType,
2741 NULL,
2742 NULL);
2743 if (ErrorCode != ERROR_SUCCESS)
2744 {
2746 NameOverflow = TRUE;
2747 else
2748 goto Exit;
2749 }
2750
2751 if (is_string(LocalType) && lpcbData)
2752 {
2753 /* We must allocate a buffer to get the unicode data */
2754 DWORD DataBufferSize = *lpcbData * sizeof(WCHAR);
2755 WCHAR* DataBuffer = NULL;
2756 DWORD DataLength = *lpcbData;
2757 LPSTR DataStr = (LPSTR)lpData;
2758
2759 if (lpData)
2760 DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR));
2761
2762 /* Do the real call */
2764 hKey,
2765 dwIndex,
2766 NameBuffer,
2767 &NameBufferSize,
2768 lpdwReserved,
2769 lpdwType,
2770 (LPBYTE)DataBuffer,
2771 &DataBufferSize);
2772
2773 *lpcbData = DataBufferSize / sizeof(WCHAR);
2774
2775 if (ErrorCode != ERROR_SUCCESS)
2776 {
2777 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2778 goto Exit;
2779 }
2780
2781 /* Copy the data whatever the error code is */
2782 if (lpData)
2783 {
2784 /* Do the data conversion */
2785 RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize);
2786 /* NULL-terminate if there is enough room */
2787 if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0'))
2788 DataStr[*lpcbData] = '\0';
2789 }
2790
2791 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2792 }
2793 else
2794 {
2795 /* No data conversion needed. Do the call with provided buffers */
2797 hKey,
2798 dwIndex,
2799 NameBuffer,
2800 &NameBufferSize,
2801 lpdwReserved,
2802 lpdwType,
2803 lpData,
2804 lpcbData);
2805
2806 if (ErrorCode != ERROR_SUCCESS)
2807 {
2808 goto Exit;
2809 }
2810 }
2811
2812 if (NameOverflow)
2813 {
2815 goto Exit;
2816 }
2817
2818 /* Convert the name string */
2819 RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR));
2820 lpName[*lpcbName] = ANSI_NULL;
2821
2822Exit:
2823 if (NameBuffer)
2824 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2825
2826 return ErrorCode;
2827}
2828
2829
2830/******************************************************************************
2831 * RegEnumValueW [ADVAPI32.@]
2832 * @implemented
2833 *
2834 * PARAMS
2835 * hkey [I] Handle to key to query
2836 * index [I] Index of value to query
2837 * value [O] Value string
2838 * val_count [I/O] Size of value buffer (in wchars)
2839 * reserved [I] Reserved
2840 * type [O] Type code
2841 * data [O] Value data
2842 * count [I/O] Size of data buffer (in bytes)
2843 *
2844 * RETURNS
2845 * Success: ERROR_SUCCESS
2846 * Failure: nonzero error code from Winerror.h
2847 */
2848LONG
2849WINAPI
2851 _In_ HKEY hKey,
2854 _Inout_ PDWORD val_count,
2859{
2862 ULONG total_size;
2863 char buffer[256], *buf_ptr = buffer;
2865 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2866
2867 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2868 hKey, index, value, val_count, reserved, type, data, count );
2869
2870 if (!value || !val_count)
2872
2873 if ((data && !count) || reserved)
2875
2877 if (!NT_SUCCESS(status))
2878 {
2880 }
2881
2882 if (IsHKCRKey(KeyHandle))
2883 {
2885 KeyHandle,
2886 index,
2887 value,
2888 val_count,
2889 reserved,
2890 type,
2891 data,
2892 count);
2894 return ErrorCode;
2895 }
2896
2897 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2898 if (data) total_size += *count;
2899 total_size = min( sizeof(buffer), total_size );
2900
2902 buffer, total_size, &total_size );
2903 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
2904
2905 if (value || data)
2906 {
2907 /* retry with a dynamically allocated buffer */
2909 {
2910 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2911 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2912 {
2914 goto done;
2915 }
2916 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2918 buf_ptr, total_size, &total_size );
2919 }
2920
2921 if (status) goto done;
2922
2923 if (value)
2924 {
2925 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2926 {
2928 goto overflow;
2929 }
2930 memcpy( value, info->Name, info->NameLength );
2931 *val_count = info->NameLength / sizeof(WCHAR);
2932 value[*val_count] = 0;
2933 }
2934
2935 if (data)
2936 {
2937 if (info->DataLength > *count)
2938 {
2940 goto overflow;
2941 }
2942 memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
2943 if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
2944 {
2945 /* if the type is REG_SZ and data is not 0-terminated
2946 * and there is enough space in the buffer NT appends a \0 */
2947 WCHAR *ptr = (WCHAR *)(data + info->DataLength);
2948 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2949 }
2950 }
2951 }
2952 else status = STATUS_SUCCESS;
2953
2954 overflow:
2955 if (type) *type = info->Type;
2956 if (count) *count = info->DataLength;
2957
2958 done:
2959 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2962}
2963
2964
2965/************************************************************************
2966 * RegFlushKey
2967 *
2968 * @implemented
2969 */
2972{
2975
2977 {
2978 return ERROR_SUCCESS;
2979 }
2980
2982 hKey);
2983 if (!NT_SUCCESS(Status))
2984 {
2986 }
2987
2989
2991
2992 if (!NT_SUCCESS(Status))
2993 {
2995 }
2996
2997 return ERROR_SUCCESS;
2998}
2999
3000
3001/************************************************************************
3002 * RegGetKeySecurity
3003 *
3004 * @implemented
3005 */
3009 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3010 LPDWORD lpcbSecurityDescriptor)
3011{
3014
3016 {
3017 return ERROR_INVALID_HANDLE;
3018 }
3019
3021 hKey);
3022 if (!NT_SUCCESS(Status))
3023 {
3024 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3026 }
3027
3030 pSecurityDescriptor,
3031 *lpcbSecurityDescriptor,
3032 lpcbSecurityDescriptor);
3033
3035
3036 if (!NT_SUCCESS(Status))
3037 {
3038 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3040 }
3041
3042 return ERROR_SUCCESS;
3043}
3044
3045
3046/************************************************************************
3047 * RegLoadKeyA
3048 *
3049 * @implemented
3050 */
3053 LPCSTR lpSubKey,
3054 LPCSTR lpFile)
3055{
3059
3060 RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
3061 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
3062
3063 if (lpSubKey)
3064 {
3066 {
3068 goto Exit;
3069 }
3070 }
3071
3072 if (lpFile)
3073 {
3075 {
3077 goto Exit;
3078 }
3079 }
3080
3082 KeyName.Buffer,
3083 FileName.Buffer);
3084
3085Exit:
3088
3089 return ErrorCode;
3090}
3091
3092
3093/************************************************************************
3094 * RegLoadKeyW
3095 *
3096 * @implemented
3097 */
3100 LPCWSTR lpSubKey,
3101 LPCWSTR lpFile)
3102{
3104 OBJECT_ATTRIBUTES KeyObjectAttributes;
3110
3112 {
3113 return ERROR_INVALID_HANDLE;
3114 }
3115
3117 hKey);
3118 if (!NT_SUCCESS(Status))
3119 {
3121 }
3122
3123 if (!RtlDosPathNameToNtPathName_U(lpFile,
3124 &FileName,
3125 NULL,
3126 NULL))
3127 {
3129 goto Cleanup;
3130 }
3131
3133 &FileName,
3135 NULL,
3136 NULL);
3137
3138 RtlInitUnicodeString(&KeyName, lpSubKey);
3139
3140 InitializeObjectAttributes(&KeyObjectAttributes,
3141 &KeyName,
3143 KeyHandle,
3144 NULL);
3145
3146 Status = NtLoadKey(&KeyObjectAttributes,
3148
3149 RtlFreeHeap(RtlGetProcessHeap(),
3150 0,
3151 FileName.Buffer);
3152
3153 if (!NT_SUCCESS(Status))
3154 {
3156 goto Cleanup;
3157 }
3158
3159Cleanup:
3161
3162 return ErrorCode;
3163}
3164
3165
3166/************************************************************************
3167 * RegNotifyChangeKeyValue
3168 *
3169 * @unimplemented
3170 */
3173 BOOL bWatchSubtree,
3174 DWORD dwNotifyFilter,
3175 HANDLE hEvent,
3176 BOOL fAsynchronous)
3177{
3182
3184 {
3185 return ERROR_INVALID_HANDLE;
3186 }
3187
3188 if ((fAsynchronous != FALSE) && (hEvent == NULL))
3189 {
3191 }
3192
3194 hKey);
3195 if (!NT_SUCCESS(Status))
3196 {
3198 }
3199
3200 /* FIXME: Remote key handles must fail */
3201
3203 hEvent,
3204 0,
3205 0,
3207 dwNotifyFilter,
3208 bWatchSubtree,
3209 0,
3210 0,
3211 fAsynchronous);
3213 {
3215 }
3216
3218
3219 return ErrorCode;
3220}
3221
3222
3223/************************************************************************
3224 * RegOpenCurrentUser
3225 *
3226 * @implemented
3227 */
3230 OUT PHKEY phkResult)
3231{
3233
3235 (PHANDLE)phkResult);
3236 if (!NT_SUCCESS(Status))
3237 {
3238 /* NOTE - don't set the last error code! just return the error! */
3240 }
3241
3242 return ERROR_SUCCESS;
3243}
3244
3245
3246/************************************************************************
3247 * RegOpenKeyA
3248 *
3249 * 20050503 Fireball - imported from WINE
3250 *
3251 * @implemented
3252 */
3255 LPCSTR lpSubKey,
3256 PHKEY phkResult)
3257{
3258 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3259 hKey, lpSubKey, phkResult);
3260
3261 if (!phkResult)
3263
3264 if (!hKey && !lpSubKey)
3265 {
3266 *phkResult = hKey;
3267 return ERROR_SUCCESS;
3268 }
3269
3270 return RegOpenKeyExA(hKey,
3271 lpSubKey,
3272 0,
3274 phkResult);
3275}
3276
3277
3278/************************************************************************
3279 * RegOpenKeyW
3280 *
3281 * 19981101 Ariadne
3282 * 19990525 EA
3283 * 20050503 Fireball - imported from WINE
3284 *
3285 * @implemented
3286 */
3289 LPCWSTR lpSubKey,
3290 PHKEY phkResult)
3291{
3292 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3293 hKey, lpSubKey, phkResult);
3294
3295 if (!phkResult)
3297
3298 if (!hKey && !lpSubKey)
3299 {
3300 *phkResult = hKey;
3301 return ERROR_SUCCESS;
3302 }
3303
3304 return RegOpenKeyExW(hKey,
3305 lpSubKey,
3306 0,
3308 phkResult);
3309}
3310
3311
3312/************************************************************************
3313 * RegOpenKeyExA
3314 *
3315 * @implemented
3316 */
3319 _In_ HKEY hKey,
3320 _In_ LPCSTR lpSubKey,
3321 _In_ DWORD ulOptions,
3322 _In_ REGSAM samDesired,
3323 _Out_ PHKEY phkResult)
3324{
3325 UNICODE_STRING SubKeyString;
3327
3328 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3329 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3330
3331 if (lpSubKey)
3332 {
3333 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
3335 }
3336 else
3337 RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
3338
3339 ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
3340
3341 RtlFreeUnicodeString(&SubKeyString);
3342
3343 return ErrorCode;
3344}
3345
3346
3347/************************************************************************
3348 * RegOpenKeyExW
3349 *
3350 * @implemented
3351 */
3354 LPCWSTR lpSubKey,
3355 DWORD ulOptions,
3356 REGSAM samDesired,
3357 PHKEY phkResult)
3358{
3360 UNICODE_STRING SubKeyString;
3365
3366 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3367 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3368 if (!phkResult)
3369 {
3371 }
3372
3373 if (!hKey && lpSubKey && phkResult)
3374 {
3375 return ERROR_INVALID_HANDLE;
3376 }
3377
3378 if (IsPredefKey(hKey) && (!lpSubKey || !*lpSubKey))
3379 {
3380 *phkResult = hKey;
3381 return ERROR_SUCCESS;
3382 }
3383
3385 if (!NT_SUCCESS(Status))
3386 {
3388 }
3389
3390 if (IsHKCRKey(KeyHandle))
3391 {
3392 ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
3394 return ErrorCode;
3395 }
3396
3397 if (ulOptions & REG_OPTION_OPEN_LINK)
3399
3400 if (lpSubKey == NULL || wcscmp(lpSubKey, L"\\") == 0)
3401 RtlInitUnicodeString(&SubKeyString, L"");
3402 else
3403 RtlInitUnicodeString(&SubKeyString, lpSubKey);
3404
3406 &SubKeyString,
3407 Attributes,
3408 KeyHandle,
3409 NULL);
3410
3411 Status = NtOpenKey((PHANDLE)phkResult,
3412 samDesired,
3414
3416 {
3417 HANDLE hAligned;
3418 UNICODE_STRING AlignedString;
3419
3421 &SubKeyString,
3422 &AlignedString);
3423 if (NT_SUCCESS(Status))
3424 {
3425 /* Try again with aligned parameters */
3427 &AlignedString,
3428 Attributes,
3429 KeyHandle,
3430 NULL);
3431
3432 Status = NtOpenKey(&hAligned,
3433 samDesired,
3435
3436 RtlFreeUnicodeString(&AlignedString);
3437
3438 if (NT_SUCCESS(Status))
3439 *phkResult = hAligned;
3440 }
3441 else
3442 {
3443 /* Restore the original error */
3445 }
3446 }
3447
3448 if (!NT_SUCCESS(Status))
3449 {
3451 }
3452
3453
3455
3456 return ErrorCode;
3457}
3458
3459
3460/************************************************************************
3461 * RegOpenUserClassesRoot
3462 *
3463 * @implemented
3464 */
3468 IN REGSAM samDesired,
3469 OUT PHKEY phkResult)
3470{
3471 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3472 const WCHAR UserClassesKeySuffix[] = L"_Classes";
3473 PTOKEN_USER TokenUserData;
3475 UNICODE_STRING UserSidString, UserClassesKeyRoot;
3478
3479 /* check parameters */
3480 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3481 {
3483 }
3484
3485 /*
3486 * Get the user sid from the token
3487 */
3488
3489ReadTokenSid:
3490 /* determine how much memory we need */
3492 TokenUser,
3493 NULL,
3494 0,
3497 {
3498 /* NOTE - as opposed to all other registry functions windows does indeed
3499 change the last error code in case the caller supplied a invalid
3500 handle for example! */
3502 }
3503 RegInitialize(); /* HACK until delay-loading is implemented */
3504 TokenUserData = RtlAllocateHeap(ProcessHeap,
3505 0,
3507 if (TokenUserData == NULL)
3508 {
3510 }
3511
3512 /* attempt to read the information */
3514 TokenUser,
3515 TokenUserData,
3518 if (!NT_SUCCESS(Status))
3519 {
3521 0,
3522 TokenUserData);
3524 {
3525 /* the information appears to have changed?! try again */
3526 goto ReadTokenSid;
3527 }
3528
3529 /* NOTE - as opposed to all other registry functions windows does indeed
3530 change the last error code in case the caller supplied a invalid
3531 handle for example! */
3533 }
3534
3535 /*
3536 * Build the absolute path for the user's registry in the form
3537 * "\Registry\User<SID>_Classes"
3538 */
3539 Status = RtlConvertSidToUnicodeString(&UserSidString,
3540 TokenUserData->User.Sid,
3541 TRUE);
3542
3543 /* we don't need the user data anymore, free it */
3545 0,
3546 TokenUserData);
3547
3548 if (!NT_SUCCESS(Status))
3549 {
3551 }
3552
3553 /* allocate enough memory for the entire key string */
3554 UserClassesKeyRoot.Length = 0;
3555 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3556 sizeof(UserClassesKeyPrefix) +
3557 sizeof(UserClassesKeySuffix);
3558 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3559 0,
3560 UserClassesKeyRoot.MaximumLength);
3561 if (UserClassesKeyRoot.Buffer == NULL)
3562 {
3563 RtlFreeUnicodeString(&UserSidString);
3565 }
3566
3567 /* build the string */
3568 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3569 UserClassesKeyPrefix);
3570 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3571 &UserSidString);
3572 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3573 UserClassesKeySuffix);
3574
3575 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3576
3577 /*
3578 * Open the key
3579 */
3581 &UserClassesKeyRoot,
3583 NULL,
3584 NULL);
3585
3586 Status = NtOpenKey((PHANDLE)phkResult,
3587 samDesired,
3589
3590 RtlFreeUnicodeString(&UserSidString);
3591 RtlFreeUnicodeString(&UserClassesKeyRoot);
3592
3593 if (!NT_SUCCESS(Status))
3594 {
3596 }
3597
3598 return ERROR_SUCCESS;
3599}
3600
3601
3602/************************************************************************
3603 * RegQueryInfoKeyA
3604 *
3605 * @implemented
3606 */
3609 LPSTR lpClass,
3610 LPDWORD lpcClass,
3611 LPDWORD lpReserved,
3612 LPDWORD lpcSubKeys,
3613 LPDWORD lpcMaxSubKeyLen,
3614 LPDWORD lpcMaxClassLen,
3615 LPDWORD lpcValues,
3616 LPDWORD lpcMaxValueNameLen,
3617 LPDWORD lpcMaxValueLen,
3618 LPDWORD lpcbSecurityDescriptor,
3619 PFILETIME lpftLastWriteTime)
3620{
3621 WCHAR ClassName[MAX_PATH];
3626 DWORD cClass = 0;
3627
3628 if ((lpClass) && (!lpcClass))
3629 {
3631 }
3632
3634 NULL);
3635 if (lpClass != NULL)
3636 {
3637 RtlInitEmptyUnicodeString(&UnicodeString,
3638 ClassName,
3639 sizeof(ClassName));
3640 cClass = sizeof(ClassName) / sizeof(WCHAR);
3641 }
3642
3644 UnicodeString.Buffer,
3645 &cClass,
3646 lpReserved,
3647 lpcSubKeys,
3648 lpcMaxSubKeyLen,
3649 lpcMaxClassLen,
3650 lpcValues,
3651 lpcMaxValueNameLen,
3652 lpcMaxValueLen,
3653 lpcbSecurityDescriptor,
3654 lpftLastWriteTime);
3655 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3656 {
3657 if (*lpcClass == 0)
3658 {
3659 return ErrorCode;
3660 }
3661
3662 RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
3663 UnicodeString.Length = cClass * sizeof(WCHAR);
3666 FALSE);
3668 cClass = AnsiString.Length;
3669 lpClass[cClass] = ANSI_NULL;
3670 }
3671
3672 if (lpcClass != NULL)
3673 {
3674 *lpcClass = cClass;
3675 }
3676
3677 return ErrorCode;
3678}
3679
3680
3681/************************************************************************
3682 * RegQueryInfoKeyW
3683 *
3684 * @implemented
3685 */
3688 LPWSTR lpClass,
3689 LPDWORD lpcClass,
3690 LPDWORD lpReserved,
3691 LPDWORD lpcSubKeys,
3692 LPDWORD lpcMaxSubKeyLen,
3693 LPDWORD lpcMaxClassLen,
3694 LPDWORD lpcValues,
3695 LPDWORD lpcMaxValueNameLen,
3696 LPDWORD lpcMaxValueLen,
3697 LPDWORD lpcbSecurityDescriptor,
3698 PFILETIME lpftLastWriteTime)
3699{
3700 KEY_FULL_INFORMATION FullInfoBuffer;
3701 PKEY_FULL_INFORMATION FullInfo;
3702 ULONG FullInfoSize;
3703 ULONG ClassLength = 0;
3706 ULONG Length;
3708
3709 if ((lpClass) && (!lpcClass))
3710 {
3712 }
3713
3715 hKey);
3716 if (!NT_SUCCESS(Status))
3717 {
3719 }
3720
3721 if (lpClass != NULL)
3722 {
3723 if (*lpcClass > 0)
3724 {
3725 ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3726 }
3727 else
3728 {
3729 ClassLength = 0;
3730 }
3731
3732 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3733 FullInfo = RtlAllocateHeap(ProcessHeap,
3734 0,
3735 FullInfoSize);
3736 if (FullInfo == NULL)
3737 {
3739 goto Cleanup;
3740 }
3741 }
3742 else
3743 {
3744 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3745 FullInfo = &FullInfoBuffer;
3746 }
3747
3748 if (lpcbSecurityDescriptor != NULL)
3749 *lpcbSecurityDescriptor = 0;
3750
3753 FullInfo,
3754 FullInfoSize,
3755 &Length);
3756 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3758 {
3760 goto Cleanup;
3761 }
3762
3763 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3764 if (lpcSubKeys != NULL)
3765 {
3766 *lpcSubKeys = FullInfo->SubKeys;
3767 }
3768
3769 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3770 if (lpcMaxSubKeyLen != NULL)
3771 {
3772 *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3773 }
3774
3775 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3776 if (lpcMaxClassLen != NULL)
3777 {
3778 *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3779 }
3780
3781 TRACE("Values %lu\n", FullInfo->Values);
3782 if (lpcValues != NULL)
3783 {
3784 *lpcValues = FullInfo->Values;
3785 }
3786
3787 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3788 if (lpcMaxValueNameLen != NULL)
3789 {
3790 *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3791 }
3792
3793 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3794 if (lpcMaxValueLen != NULL)
3795 {
3796 *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3797 }
3798
3799 if (lpcbSecurityDescriptor != NULL)
3800 {
3805 NULL,
3806 0,
3807 lpcbSecurityDescriptor);
3808 TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
3809 }
3810
3811 if (lpftLastWriteTime != NULL)
3812 {
3813 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3814 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3815 }
3816
3817 if (lpClass != NULL)
3818 {
3819 if (*lpcClass == 0)
3820 {
3821 goto Cleanup;
3822 }
3823
3824 if (FullInfo->ClassLength > ClassLength)
3825 {
3827 }
3828 else
3829 {
3830 RtlCopyMemory(lpClass,
3831 FullInfo->Class,
3832 FullInfo->ClassLength);
3833 lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3834 }
3835 }
3836
3837 if (lpcClass != NULL)
3838 {
3839 *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3840 }
3841
3842Cleanup:
3843 if (lpClass != NULL)
3844 {
3846 0,
3847 FullInfo);
3848 }
3849
3851
3852 return ErrorCode;
3853}
3854
3855
3856/************************************************************************
3857 * RegQueryMultipleValuesA
3858 *
3859 * @implemented
3860 */
3863 PVALENTA val_list,
3864 DWORD num_vals,
3865 LPSTR lpValueBuf,
3866 LPDWORD ldwTotsize)
3867{
3868 ULONG i;
3869 DWORD maxBytes = *ldwTotsize;
3870 LPSTR bufptr = lpValueBuf;
3872
3873 if (maxBytes >= (1024*1024))
3874 return ERROR_MORE_DATA;
3875
3876 *ldwTotsize = 0;
3877
3878 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3879 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3880
3881 for (i = 0; i < num_vals; i++)
3882 {
3883 val_list[i].ve_valuelen = 0;
3885 val_list[i].ve_valuename,
3886 NULL,
3887 NULL,
3888 NULL,
3889 &val_list[i].ve_valuelen);
3890 if (ErrorCode != ERROR_SUCCESS)
3891 {
3892 return ErrorCode;
3893 }
3894
3895 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3896 {
3898 val_list[i].ve_valuename,
3899 NULL,
3900 &val_list[i].ve_type,
3901 (LPBYTE)bufptr,
3902 &val_list[i].ve_valuelen);
3903 if (ErrorCode != ERROR_SUCCESS)
3904 {
3905 return ErrorCode;
3906 }
3907
3908 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3909
3910 bufptr += val_list[i].ve_valuelen;
3911 }
3912
3913 *ldwTotsize += val_list[i].ve_valuelen;
3914 }
3915
3916 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3917}
3918
3919
3920/************************************************************************
3921 * RegQueryMultipleValuesW
3922 *
3923 * @implemented
3924 */
3927 PVALENTW val_list,
3928 DWORD num_vals,
3929 LPWSTR lpValueBuf,
3930 LPDWORD ldwTotsize)
3931{
3932 ULONG i;
3933 DWORD maxBytes = *ldwTotsize;
3934 LPSTR bufptr = (LPSTR)lpValueBuf;
3936
3937 if (maxBytes >= (1024*1024))
3938 return ERROR_MORE_DATA;
3939
3940 *ldwTotsize = 0;
3941
3942 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3943 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3944
3945 for (i = 0; i < num_vals; i++)
3946 {
3947 val_list[i].ve_valuelen = 0;
3949 val_list[i].ve_valuename,
3950 NULL,
3951 NULL,
3952 NULL,
3953 &val_list[i].ve_valuelen);
3954 if (ErrorCode != ERROR_SUCCESS)
3955 {
3956 return ErrorCode;
3957 }
3958
3959 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3960 {
3962 val_list[i].ve_valuename,
3963 NULL,
3964 &val_list[i].ve_type,
3965 (LPBYTE)bufptr,
3966 &val_list[i].ve_valuelen);
3967 if (ErrorCode != ERROR_SUCCESS)
3968 {
3969 return ErrorCode;
3970 }
3971
3972 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3973
3974 bufptr += val_list[i].ve_valuelen;
3975 }
3976
3977 *ldwTotsize += val_list[i].ve_valuelen;
3978 }
3979
3980 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3981}
3982
3983
3984/************************************************************************
3985 * RegQueryReflectionKey
3986 *
3987 * @unimplemented
3988 */
3991 OUT BOOL* bIsReflectionDisabled)
3992{
3993 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3994 hBase, bIsReflectionDisabled);
3996}
3997
3998
3999/******************************************************************************
4000 * RegQueryValueExA [ADVAPI32.@]
4001 *
4002 * Get the type and contents of a specified value under with a key.
4003 *
4004 * PARAMS
4005 * hkey [I] Handle of the key to query
4006 * name [I] Name of value under hkey to query
4007 * reserved [I] Reserved - must be NULL
4008 * type [O] Destination for the value type, or NULL if not required
4009 * data [O] Destination for the values contents, or NULL if not required
4010 * count [I/O] Size of data, updated with the number of bytes returned
4011 *
4012 * RETURNS
4013 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4014 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4015 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4016 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4017 *
4018 * NOTES
4019 * MSDN states that if data is too small it is partially filled. In reality
4020 * it remains untouched.
4021 */
4022LONG
4023WINAPI
4025 _In_ HKEY hkeyorg,
4031{
4035 DWORD BufferSize = 0;
4036 WCHAR* Buffer;
4037 CHAR* DataStr = (CHAR*)data;
4038 DWORD LocalType;
4039
4040 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4041 if ((data && !count) || reserved)
4043
4044 if (name)
4045 {
4048 }
4049 else
4050 RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4051
4052 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4053 if (ErrorCode != ERROR_SUCCESS)
4054 {
4055 if ((!data) && count)
4056 *count = 0;
4058 return ErrorCode;
4059 }
4060
4061 /* See if we can directly handle the call without caring for conversion */
4062 if (!is_string(LocalType) || !count)
4063 {
4064 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4066 return ErrorCode;
4067 }
4068
4069 /* Allocate a unicode string to get the data */
4070 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4071 if (!Buffer)
4072 {
4075 }
4076
4078 if (ErrorCode != ERROR_SUCCESS)
4079 {
4080 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4082 return ErrorCode;
4083 }
4084
4085 /* We don't need this anymore */
4087
4088 /* Get the length for the multi-byte string (without the terminating NULL!) */
4089 DataLength = *count;
4091
4092 if ((!data) || (DataLength < *count))
4093 {
4094 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4096 }
4097
4098 /* We can finally do the conversion */
4100
4101 /* NULL-terminate if there is enough room */
4102 if (DataLength > *count)
4103 DataStr[*count] = '\0';
4104
4105 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4106
4107 return ERROR_SUCCESS;
4108}
4109
4110
4111/************************************************************************
4112 * RegQueryValueExW
4113 *
4114 * @implemented
4115 */
4116LONG
4117WINAPI
4119 _In_ HKEY hkeyorg,
4125{
4126 HANDLE hkey;
4128 UNICODE_STRING name_str;
4129 DWORD total_size;
4130 char buffer[256], *buf_ptr = buffer;
4132 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4133
4134 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4135 hkeyorg, debugstr_w(name), reserved, type, data, count,
4136 (count && data) ? *count : 0 );
4137
4138 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4139
4140 status = MapDefaultKey(&hkey, hkeyorg);
4141 if (!NT_SUCCESS(status))
4142 {
4144 }
4145
4146 if (IsHKCRKey(hkey))
4147 {
4149 ClosePredefKey(hkey);
4150 return ErrorCode;
4151 }
4152
4153 RtlInitUnicodeString( &name_str, name );
4154
4155 if (data)
4156 total_size = min( sizeof(buffer), *count + info_size );
4157 else
4158 total_size = info_size;
4159
4160
4162 buffer, total_size, &total_size );
4163
4165 {
4166 // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4167 // On windows these conditions are likely to be side effects of the implementation...
4168 if (status == STATUS_INVALID_HANDLE && hkey)
4169 {
4170 if (type) *type = REG_NONE;
4171 if (count) *count = 0;
4172 }
4174 {
4175 if (type) *type = REG_NONE;
4176 if (data == NULL && count) *count = 0;
4177 }
4178 goto done;
4179 }
4180
4181 if (data)
4182 {
4183 /* retry with a dynamically allocated buffer */
4184 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4185 {
4186 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4187 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4188 {
4189 ClosePredefKey(hkey);
4191 }
4194 buf_ptr, total_size, &total_size );
4195 }
4196
4197 if (NT_SUCCESS(status))
4198 {
4199 memcpy( data, buf_ptr + info_size, total_size - info_size );
4200 /* if the type is REG_SZ and data is not 0-terminated
4201 * and there is enough space in the buffer NT appends a \0 */
4202 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4203 {
4204 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4205 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4206 }
4207 }
4208 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4209 }
4210 else status = STATUS_SUCCESS;
4211
4212 if (type) *type = info->Type;
4213 if (count) *count = total_size - info_size;
4214
4215 done:
4216 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4217 ClosePredefKey(hkey);
4219}
4220
4221
4222/************************************************************************
4223 * RegQueryValueA
4224 *
4225 * @implemented
4226 */
4228{
4229 DWORD ret;
4230 HKEY subkey = hkey;
4231
4232 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4233
4234 if (name && name[0])
4235 {
4236 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4237 }
4239 if (subkey != hkey) RegCloseKey( subkey );
4241 {
4242 /* return empty string if default value not found */
4243 if (data) *data = 0;
4244 if (count) *count = 1;
4246 }
4247 return ret;
4248}
4249
4250
4251/************************************************************************
4252 * RegQueryValueW
4253 *
4254 * @implemented
4255 */
4257{
4258 DWORD ret;
4259 HKEY subkey = hkey;
4260
4261 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4262 if (hkey == NULL)
4263 {
4264 return ERROR_INVALID_HANDLE;
4265 }
4266 if (name && name[0])
4267 {
4268 ret = RegOpenKeyW( hkey, name, &subkey);
4269 if (ret != ERROR_SUCCESS)
4270 {
4271 return ret;
4272 }
4273 }
4274
4276
4277 if (subkey != hkey)
4278 {
4279 RegCloseKey( subkey );
4280 }
4281
4283 {
4284 /* return empty string if default value not found */
4285 if (data)
4286 *data = 0;
4287 if (count)
4288 *count = sizeof(WCHAR);
4290 }
4291 return ret;
4292}
4293
4294
4295/************************************************************************
4296 * RegReplaceKeyA
4297 *
4298 * @implemented
4299 */
4302 LPCSTR lpSubKey,
4303 LPCSTR lpNewFile,
4304 LPCSTR lpOldFile)
4305{
4306 UNICODE_STRING SubKey;
4307 UNICODE_STRING NewFile;
4308 UNICODE_STRING OldFile;
4310
4311 RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4312 RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4313 RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4314
4315 if (lpSubKey)
4316 {
4317 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4318 {
4320 goto Exit;
4321 }
4322 }
4323
4324 if (lpOldFile)
4325 {
4326 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4327 {
4329 goto Exit;
4330 }
4331 }
4332
4333 if (lpNewFile)
4334 {
4335 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4336 {
4338 goto Exit;
4339 }
4340 }
4341
4343 SubKey.Buffer,
4344 NewFile.Buffer,
4345 OldFile.Buffer);
4346
4347Exit:
4348 RtlFreeUnicodeString(&OldFile);
4349 RtlFreeUnicodeString(&NewFile);
4350 RtlFreeUnicodeString(&SubKey);
4351
4352 return ErrorCode;
4353}
4354
4355
4356/************************************************************************
4357 * RegReplaceKeyW
4358 *
4359 * @unimplemented
4360 */
4363 LPCWSTR lpSubKey,
4364 LPCWSTR lpNewFile,
4365 LPCWSTR lpOldFile)
4366{
4367 OBJECT_ATTRIBUTES KeyObjectAttributes;
4368 OBJECT_ATTRIBUTES NewObjectAttributes;
4369 OBJECT_ATTRIBUTES OldObjectAttributes;
4371 UNICODE_STRING NewFileName;
4372 UNICODE_STRING OldFileName;
4373 BOOLEAN CloseRealKey;
4374 HANDLE RealKeyHandle;
4378
4380 {
4381 return ERROR_INVALID_HANDLE;
4382 }
4383
4385 hKey);
4386 if (!NT_SUCCESS(Status))
4387 {
4389 }
4390
4391 /* Open the real key */
4392 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4393 {
4394 RtlInitUnicodeString(&SubKeyName, lpSubKey);
4395 InitializeObjectAttributes(&KeyObjectAttributes,
4396 &SubKeyName,
4398 KeyHandle,
4399 NULL);
4400 Status = NtOpenKey(&RealKeyHandle,
4402 &KeyObjectAttributes);
4403 if (!NT_SUCCESS(Status))
4404 {
4406 goto Cleanup;
4407 }
4408
4409 CloseRealKey = TRUE;
4410 }
4411 else
4412 {
4413 RealKeyHandle = KeyHandle;
4414 CloseRealKey = FALSE;
4415 }
4416
4417 /* Convert new file name */
4418 if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4419 &NewFileName,
4420 NULL,
4421 NULL))
4422 {
4423 if (CloseRealKey)
4424 {
4425 NtClose(RealKeyHandle);
4426 }
4427
4429 goto Cleanup;
4430 }
4431
4432 InitializeObjectAttributes(&NewObjectAttributes,
4433 &NewFileName,
4435 NULL,
4436 NULL);
4437
4438 /* Convert old file name */
4439 if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4440 &OldFileName,
4441 NULL,
4442 NULL))
4443 {
4444 RtlFreeHeap(RtlGetProcessHeap (),
4445 0,
4446 NewFileName.Buffer);
4447 if (CloseRealKey)
4448 {
4449 NtClose(RealKeyHandle);
4450 }
4451
4453 goto Cleanup;
4454 }
4455
4456 InitializeObjectAttributes(&OldObjectAttributes,
4457 &OldFileName,
4459 NULL,
4460 NULL);
4461
4462 Status = NtReplaceKey(&NewObjectAttributes,
4463 RealKeyHandle,
4464 &OldObjectAttributes);
4465
4466 RtlFreeHeap(RtlGetProcessHeap(),
4467 0,
4468 OldFileName.Buffer);
4469 RtlFreeHeap(RtlGetProcessHeap(),
4470 0,
4471 NewFileName.Buffer);
4472
4473 if (CloseRealKey)
4474 {
4475 NtClose(RealKeyHandle);
4476 }
4477
4478 if (!NT_SUCCESS(Status))
4479 {
4481 }
4482
4483Cleanup:
4485
4486 return ErrorCode;
4487}
4488
4489
4490/************************************************************************
4491 * RegRestoreKeyA
4492 *
4493 * @implemented
4494 */
4497 LPCSTR lpFile,
4498 DWORD dwFlags)
4499{
4502
4503 if (lpFile)
4504 {
4507 }
4508 else
4509 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4510
4512 FileName.Buffer,
4513 dwFlags);
4514
4516
4517 return ErrorCode;
4518}
4519
4520
4521/************************************************************************
4522 * RegRestoreKeyW
4523 *
4524 * @implemented
4525 */
4528 LPCWSTR lpFile,
4529 DWORD dwFlags)
4530{
4537
4539 {
4540 return ERROR_INVALID_HANDLE;
4541 }
4542
4544 hKey);
4545 if (!NT_SUCCESS(Status))
4546 {
4548 }
4549
4550 if (!RtlDosPathNameToNtPathName_U(lpFile,
4551 &FileName,
4552 NULL,
4553 NULL))
4554 {
4556 goto Cleanup;
4557 }
4558
4560 &FileName,
4562 NULL,
4563 NULL);
4564
4571 RtlFreeHeap(RtlGetProcessHeap(),
4572 0,
4573 FileName.Buffer);
4574 if (!NT_SUCCESS(Status))
4575 {
4576 goto Cleanup;
4577 }
4578
4580 FileHandle,
4581 (ULONG)dwFlags);
4583
4584Cleanup:
4586
4587 if (!NT_SUCCESS(Status))
4588 {
4590 }
4591
4592 return ERROR_SUCCESS;
4593}
4594
4595
4596/************************************************************************
4597 * RegSaveKeyA
4598 *
4599 * @implemented
4600 */
4603 LPCSTR lpFile,
4604 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4605{
4608
4609 if (lpFile)
4610 {
4613 }
4614 else
4615 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4616
4618 FileName.Buffer,
4619 lpSecurityAttributes);
4621
4622 return ErrorCode;
4623}
4624
4625
4626/************************************************************************
4627 * RegSaveKeyW
4628 *
4629 * @implemented
4630 */
4633 LPCWSTR lpFile,
4634 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4635{
4643
4645 hKey);
4646 if (!NT_SUCCESS(Status))
4647 {
4649 }
4650
4651 if (!RtlDosPathNameToNtPathName_U(lpFile,
4652 &FileName,
4653 NULL,
4654 NULL))
4655 {
4657 goto Cleanup;
4658 }
4659
4660 if (lpSecurityAttributes != NULL)
4661 {
4662 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4663 }
4664
4666 &FileName,
4668 NULL,
4674 NULL,
4679 NULL,
4680 0);
4681 RtlFreeHeap(RtlGetProcessHeap(),
4682 0,
4683 FileName.Buffer);
4684 if (!NT_SUCCESS(Status))
4685 {
4686 goto Cleanup;
4687 }
4688
4690 FileHandle);
4692
4693Cleanup:
4695
4696 if (!NT_SUCCESS(Status))
4697 {
4699 }
4700
4701 return ERROR_SUCCESS;
4702}
4703
4704
4705/************************************************************************
4706 * RegSaveKeyExA
4707 *
4708 * @implemented
4709 */
4710LONG
4711WINAPI
4713 LPCSTR lpFile,
4714 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4715 DWORD Flags)
4716{
4719
4720 if (lpFile)
4721 {
4722 if (!