ReactOS  0.4.15-dev-5606-gf34e425
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 
38 static BOOLEAN DllInitialized = FALSE; /* HACK */
39 
40 /* PROTOTYPES ***************************************************************/
41 
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 
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
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  */
92 BOOL
94 {
95  TRACE("RegCleanup()\n");
96 
99 
100  return TRUE;
101 }
102 
103 
104 static NTSTATUS
106  OUT HANDLE Handle)
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 
152 static NTSTATUS
154  IN HKEY Key)
155 {
156  PHANDLE Handle;
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 */
171  if (Index >= MAX_DEFAULT_HANDLES)
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 
215 static 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 
235 static 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 
263 static 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 
287 static 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 
306 static 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  */
331 LONG WINAPI
333 {
334  RegInitialize(); /* HACK until delay-loading is implemented */
338  return ERROR_SUCCESS;
339 }
340 
341 
342 /************************************************************************
343  * RegDisablePredefinedCacheEx
344  *
345  * @implemented
346  */
347 LONG WINAPI
349 {
350  RegInitialize(); /* HACK until delay-loading is implemented */
355  return ERROR_SUCCESS;
356 }
357 
358 
359 /************************************************************************
360  * RegOverridePredefKey
361  *
362  * @implemented
363  */
364 LONG WINAPI
366  IN HKEY hNewHKey OPTIONAL)
367 {
369 
370  if ((hKey == HKEY_CLASSES_ROOT ||
372  hKey == HKEY_CURRENT_USER ||
375  hKey == HKEY_USERS) &&
376  !IsPredefKey(hNewHKey))
377  {
378  PHANDLE Handle;
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  */
422 LONG WINAPI
424 {
426 
427  /* don't close null handle or a pseudo handle */
428  if (!hKey)
429  {
430  return ERROR_INVALID_HANDLE;
431  }
432 
433  if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)
434  {
435  return ERROR_SUCCESS;
436  }
437 
438  Status = NtClose(hKey);
439  if (!NT_SUCCESS(Status))
440  {
442  }
443 
444  return ERROR_SUCCESS;
445 }
446 
447 
448 static 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  {
463  KEY_VALUE_FULL_INFORMATION *KeyValue;
464  KEY_NODE_INFORMATION *KeyNode;
465  PVOID Buffer;
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,
507  BufferSize,
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  {
538  PVOID Buffer;
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,
584  BufferSize,
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  {
664  PVOID Buffer;
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  */
735 LONG WINAPI
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 
762  RtlInitUnicodeString(&SubKeyName, lpSubKey);
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 
791 Cleanup:
792  ClosePredefKey(DestKeyHandle);
793 Cleanup2:
795 
796  if (!NT_SUCCESS(Status))
797  {
799  }
800 
801  return ERROR_SUCCESS;
802 }
803 
804 
805 /************************************************************************
806  * RegCopyTreeA
807  *
808  * @implemented
809  */
810 LONG WINAPI
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  */
839 LONG WINAPI
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  */
868 LONG WINAPI
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  */
914 static NTSTATUS
917  PUNICODE_STRING ClassString,
919  REGSAM samDesired,
920  DWORD *lpdwDisposition)
921 {
922  OBJECT_ATTRIBUTES LocalObjectAttributes;
923  UNICODE_STRING LocalKeyName;
926  ULONG FullNameLength;
927  ULONG Length;
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  */
1028 LONG WINAPI
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;
1042  DWORD ErrorCode;
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 
1076 Exit:
1077  RtlFreeUnicodeString(&SubKeyString);
1078  RtlFreeUnicodeString(&ClassString);
1079 
1080  return ErrorCode;
1081 }
1082 
1083 
1084 /************************************************************************
1085  * RegCreateKeyExW
1086  *
1087  * @implemented
1088  */
1089 LONG
1090 WINAPI
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;
1105  HANDLE ParentKey;
1107  NTSTATUS Status;
1108 
1109  TRACE("RegCreateKeyExW() called\n");
1110 
1111  if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1113 
1114  /* get the real parent key */
1116  hKey);
1117  if (!NT_SUCCESS(Status))
1118  {
1119  return RtlNtStatusToDosError(Status);
1120  }
1121 
1122  TRACE("ParentKey %p\n", ParentKey);
1123 
1124  if (IsHKCRKey(ParentKey))
1125  {
1127  ParentKey,
1128  lpSubKey,
1129  Reserved,
1130  lpClass,
1131  dwOptions,
1132  samDesired,
1133  lpSecurityAttributes,
1134  phkResult,
1135  lpdwDisposition);
1137  return ErrorCode;
1138  }
1139 
1142 
1143  RtlInitUnicodeString(&ClassString,
1144  lpClass);
1145  RtlInitUnicodeString(&SubKeyString,
1146  lpSubKey);
1148  &SubKeyString,
1149  Attributes,
1150  (HANDLE)ParentKey,
1151  lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1152  Status = CreateNestedKey(phkResult,
1154  (lpClass == NULL)? NULL : &ClassString,
1155  dwOptions,
1156  samDesired,
1157  lpdwDisposition);
1158 
1160 
1161  TRACE("Status %x\n", Status);
1162  if (!NT_SUCCESS(Status))
1163  {
1164  return RtlNtStatusToDosError(Status);
1165  }
1166 
1167  return ERROR_SUCCESS;
1168 }
1169 
1170 
1171 /************************************************************************
1172  * RegCreateKeyA
1173  *
1174  * @implemented
1175  */
1176 LONG WINAPI
1178  LPCSTR lpSubKey,
1179  PHKEY phkResult)
1180 {
1181  return RegCreateKeyExA(hKey,
1182  lpSubKey,
1183  0,
1184  NULL,
1185  0,
1187  NULL,
1188  phkResult,
1189  NULL);
1190 }
1191 
1192 
1193 /************************************************************************
1194  * RegCreateKeyW
1195  *
1196  * @implemented
1197  */
1198 LONG WINAPI
1200  LPCWSTR lpSubKey,
1201  PHKEY phkResult)
1202 {
1203  return RegCreateKeyExW(hKey,
1204  lpSubKey,
1205  0,
1206  NULL,
1207  0,
1209  NULL,
1210  phkResult,
1211  NULL);
1212 }
1213 
1214 
1215 /************************************************************************
1216  * RegDeleteKeyA
1217  *
1218  * @implemented
1219  */
1220 LONG
1221 WINAPI
1223  _In_ HKEY hKey,
1224  _In_ LPCSTR lpSubKey)
1225 {
1226  return RegDeleteKeyExA(hKey, lpSubKey, 0, 0);
1227 }
1228 
1229 
1230 /************************************************************************
1231  * RegDeleteKeyW
1232  *
1233  * @implemented
1234  */
1235 LONG
1236 WINAPI
1238  _In_ HKEY hKey,
1239  _In_ LPCWSTR lpSubKey)
1240 {
1241  return RegDeleteKeyExW(hKey, lpSubKey, 0, 0);
1242 }
1243 
1244 
1245 /************************************************************************
1246  * RegDeleteKeyExA
1247  *
1248  * @implemented
1249  */
1250 LONG
1251 WINAPI
1253  _In_ HKEY hKey,
1254  _In_ LPCSTR lpSubKey,
1255  _In_ REGSAM samDesired,
1257 {
1258  LONG ErrorCode;
1260 
1261  if (lpSubKey)
1262  {
1264  return ERROR_NOT_ENOUGH_MEMORY;
1265  }
1266  else
1267  RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0);
1268 
1269  ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved);
1270 
1272 
1273  return ErrorCode;
1274 }
1275 
1276 
1277 /************************************************************************
1278  * RegDeleteKeyExW
1279  *
1280  * @implemented
1281  */
1282 LONG
1283 WINAPI
1285  _In_ HKEY hKey,
1286  _In_ LPCWSTR lpSubKey,
1287  _In_ REGSAM samDesired,
1289 {
1292  HANDLE ParentKey;
1293  HANDLE TargetKey;
1294  NTSTATUS Status;
1295 
1296  /* Make sure we got a subkey */
1297  if (!lpSubKey)
1298  {
1299  /* Fail */
1300  return ERROR_INVALID_PARAMETER;
1301  }
1302 
1304  hKey);
1305  if (!NT_SUCCESS(Status))
1306  {
1307  return RtlNtStatusToDosError(Status);
1308  }
1309 
1310  if (IsHKCRKey(ParentKey))
1311  {
1312  LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
1314  return ErrorCode;
1315  }
1316 
1317  if (samDesired & KEY_WOW64_32KEY)
1318  ERR("Wow64 not yet supported!\n");
1319 
1320  if (samDesired & KEY_WOW64_64KEY)
1321  ERR("Wow64 not yet supported!\n");
1322 
1323 
1324  RtlInitUnicodeString(&SubKeyName, lpSubKey);
1326  &SubKeyName,
1328  ParentKey,
1329  NULL);
1330  Status = NtOpenKey(&TargetKey,
1331  DELETE,
1332  &ObjectAttributes);
1333  if (!NT_SUCCESS(Status))
1334  {
1335  goto Cleanup;
1336  }
1337 
1338  Status = NtDeleteKey(TargetKey);
1339  NtClose(TargetKey);
1340 
1341 Cleanup:
1343 
1344  if (!NT_SUCCESS(Status))
1345  {
1346  return RtlNtStatusToDosError(Status);
1347  }
1348 
1349  return ERROR_SUCCESS;
1350 }
1351 
1352 
1353 /************************************************************************
1354  * RegDeleteKeyValueW
1355  *
1356  * @implemented
1357  */
1358 LONG WINAPI
1360  IN LPCWSTR lpSubKey OPTIONAL,
1361  IN LPCWSTR lpValueName OPTIONAL)
1362 {
1364  HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1365  NTSTATUS Status;
1366 
1368  hKey);
1369  if (!NT_SUCCESS(Status))
1370  {
1371  return RtlNtStatusToDosError(Status);
1372  }
1373 
1374  if (lpSubKey != NULL)
1375  {
1378 
1379  RtlInitUnicodeString(&SubKeyName, lpSubKey);
1380 
1382  &SubKeyName,
1384  KeyHandle,
1385  NULL);
1386 
1388  KEY_SET_VALUE,
1389  &ObjectAttributes);
1390  if (!NT_SUCCESS(Status))
1391  {
1392  goto Cleanup;
1393  }
1394 
1395  CurKey = SubKeyHandle;
1396  }
1397  else
1398  CurKey = KeyHandle;
1399 
1400  RtlInitUnicodeString(&ValueName, lpValueName);
1401 
1402  Status = NtDeleteValueKey(CurKey,
1403  &ValueName);
1404 
1405  if (SubKeyHandle != NULL)
1406  {
1408  }
1409 
1410 Cleanup:
1412 
1413  if (!NT_SUCCESS(Status))
1414  {
1415  return RtlNtStatusToDosError(Status);
1416  }
1417 
1418  return ERROR_SUCCESS;
1419 }
1420 
1421 
1422 /************************************************************************
1423  * RegDeleteKeyValueA
1424  *
1425  * @implemented
1426  */
1427 LONG WINAPI
1429  IN LPCSTR lpSubKey OPTIONAL,
1430  IN LPCSTR lpValueName OPTIONAL)
1431 {
1432  UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
1433  LONG Ret;
1434 
1435  if (lpSubKey != NULL &&
1436  !RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
1437  {
1438  return ERROR_NOT_ENOUGH_MEMORY;
1439  }
1440 
1441  if (lpValueName != NULL &&
1443  {
1444  RtlFreeUnicodeString(&SubKey);
1445  return ERROR_NOT_ENOUGH_MEMORY;
1446  }
1447 
1448  Ret = RegDeleteKeyValueW(hKey,
1449  SubKey.Buffer,
1450  SubKey.Buffer);
1451 
1452  RtlFreeUnicodeString(&SubKey);
1454 
1455  return Ret;
1456 }
1457 
1458 #if 0
1459 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1460 static NTSTATUS
1461 RegpDeleteTree(IN HKEY hKey)
1462 {
1463  typedef struct
1464  {
1465  LIST_ENTRY ListEntry;
1466  HANDLE KeyHandle;
1467  } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1468 
1469  LIST_ENTRY delQueueHead;
1470  PREG_DEL_KEYS delKeys, newDelKeys;
1472  ULONG BufferSize;
1473  PKEY_BASIC_INFORMATION BasicInfo;
1474  PREG_DEL_KEYS KeyDelRoot;
1476  NTSTATUS Status2 = STATUS_SUCCESS;
1477 
1478  InitializeListHead(&delQueueHead);
1479 
1480  ProcessHeap = RtlGetProcessHeap();
1481 
1482  /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1483  structure for the root key, we only do that for subkeys as we need to
1484  allocate REGP_DEL_KEYS structures anyway! */
1485  KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1486  0,
1487  sizeof(REGP_DEL_KEYS));
1488  if (KeyDelRoot != NULL)
1489  {
1490  KeyDelRoot->KeyHandle = hKey;
1491  InsertTailList(&delQueueHead,
1492  &KeyDelRoot->ListEntry);
1493 
1494  do
1495  {
1496  delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1497  REGP_DEL_KEYS,
1498  ListEntry);
1499 
1500  BufferSize = 0;
1501  BasicInfo = NULL;
1502  newDelKeys = NULL;
1503 
1504 ReadFirstSubKey:
1505  /* check if this key contains subkeys and delete them first by queuing
1506  them at the head of the list */
1507  Status2 = NtEnumerateKey(delKeys->KeyHandle,
1508  0,
1510  BasicInfo,
1511  BufferSize,
1512  &BufferSize);
1513 
1514  if (NT_SUCCESS(Status2))
1515  {
1518 
1519  ASSERT(newDelKeys != NULL);
1520  ASSERT(BasicInfo != NULL);
1521 
1522  /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1523  SubKeyName.Length = BasicInfo->NameLength;
1524  SubKeyName.MaximumLength = BasicInfo->NameLength;
1525  SubKeyName.Buffer = BasicInfo->Name;
1526 
1528  &SubKeyName,
1530  delKeys->KeyHandle,
1531  NULL);
1532 
1533  /* open the subkey */
1534  Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1536  &ObjectAttributes);
1537  if (!NT_SUCCESS(Status2))
1538  {
1539  goto SubKeyFailure;
1540  }
1541 
1542  /* enqueue this key to the head of the deletion queue */
1543  InsertHeadList(&delQueueHead,
1544  &newDelKeys->ListEntry);
1545 
1546  /* try again from the head of the list */
1547  continue;
1548  }
1549  else
1550  {
1551  if (Status2 == STATUS_BUFFER_TOO_SMALL)
1552  {
1553  newDelKeys = RtlAllocateHeap(ProcessHeap,
1554  0,
1555  BufferSize + sizeof(REGP_DEL_KEYS));
1556  if (newDelKeys != NULL)
1557  {
1558  BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1559 
1560  /* try again */
1561  goto ReadFirstSubKey;
1562  }
1563  else
1564  {
1565  /* don't break, let's try to delete as many keys as possible */
1567  goto SubKeyFailureNoFree;
1568  }
1569  }
1570  else if (Status2 == STATUS_BUFFER_OVERFLOW)
1571  {
1572  PREG_DEL_KEYS newDelKeys2;
1573 
1574  ASSERT(newDelKeys != NULL);
1575 
1576  /* we need more memory to query the key name */
1577  newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1578  0,
1579  newDelKeys,
1580  BufferSize + sizeof(REGP_DEL_KEYS));
1581  if (newDelKeys2 != NULL)
1582  {
1583  newDelKeys = newDelKeys2;
1584  BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1585 
1586  /* try again */
1587  goto ReadFirstSubKey;
1588  }
1589  else
1590  {
1591  /* don't break, let's try to delete as many keys as possible */
1593  }
1594  }
1595  else if (Status2 == STATUS_NO_MORE_ENTRIES)
1596  {
1597  /* in some race conditions where another thread would delete
1598  the same tree at the same time, newDelKeys could actually
1599  be != NULL! */
1600  if (newDelKeys != NULL)
1601  {
1603  0,
1604  newDelKeys);
1605  }
1606  break;
1607  }
1608 
1609 SubKeyFailure:
1610  /* newDelKeys can be NULL here when NtEnumerateKey returned an
1611  error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1612  if (newDelKeys != NULL)
1613  {
1615  0,
1616  newDelKeys);
1617  }
1618 
1619 SubKeyFailureNoFree:
1620  /* don't break, let's try to delete as many keys as possible */
1621  if (NT_SUCCESS(Status))
1622  {
1623  Status = Status2;
1624  }
1625  }
1626 
1627  Status2 = NtDeleteKey(delKeys->KeyHandle);
1628 
1629  /* NOTE: do NOT close the handle anymore, it's invalid already! */
1630 
1631  if (!NT_SUCCESS(Status2))
1632  {
1633  /* close the key handle so we don't leak handles for keys we were
1634  unable to delete. But only do this for handles not supplied
1635  by the caller! */
1636 
1637  if (delKeys->KeyHandle != hKey)
1638  {
1639  NtClose(delKeys->KeyHandle);
1640  }
1641 
1642  if (NT_SUCCESS(Status))
1643  {
1644  /* don't break, let's try to delete as many keys as possible */
1645  Status = Status2;
1646  }
1647  }
1648 
1649  /* remove the entry from the list */
1650  RemoveEntryList(&delKeys->ListEntry);
1651 
1653  0,
1654  delKeys);
1655  } while (!IsListEmpty(&delQueueHead));
1656  }
1657  else
1659 
1660  return Status;
1661 }
1662 
1663 
1664 /************************************************************************
1665  * RegDeleteTreeW
1666  *
1667  * @implemented
1668  */
1669 LONG WINAPI
1671  IN LPCWSTR lpSubKey OPTIONAL)
1672 {
1673  HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1674  NTSTATUS Status;
1675 
1677  hKey);
1678  if (!NT_SUCCESS(Status))
1679  {
1680  return RtlNtStatusToDosError(Status);
1681  }
1682 
1683  if (lpSubKey != NULL)
1684  {
1687 
1688  RtlInitUnicodeString(&SubKeyName, lpSubKey);
1689 
1691  &SubKeyName,
1693  KeyHandle,
1694  NULL);
1695 
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  {
1718  }
1719 
1720  return ERROR_SUCCESS;
1721  }
1722  else
1723  {
1724  /* make sure we close all handles we created! */
1725  if (SubKeyHandle != NULL)
1726  {
1728  }
1729 
1730 Cleanup:
1732 
1733  return RtlNtStatusToDosError(Status);
1734  }
1735 }
1736 #endif
1737 
1738 
1739 /************************************************************************
1740  * RegDeleteTreeW
1741  *
1742  * @implemented
1743  */
1744 LSTATUS
1745 WINAPI
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 
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  {
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  {
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 
1829 
1830  return ret;
1831 }
1832 
1833 
1834 /************************************************************************
1835  * RegDeleteTreeA
1836  *
1837  * @implemented
1838  */
1839 LONG WINAPI
1841  IN LPCSTR lpSubKey OPTIONAL)
1842 {
1843  UNICODE_STRING SubKeyName = { 0, 0, NULL };
1844  LONG Ret;
1845 
1846  if (lpSubKey != NULL &&
1848  {
1849  return ERROR_NOT_ENOUGH_MEMORY;
1850  }
1851 
1852  Ret = RegDeleteTreeW(hKey,
1853  SubKeyName.Buffer);
1854 
1856 
1857  return Ret;
1858 }
1859 
1860 
1861 /************************************************************************
1862  * RegDisableReflectionKey
1863  *
1864  * @unimplemented
1865  */
1866 LONG WINAPI
1868 {
1869  FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1871 }
1872 
1873 
1874 /************************************************************************
1875  * RegEnableReflectionKey
1876  *
1877  * @unimplemented
1878  */
1879 LONG WINAPI
1881 {
1882  FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1884 }
1885 
1886 
1887 /******************************************************************************
1888  * RegpApplyRestrictions [internal]
1889  *
1890  * Helper function for RegGetValueA/W.
1891  */
1892 static VOID
1894  DWORD dwType,
1895  DWORD cbData,
1896  PLONG ret)
1897 {
1898  /* Check if the type is restricted by the passed flags */
1899  if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1900  {
1901  DWORD dwMask = 0;
1902 
1903  switch (dwType)
1904  {
1905  case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1906  case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1907  case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1908  case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1909  case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1910  case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1911  case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1912  }
1913 
1914  if (dwFlags & dwMask)
1915  {
1916  /* Type is not restricted, check for size mismatch */
1917  if (dwType == REG_BINARY)
1918  {
1919  DWORD cbExpect = 0;
1920 
1921  if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1922  cbExpect = 4;
1923  else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1924  cbExpect = 8;
1925 
1926  if (cbExpect && cbData != cbExpect)
1928  }
1929  }
1930  else *ret = ERROR_UNSUPPORTED_TYPE;
1931  }
1932 }
1933 
1934 
1935 /******************************************************************************
1936  * RegGetValueW [ADVAPI32.@]
1937  *
1938  * Retrieves the type and data for a value name associated with a key,
1939  * optionally expanding its content and restricting its type.
1940  *
1941  * PARAMS
1942  * hKey [I] Handle to an open key.
1943  * pszSubKey [I] Name of the subkey of hKey.
1944  * pszValue [I] Name of value under hKey/szSubKey to query.
1945  * dwFlags [I] Flags restricting the value type to retrieve.
1946  * pdwType [O] Destination for the values type, may be NULL.
1947  * pvData [O] Destination for the values content, may be NULL.
1948  * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1949  * retrieve the whole content, including the trailing '\0'
1950  * for strings.
1951  *
1952  * RETURNS
1953  * Success: ERROR_SUCCESS
1954  * Failure: nonzero error code from Winerror.h
1955  *
1956  * NOTES
1957  * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1958  * expanded and pdwType is set to REG_SZ instead.
1959  * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1960  * without RRF_NOEXPAND is thus not allowed.
1961  * An exception is the case where RRF_RT_ANY is specified, because then
1962  * RRF_NOEXPAND is allowed.
1963  */
1966  LPCWSTR pszSubKey,
1967  LPCWSTR pszValue,
1968  DWORD dwFlags,
1969  LPDWORD pdwType,
1970  PVOID pvData,
1971  LPDWORD pcbData)
1972 {
1973  DWORD dwType, cbData = pcbData ? *pcbData : 0;
1974  PVOID pvBuf = NULL;
1975  LONG ret;
1976 
1977  TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1978  hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1979  pvData, pcbData, cbData);
1980 
1981  if (pvData && !pcbData)
1982  return ERROR_INVALID_PARAMETER;
1984  ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1985  return ERROR_INVALID_PARAMETER;
1986 
1987  if (pszSubKey && pszSubKey[0])
1988  {
1989  ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1990  if (ret != ERROR_SUCCESS) return ret;
1991  }
1992 
1993  ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1994 
1995  /* If we are going to expand we need to read in the whole the value even
1996  * if the passed buffer was too small as the expanded string might be
1997  * smaller than the unexpanded one and could fit into cbData bytes. */
1998  if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1999  dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
2000  {
2001  do
2002  {
2003  HeapFree(GetProcessHeap(), 0, pvBuf);
2004 
2005  pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2006  if (!pvBuf)
2007  {
2009  break;
2010  }
2011 
2012  if (ret == ERROR_MORE_DATA || !pvData)
2013  ret = RegQueryValueExW(hKey, pszValue, NULL,
2014  &dwType, pvBuf, &cbData);
2015  else
2016  {
2017  /* Even if cbData was large enough we have to copy the
2018  * string since ExpandEnvironmentStrings can't handle
2019  * overlapping buffers. */
2020  CopyMemory(pvBuf, pvData, cbData);
2021  }
2022 
2023  /* Both the type or the value itself could have been modified in
2024  * between so we have to keep retrying until the buffer is large
2025  * enough or we no longer have to expand the value. */
2026  }
2027  while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2028 
2029  if (ret == ERROR_SUCCESS)
2030  {
2031  /* Recheck dwType in case it changed since the first call */
2032  if (dwType == REG_EXPAND_SZ)
2033  {
2034  cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2035  pcbData ? *pcbData : 0) * sizeof(WCHAR);
2036  dwType = REG_SZ;
2037  if (pvData && pcbData && cbData > *pcbData)
2038  ret = ERROR_MORE_DATA;
2039  }
2040  else if (pvData)
2041  CopyMemory(pvData, pvBuf, *pcbData);
2042  }
2043 
2044  HeapFree(GetProcessHeap(), 0, pvBuf);
2045  }
2046 
2047  if (pszSubKey && pszSubKey[0])
2048  RegCloseKey(hKey);
2049 
2050  RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2051 
2054 
2055  if (pdwType)
2056  *pdwType = dwType;
2057 
2058  if (pcbData)
2059  *pcbData = cbData;
2060 
2061  return ret;
2062 }
2063 
2064 
2065 /******************************************************************************
2066  * RegGetValueA [ADVAPI32.@]
2067  *
2068  * See RegGetValueW.
2069  */
2072  LPCSTR pszSubKey,
2073  LPCSTR pszValue,
2074  DWORD dwFlags,
2075  LPDWORD pdwType,
2076  PVOID pvData,
2077  LPDWORD pcbData)
2078 {
2079  DWORD dwType, cbData = pcbData ? *pcbData : 0;
2080  PVOID pvBuf = NULL;
2081  LONG ret;
2082 
2083  TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2084  hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2085  cbData);
2086 
2087  if (pvData && !pcbData)
2088  return ERROR_INVALID_PARAMETER;
2090  ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2091  return ERROR_INVALID_PARAMETER;
2092 
2093  if (pszSubKey && pszSubKey[0])
2094  {
2095  ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2096  if (ret != ERROR_SUCCESS) return ret;
2097  }
2098 
2099  ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2100 
2101  /* If we are going to expand we need to read in the whole the value even
2102  * if the passed buffer was too small as the expanded string might be
2103  * smaller than the unexpanded one and could fit into cbData bytes. */
2104  if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2105  (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2106  {
2107  do {
2108  HeapFree(GetProcessHeap(), 0, pvBuf);
2109 
2110  pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2111  if (!pvBuf)
2112  {
2114  break;
2115  }
2116 
2117  if (ret == ERROR_MORE_DATA || !pvData)
2118  ret = RegQueryValueExA(hKey, pszValue, NULL,
2119  &dwType, pvBuf, &cbData);
2120  else
2121  {
2122  /* Even if cbData was large enough we have to copy the
2123  * string since ExpandEnvironmentStrings can't handle
2124  * overlapping buffers. */
2125  CopyMemory(pvBuf, pvData, cbData);
2126  }
2127 
2128  /* Both the type or the value itself could have been modified in
2129  * between so we have to keep retrying until the buffer is large
2130  * enough or we no longer have to expand the value. */
2131  } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2132 
2133  if (ret == ERROR_SUCCESS)
2134  {
2135  /* Recheck dwType in case it changed since the first call */
2136  if (dwType == REG_EXPAND_SZ)
2137  {
2138  cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2139  pcbData ? *pcbData : 0);
2140  dwType = REG_SZ;
2141  if(pvData && pcbData && cbData > *pcbData)
2142  ret = ERROR_MORE_DATA;
2143  }
2144  else if (pvData)
2145  CopyMemory(pvData, pvBuf, *pcbData);
2146  }
2147 
2148  HeapFree(GetProcessHeap(), 0, pvBuf);
2149  }
2150 
2151  if (pszSubKey && pszSubKey[0])
2152  RegCloseKey(hKey);
2153 
2154  RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2155 
2158 
2159  if (pdwType) *pdwType = dwType;
2160  if (pcbData) *pcbData = cbData;
2161 
2162  return ret;
2163 }
2164 
2165 
2166 /************************************************************************
2167  * RegSetKeyValueW
2168  *
2169  * @implemented
2170  */
2171 LONG WINAPI
2173  IN LPCWSTR lpSubKey OPTIONAL,
2174  IN LPCWSTR lpValueName OPTIONAL,
2175  IN DWORD dwType,
2176  IN LPCVOID lpData OPTIONAL,
2177  IN DWORD cbData)
2178 {
2179  HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2180  NTSTATUS Status;
2181  LONG Ret;
2182 
2184  hKey);
2185  if (!NT_SUCCESS(Status))
2186  {
2187  return RtlNtStatusToDosError(Status);
2188  }
2189 
2190  if (lpSubKey != NULL)
2191  {
2194 
2195  RtlInitUnicodeString(&SubKeyName, lpSubKey);
2196 
2198  &SubKeyName,
2200  KeyHandle,
2201  NULL);
2202 
2204  KEY_SET_VALUE,
2205  &ObjectAttributes);
2206  if (!NT_SUCCESS(Status))
2207  {
2209  goto Cleanup;
2210  }
2211 
2212  CurKey = SubKeyHandle;
2213  }
2214  else
2215  CurKey = KeyHandle;
2216 
2217  Ret = RegSetValueExW(CurKey,
2218  lpValueName,
2219  0,
2220  dwType,
2221  lpData,
2222  cbData);
2223 
2224  if (SubKeyHandle != NULL)
2225  {
2227  }
2228 
2229 Cleanup:
2231 
2232  return Ret;
2233 }
2234 
2235 
2236 /************************************************************************
2237  * RegSetKeyValueA
2238  *
2239  * @implemented
2240  */
2241 LONG WINAPI
2243  IN LPCSTR lpSubKey OPTIONAL,
2244  IN LPCSTR lpValueName OPTIONAL,
2245  IN DWORD dwType,
2246  IN LPCVOID lpData OPTIONAL,
2247  IN DWORD cbData)
2248 {
2249  HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2250  NTSTATUS Status;
2251  LONG Ret;
2252 
2254  hKey);
2255  if (!NT_SUCCESS(Status))
2256  {
2257  return RtlNtStatusToDosError(Status);
2258  }
2259 
2260  if (lpSubKey != NULL)
2261  {
2264 
2266  {
2268  goto Cleanup;
2269  }
2270 
2272  &SubKeyName,
2274  KeyHandle,
2275  NULL);
2276 
2278  KEY_SET_VALUE,
2279  &ObjectAttributes);
2280 
2282 
2283  if (!NT_SUCCESS(Status))
2284  {
2286  goto Cleanup;
2287  }
2288 
2289  CurKey = SubKeyHandle;
2290  }
2291  else
2292  CurKey = KeyHandle;
2293 
2294  Ret = RegSetValueExA(CurKey,
2295  lpValueName,
2296  0,
2297  dwType,
2298  lpData,
2299  cbData);
2300 
2301  if (SubKeyHandle != NULL)
2302  {
2304  }
2305 
2306 Cleanup:
2308 
2309  return Ret;
2310 }
2311 
2312 
2313 /************************************************************************
2314  * RegDeleteValueA
2315  *
2316  * @implemented
2317  */
2318 LONG WINAPI
2320  LPCSTR lpValueName)
2321 {
2323  HANDLE KeyHandle;
2324  NTSTATUS Status;
2325 
2327  hKey);
2328  if (!NT_SUCCESS(Status))
2329  {
2330  return RtlNtStatusToDosError(Status);
2331  }
2332 
2335  &ValueName);
2337 
2339 
2340  if (!NT_SUCCESS(Status))
2341  {
2342  return RtlNtStatusToDosError(Status);
2343  }
2344 
2345  return ERROR_SUCCESS;
2346 }
2347 
2348 
2349 /************************************************************************
2350  * RegDeleteValueW
2351  *
2352  * @implemented
2353  */
2354 LONG WINAPI
2356  LPCWSTR lpValueName)
2357 {
2359  NTSTATUS Status;
2360  HANDLE KeyHandle;
2361 
2363  hKey);
2364  if (!NT_SUCCESS(Status))
2365  {
2366  return RtlNtStatusToDosError(Status);
2367  }
2368 
2369  RtlInitUnicodeString(&ValueName, lpValueName);
2370 
2372  &ValueName);
2373 
2375 
2376  if (!NT_SUCCESS(Status))
2377  {
2378  return RtlNtStatusToDosError(Status);
2379  }
2380 
2381  return ERROR_SUCCESS;
2382 }
2383 
2384 
2385 /************************************************************************
2386  * RegEnumKeyA
2387  *
2388  * @implemented
2389  */
2390 LONG WINAPI
2392  DWORD dwIndex,
2393  LPSTR lpName,
2394  DWORD cbName)
2395 {
2396  DWORD dwLength;
2397 
2398  dwLength = cbName;
2399  return RegEnumKeyExA(hKey,
2400  dwIndex,
2401  lpName,
2402  &dwLength,
2403  NULL,
2404  NULL,
2405  NULL,
2406  NULL);
2407 }
2408 
2409 
2410 /************************************************************************
2411  * RegEnumKeyW
2412  *
2413  * @implemented
2414  */
2415 LONG WINAPI
2417  DWORD dwIndex,
2418  LPWSTR lpName,
2419  DWORD cbName)
2420 {
2421  DWORD dwLength;
2422 
2423  dwLength = cbName;
2424  return RegEnumKeyExW(hKey,
2425  dwIndex,
2426  lpName,
2427  &dwLength,
2428  NULL,
2429  NULL,
2430  NULL,
2431  NULL);
2432 }
2433 
2434 
2435 /************************************************************************
2436  * RegEnumKeyExA
2437  *
2438  * @implemented
2439  */
2440 LONG
2441 WINAPI
2443  _In_ HKEY hKey,
2444  _In_ DWORD dwIndex,
2445  _Out_ LPSTR lpName,
2446  _Inout_ LPDWORD lpcbName,
2447  _Reserved_ LPDWORD lpReserved,
2448  _Out_opt_ LPSTR lpClass,
2449  _Inout_opt_ LPDWORD lpcbClass,
2450  _Out_opt_ PFILETIME lpftLastWriteTime)
2451 {
2452  WCHAR* NameBuffer = NULL;
2453  WCHAR* ClassBuffer = NULL;
2454  DWORD NameLength, ClassLength;
2455  LONG ErrorCode;
2456 
2457  /* Allocate our buffers */
2458  if (*lpcbName > 0)
2459  {
2460  NameLength = *lpcbName;
2461  NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR));
2462  if (NameBuffer == NULL)
2463  {
2465  goto Exit;
2466  }
2467  }
2468 
2469  if (lpClass)
2470  {
2471  if (*lpcbClass > 0)
2472  {
2473  ClassLength = *lpcbClass;
2474  ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR));
2475  if (ClassBuffer == NULL)
2476  {
2478  goto Exit;
2479  }
2480  }
2481  }
2482 
2483  /* Do the actual call */
2485  hKey,
2486  dwIndex,
2487  NameBuffer,
2488  lpcbName,
2489  lpReserved,
2490  ClassBuffer,
2491  lpcbClass,
2492  lpftLastWriteTime);
2493 
2494  if (ErrorCode != ERROR_SUCCESS)
2495  goto Exit;
2496 
2497  /* Convert the strings */
2498  RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR));
2499  /* NULL terminate if we can */
2500  if (NameLength > *lpcbName)
2501  lpName[*lpcbName] = '\0';
2502 
2503  if (lpClass)
2504  {
2505  RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR));
2506  if (ClassLength > *lpcbClass)
2507  lpClass[*lpcbClass] = '\0';
2508  }
2509 
2510 Exit:
2511  if (NameBuffer)
2512  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2513  if (ClassBuffer)
2514  RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
2515 
2516  return ErrorCode;
2517 }
2518 
2519 
2520 /************************************************************************
2521  * RegEnumKeyExW
2522  *
2523  * @implemented
2524  */
2525 LONG
2526 WINAPI
2528  _In_ HKEY hKey,
2529  _In_ DWORD dwIndex,
2531  _Inout_ LPDWORD lpcbName,
2532  _Reserved_ LPDWORD lpReserved,
2533  _Out_opt_ LPWSTR lpClass,
2534  _Inout_opt_ LPDWORD lpcbClass,
2535  _Out_opt_ PFILETIME lpftLastWriteTime)
2536 {
2537  union
2538  {
2540  KEY_BASIC_INFORMATION Basic;
2541  } *KeyInfo;
2542 
2543  ULONG BufferSize;
2544  ULONG ResultSize;
2545  ULONG NameLength;
2546  ULONG ClassLength = 0;
2547  HANDLE KeyHandle;
2549  NTSTATUS Status;
2550 
2552  hKey);
2553  if (!NT_SUCCESS(Status))
2554  {
2555  return RtlNtStatusToDosError(Status);
2556  }
2557 
2558  if (IsHKCRKey(KeyHandle))
2559  {
2561  KeyHandle,
2562  dwIndex,
2563  lpName,
2564  lpcbName,
2565  lpReserved,
2566  lpClass,
2567  lpcbClass,
2568  lpftLastWriteTime);
2570  return ErrorCode;
2571  }
2572 
2573  if (*lpcbName > 0)
2574  {
2575  NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2576  }
2577  else
2578  {
2579  NameLength = 0;
2580  }
2581 
2582  if (lpClass)
2583  {
2584  if (*lpcbClass > 0)
2585  {
2586  ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2587  }
2588  else
2589  {
2590  ClassLength = 0;
2591  }
2592 
2593  BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2594  }
2595  else
2596  {
2597  BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2598  }
2599 
2600  KeyInfo = RtlAllocateHeap(ProcessHeap,
2601  0,
2602  BufferSize);
2603  if (KeyInfo == NULL)
2604  {
2606  goto Cleanup;
2607  }
2608 
2610  (ULONG)dwIndex,
2612  KeyInfo,
2613  BufferSize,
2614  &ResultSize);
2615  TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2616  if (!NT_SUCCESS(Status))
2617  {
2619  }
2620  else
2621  {
2622  if (lpClass == NULL)
2623  {
2624  if (KeyInfo->Basic.NameLength > NameLength)
2625  {
2627  }
2628  else
2629  {
2631  KeyInfo->Basic.Name,
2632  KeyInfo->Basic.NameLength);
2633  *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2634  lpName[*lpcbName] = 0;
2635  }
2636  }
2637  else
2638  {
2639  if (KeyInfo->Node.NameLength > NameLength ||
2640  KeyInfo->Node.ClassLength > ClassLength)
2641  {
2643  }
2644  else
2645  {
2647  KeyInfo->Node.Name,
2648  KeyInfo->Node.NameLength);
2649  *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2650  lpName[*lpcbName] = 0;
2651  RtlCopyMemory(lpClass,
2652  (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2653  KeyInfo->Node.ClassLength);
2654  *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2655  lpClass[*lpcbClass] = 0;
2656  }
2657  }
2658 
2659  if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2660  {
2661  if (lpClass == NULL)
2662  {
2663  lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2664  lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2665  }
2666  else
2667  {
2668  lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2669  lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2670  }
2671  }
2672  }
2673 
2675  0,
2676  KeyInfo);
2677 
2678 Cleanup:
2680 
2681  return ErrorCode;
2682 }
2683 
2684 
2685 /************************************************************************
2686  * RegEnumValueA
2687  *
2688  * @implemented
2689  */
2690 LONG WINAPI
2692  _In_ HKEY hKey,
2693  _In_ DWORD dwIndex,
2694  _Out_ LPSTR lpName,
2695  _Inout_ LPDWORD lpcbName,
2696  _Reserved_ LPDWORD lpdwReserved,
2697  _Out_opt_ LPDWORD lpdwType,
2698  _Out_opt_ LPBYTE lpData,
2699  _Inout_opt_ LPDWORD lpcbData)
2700 {
2701  WCHAR* NameBuffer;
2702  DWORD NameBufferSize, NameLength;
2703  LONG ErrorCode;
2704  DWORD LocalType = REG_NONE;
2705  BOOL NameOverflow = FALSE;
2706 
2707  /* Do parameter checks now, once and for all. */
2708  if (!lpName || !lpcbName)
2709  return ERROR_INVALID_PARAMETER;
2710 
2711  if ((lpData && !lpcbData) || lpdwReserved)
2712  return ERROR_INVALID_PARAMETER;
2713 
2714  /* Get the size of the buffer we must use for the first call to RegEnumValueW */
2716  hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
2717  if (ErrorCode != ERROR_SUCCESS)
2718  return ErrorCode;
2719 
2720  /* Add space for the null terminator */
2721  NameBufferSize++;
2722 
2723  /* Allocate the buffer for the unicode name */
2724  NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR));
2725  if (NameBuffer == NULL)
2726  {
2727  return ERROR_NOT_ENOUGH_MEMORY;
2728  }
2729 
2730  /*
2731  * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
2732  * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
2733  * is an overflow on the data or on the name during the the second call. So the first time, we make the
2734  * call with the supplied value. This is merdique, but this is how it is.
2735  */
2736  NameLength = *lpcbName;
2738  hKey,
2739  dwIndex,
2740  NameBuffer,
2741  &NameLength,
2742  NULL,
2743  &LocalType,
2744  NULL,
2745  NULL);
2746  if (ErrorCode != ERROR_SUCCESS)
2747  {
2748  if (ErrorCode == ERROR_MORE_DATA)
2749  NameOverflow = TRUE;
2750  else
2751  goto Exit;
2752  }
2753 
2754  if (is_string(LocalType) && lpcbData)
2755  {
2756  /* We must allocate a buffer to get the unicode data */
2757  DWORD DataBufferSize = *lpcbData * sizeof(WCHAR);
2758  WCHAR* DataBuffer = NULL;
2759  DWORD DataLength = *lpcbData;
2760  LPSTR DataStr = (LPSTR)lpData;
2761 
2762  if (lpData)
2763  DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR));
2764 
2765  /* Do the real call */
2767  hKey,
2768  dwIndex,
2769  NameBuffer,
2770  &NameBufferSize,
2771  lpdwReserved,
2772  lpdwType,
2773  (LPBYTE)DataBuffer,
2774  &DataBufferSize);
2775 
2776  *lpcbData = DataBufferSize / sizeof(WCHAR);
2777 
2778  if (ErrorCode != ERROR_SUCCESS)
2779  {
2780  RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2781  goto Exit;
2782  }
2783 
2784  /* Copy the data whatever the error code is */
2785  if (lpData)
2786  {
2787  /* Do the data conversion */
2788  RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize);
2789  /* NULL-terminate if there is enough room */
2790  if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0'))
2791  DataStr[*lpcbData] = '\0';
2792  }
2793 
2794  RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2795  }
2796  else
2797  {
2798  /* No data conversion needed. Do the call with provided buffers */
2800  hKey,
2801  dwIndex,
2802  NameBuffer,
2803  &NameBufferSize,
2804  lpdwReserved,
2805  lpdwType,
2806  lpData,
2807  lpcbData);
2808 
2809  if (ErrorCode != ERROR_SUCCESS)
2810  {
2811  goto Exit;
2812  }
2813  }
2814 
2815  if (NameOverflow)
2816  {
2818  goto Exit;
2819  }
2820 
2821  /* Convert the name string */
2822  RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR));
2823  lpName[*lpcbName] = ANSI_NULL;
2824 
2825 Exit:
2826  if (NameBuffer)
2827  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2828 
2829  return ErrorCode;
2830 }
2831 
2832 
2833 /******************************************************************************
2834  * RegEnumValueW [ADVAPI32.@]
2835  * @implemented
2836  *
2837  * PARAMS
2838  * hkey [I] Handle to key to query
2839  * index [I] Index of value to query
2840  * value [O] Value string
2841  * val_count [I/O] Size of value buffer (in wchars)
2842  * reserved [I] Reserved
2843  * type [O] Type code
2844  * data [O] Value data
2845  * count [I/O] Size of data buffer (in bytes)
2846  *
2847  * RETURNS
2848  * Success: ERROR_SUCCESS
2849  * Failure: nonzero error code from Winerror.h
2850  */
2851 LONG
2852 WINAPI
2854  _In_ HKEY hKey,
2855  _In_ DWORD index,
2856  _Out_ LPWSTR value,
2857  _Inout_ PDWORD val_count,
2862 {
2863  HANDLE KeyHandle;
2864  NTSTATUS status;
2865  ULONG total_size;
2866  char buffer[256], *buf_ptr = buffer;
2868  static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2869 
2870  TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2871  hKey, index, value, val_count, reserved, type, data, count );
2872 
2873  if (!value || !val_count)
2874  return ERROR_INVALID_PARAMETER;
2875 
2876  if ((data && !count) || reserved)
2877  return ERROR_INVALID_PARAMETER;
2878 
2880  if (!NT_SUCCESS(status))
2881  {
2882  return RtlNtStatusToDosError(status);
2883  }
2884 
2885  if (IsHKCRKey(KeyHandle))
2886  {
2888  KeyHandle,
2889  index,
2890  value,
2891  val_count,
2892  reserved,
2893  type,
2894  data,
2895  count);
2897  return ErrorCode;
2898  }
2899 
2900  total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2901  if (data) total_size += *count;
2902  total_size = min( sizeof(buffer), total_size );
2903 
2905  buffer, total_size, &total_size );
2906  if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
2907 
2908  if (value || data)
2909  {
2910  /* retry with a dynamically allocated buffer */
2912  {
2913  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2914  if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2915  {
2917  goto done;
2918  }
2919  info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2921  buf_ptr, total_size, &total_size );
2922  }
2923 
2924  if (status) goto done;
2925 
2926  if (value)
2927  {
2928  if (info->NameLength/sizeof(WCHAR) >= *val_count)
2929  {
2931  goto overflow;
2932  }
2933  memcpy( value, info->Name, info->NameLength );
2934  *val_count = info->NameLength / sizeof(WCHAR);
2935  value[*val_count] = 0;
2936  }
2937 
2938  if (data)
2939  {
2940  if (info->DataLength > *count)
2941  {
2943  goto overflow;
2944  }
2945  memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
2946  if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
2947  {
2948  /* if the type is REG_SZ and data is not 0-terminated
2949  * and there is enough space in the buffer NT appends a \0 */
2950  WCHAR *ptr = (WCHAR *)(data + info->DataLength);
2951  if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2952  }
2953  }
2954  }
2955  else status = STATUS_SUCCESS;
2956 
2957  overflow:
2958  if (type) *type = info->Type;
2959  if (count) *count = info->DataLength;
2960 
2961  done:
2962  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2964  return RtlNtStatusToDosError(status);
2965 }
2966 
2967 
2968 /************************************************************************
2969  * RegFlushKey
2970  *
2971  * @implemented
2972  */
2973 LONG WINAPI
2975 {
2976  HANDLE KeyHandle;
2977  NTSTATUS Status;
2978 
2979  if (hKey == HKEY_PERFORMANCE_DATA)
2980  {
2981  return ERROR_SUCCESS;
2982  }
2983 
2985  hKey);
2986  if (!NT_SUCCESS(Status))
2987  {
2988  return RtlNtStatusToDosError(Status);
2989  }
2990 
2992 
2994 
2995  if (!NT_SUCCESS(Status))
2996  {
2997  return RtlNtStatusToDosError(Status);
2998  }
2999 
3000  return ERROR_SUCCESS;
3001 }
3002 
3003 
3004 /************************************************************************
3005  * RegGetKeySecurity
3006  *
3007  * @implemented
3008  */
3009 LONG WINAPI
3012  PSECURITY_DESCRIPTOR pSecurityDescriptor,
3013  LPDWORD lpcbSecurityDescriptor)
3014 {
3015  HANDLE KeyHandle;
3016  NTSTATUS Status;
3017 
3018  if (hKey == HKEY_PERFORMANCE_DATA)
3019  {
3020  return ERROR_INVALID_HANDLE;
3021  }
3022 
3024  hKey);
3025  if (!NT_SUCCESS(Status))
3026  {
3027  TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3028  return RtlNtStatusToDosError(Status);
3029  }
3030 
3033  pSecurityDescriptor,
3034  *lpcbSecurityDescriptor,
3035  lpcbSecurityDescriptor);
3036 
3038 
3039  if (!NT_SUCCESS(Status))
3040  {
3041  WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3042  return RtlNtStatusToDosError(Status);
3043  }
3044 
3045  return ERROR_SUCCESS;
3046 }
3047 
3048 
3049 /************************************************************************
3050  * RegLoadKeyA
3051  *
3052  * @implemented
3053  */
3054 LONG WINAPI
3056  LPCSTR lpSubKey,
3057  LPCSTR lpFile)
3058 {
3061  LONG ErrorCode;
3062 
3063  RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
3064  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
3065 
3066  if (lpSubKey)
3067  {
3068  if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
3069  {
3071  goto Exit;
3072  }
3073  }
3074 
3075  if (lpFile)
3076  {
3078  {
3080  goto Exit;
3081  }
3082  }
3083 
3085  KeyName.Buffer,
3086  FileName.Buffer);
3087 
3088 Exit:
3091 
3092  return ErrorCode;
3093 }
3094 
3095 
3096 /************************************************************************
3097  * RegLoadKeyW
3098  *
3099  * @implemented
3100  */
3101 LONG WINAPI
3103  LPCWSTR lpSubKey,
3104  LPCWSTR lpFile)
3105 {
3107  OBJECT_ATTRIBUTES KeyObjectAttributes;
3110  HANDLE KeyHandle;
3111  NTSTATUS Status;
3113 
3114  if (hKey == HKEY_PERFORMANCE_DATA)
3115  {
3116  return ERROR_INVALID_HANDLE;
3117  }
3118 
3120  hKey);
3121  if (!NT_SUCCESS(Status))
3122  {
3123  return RtlNtStatusToDosError(Status);
3124  }
3125 
3126  if (!RtlDosPathNameToNtPathName_U(lpFile,
3127  &FileName,
3128  NULL,
3129  NULL))
3130  {
3132  goto Cleanup;
3133  }
3134 
3136  &FileName,
3138  NULL,
3139  NULL);
3140 
3141  RtlInitUnicodeString(&KeyName, lpSubKey);
3142 
3143  InitializeObjectAttributes(&KeyObjectAttributes,
3144  &KeyName,
3146  KeyHandle,
3147  NULL);
3148 
3149  Status = NtLoadKey(&KeyObjectAttributes,
3151 
3152  RtlFreeHeap(RtlGetProcessHeap(),
3153  0,
3154  FileName.Buffer);
3155 
3156  if (!NT_SUCCESS(Status))
3157  {
3159  goto Cleanup;
3160  }
3161 
3162 Cleanup:
3164 
3165  return ErrorCode;
3166 }
3167 
3168 
3169 /************************************************************************
3170  * RegNotifyChangeKeyValue
3171  *
3172  * @unimplemented
3173  */
3174 LONG WINAPI
3176  BOOL bWatchSubtree,
3177  DWORD dwNotifyFilter,
3178  HANDLE hEvent,
3179  BOOL fAsynchronous)
3180 {
3182  HANDLE KeyHandle;
3183  NTSTATUS Status;
3185 
3186  if (hKey == HKEY_PERFORMANCE_DATA)
3187  {
3188  return ERROR_INVALID_HANDLE;
3189  }
3190 
3191  if ((fAsynchronous != FALSE) && (hEvent == NULL))
3192  {
3193  return ERROR_INVALID_PARAMETER;
3194  }
3195 
3197  hKey);
3198  if (!NT_SUCCESS(Status))
3199  {
3200  return RtlNtStatusToDosError(Status);
3201  }
3202 
3203  /* FIXME: Remote key handles must fail */
3204 
3206  hEvent,
3207  0,
3208  0,
3209  &IoStatusBlock,
3210  dwNotifyFilter,
3211  bWatchSubtree,
3212  0,
3213  0,
3214  fAsynchronous);
3215  if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3216  {
3218  }
3219 
3221 
3222  return ErrorCode;
3223 }
3224 
3225 
3226 /************************************************************************
3227  * RegOpenCurrentUser
3228  *
3229  * @implemented
3230  */
3231 LONG WINAPI
3233  OUT PHKEY phkResult)
3234 {
3235  NTSTATUS Status;
3236 
3237  Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3238  (PHANDLE)phkResult);
3239  if (!NT_SUCCESS(Status))
3240  {
3241  /* NOTE - don't set the last error code! just return the error! */
3242  return RtlNtStatusToDosError(Status);
3243  }
3244 
3245  return ERROR_SUCCESS;
3246 }
3247 
3248 
3249 /************************************************************************
3250  * RegOpenKeyA
3251  *
3252  * 20050503 Fireball - imported from WINE
3253  *
3254  * @implemented
3255  */
3256 LONG WINAPI
3258  LPCSTR lpSubKey,
3259  PHKEY phkResult)
3260 {
3261  TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3262  hKey, lpSubKey, phkResult);
3263 
3264  if (!phkResult)
3265  return ERROR_INVALID_PARAMETER;
3266 
3267  if (!hKey && !lpSubKey)
3268  {
3269  *phkResult = hKey;
3270  return ERROR_SUCCESS;
3271  }
3272 
3273  return RegOpenKeyExA(hKey,
3274  lpSubKey,
3275  0,
3277  phkResult);
3278 }
3279 
3280 
3281 /************************************************************************
3282  * RegOpenKeyW
3283  *
3284  * 19981101 Ariadne
3285  * 19990525 EA
3286  * 20050503 Fireball - imported from WINE
3287  *
3288  * @implemented
3289  */
3290 LONG WINAPI
3292  LPCWSTR lpSubKey,
3293  PHKEY phkResult)
3294 {
3295  TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3296  hKey, lpSubKey, phkResult);
3297 
3298  if (!phkResult)
3299  return ERROR_INVALID_PARAMETER;
3300 
3301  if (!hKey && !lpSubKey)
3302  {
3303  *phkResult = hKey;
3304  return ERROR_SUCCESS;
3305  }
3306 
3307  return RegOpenKeyExW(hKey,
3308  lpSubKey,
3309  0,
3311  phkResult);
3312 }
3313 
3314 
3315 /************************************************************************
3316  * RegOpenKeyExA
3317  *
3318  * @implemented
3319  */
3320 LONG WINAPI
3322  _In_ HKEY hKey,
3323  _In_ LPCSTR lpSubKey,
3324  _In_ DWORD ulOptions,
3325  _In_ REGSAM samDesired,
3326  _Out_ PHKEY phkResult)
3327 {
3328  UNICODE_STRING SubKeyString;
3329  LONG ErrorCode;
3330 
3331  TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3332  hKey, lpSubKey, ulOptions, samDesired, phkResult);
3333 
3334  if (lpSubKey)
3335  {
3336  if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
3337  return ERROR_NOT_ENOUGH_MEMORY;
3338  }
3339  else
3340  RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
3341 
3342  ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
3343 
3344  RtlFreeUnicodeString(&SubKeyString);
3345 
3346  return ErrorCode;
3347 }
3348 
3349 
3350 /************************************************************************
3351  * RegOpenKeyExW
3352  *
3353  * @implemented
3354  */
3355 LONG WINAPI
3357  LPCWSTR lpSubKey,
3358  DWORD ulOptions,
3359  REGSAM samDesired,
3360  PHKEY phkResult)
3361 {
3363  UNICODE_STRING SubKeyString;
3364  HANDLE KeyHandle;
3365  NTSTATUS Status;
3368 
3369  TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3370  hKey, lpSubKey, ulOptions, samDesired, phkResult);
3371  if (!phkResult)
3372  {
3373  return ERROR_INVALID_PARAMETER;
3374  }
3375 
3376  if (!hKey && lpSubKey && phkResult)
3377  {
3378  return ERROR_INVALID_HANDLE;
3379  }
3380 
3381  if (IsPredefKey(hKey) && (!lpSubKey || !*lpSubKey))
3382  {
3383  *phkResult = hKey;
3384  return ERROR_SUCCESS;
3385  }
3386 
3388  if (!NT_SUCCESS(Status))
3389  {
3390  return RtlNtStatusToDosError(Status);
3391  }
3392 
3393  if (IsHKCRKey(KeyHandle))
3394  {
3395  ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
3397  return ErrorCode;
3398  }
3399 
3400  if (ulOptions & REG_OPTION_OPEN_LINK)
3402 
3403  if (lpSubKey == NULL || wcscmp(lpSubKey, L"\\") == 0)
3404  RtlInitUnicodeString(&SubKeyString, L"");
3405  else
3406  RtlInitUnicodeString(&SubKeyString, lpSubKey);
3407 
3409  &SubKeyString,
3410  Attributes,
3411  KeyHandle,
3412  NULL);
3413 
3414  Status = NtOpenKey((PHANDLE)phkResult,
3415  samDesired,
3416  &ObjectAttributes);
3417 
3419  {
3420  HANDLE hAligned;
3421  UNICODE_STRING AlignedString;
3422 
3424  &SubKeyString,
3425  &AlignedString);
3426  if (NT_SUCCESS(Status))
3427  {
3428  /* Try again with aligned parameters */
3430  &AlignedString,
3431  Attributes,
3432  KeyHandle,
3433  NULL);
3434 
3435  Status = NtOpenKey(&hAligned,
3436  samDesired,
3437  &ObjectAttributes);
3438 
3439  RtlFreeUnicodeString(&AlignedString);
3440 
3441  if (NT_SUCCESS(Status))
3442  *phkResult = hAligned;
3443  }
3444  else
3445  {
3446  /* Restore the original error */
3448  }
3449  }
3450 
3451  if (!NT_SUCCESS(Status))
3452  {
3454  }
3455 
3456 
3458 
3459  return ErrorCode;
3460 }
3461 
3462 
3463 /************************************************************************
3464  * RegOpenUserClassesRoot
3465  *
3466  * @implemented
3467  */
3468 LONG WINAPI
3470  IN DWORD dwOptions,
3471  IN REGSAM samDesired,
3472  OUT PHKEY phkResult)
3473 {
3474  const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3475  const WCHAR UserClassesKeySuffix[] = L"_Classes";
3476  PTOKEN_USER TokenUserData;
3478  UNICODE_STRING UserSidString, UserClassesKeyRoot;
3480  NTSTATUS Status;
3481 
3482  /* check parameters */
3483  if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3484  {
3485  return ERROR_INVALID_PARAMETER;
3486  }
3487 
3488  /*
3489  * Get the user sid from the token
3490  */
3491 
3492 ReadTokenSid:
3493  /* determine how much memory we need */
3495  TokenUser,
3496  NULL,
3497  0,
3498  &RequiredLength);
3500  {
3501  /* NOTE - as opposed to all other registry functions windows does indeed
3502  change the last error code in case the caller supplied a invalid
3503  handle for example! */
3504  return RtlNtStatusToDosError(Status);
3505  }
3506  RegInitialize(); /* HACK until delay-loading is implemented */
3507  TokenUserData = RtlAllocateHeap(ProcessHeap,
3508  0,
3509  RequiredLength);
3510  if (TokenUserData == NULL)
3511  {
3512  return ERROR_NOT_ENOUGH_MEMORY;
3513  }
3514 
3515  /* attempt to read the information */
3517  TokenUser,
3518  TokenUserData,
3520  &RequiredLength);
3521  if (!NT_SUCCESS(Status))
3522  {
3524  0,
3525  TokenUserData);
3527  {
3528  /* the information appears to have changed?! try again */
3529  goto ReadTokenSid;
3530  }
3531 
3532  /* NOTE - as opposed to all other registry functions windows does indeed
3533  change the last error code in case the caller supplied a invalid
3534  handle for example! */
3535  return RtlNtStatusToDosError(Status);
3536  }
3537 
3538  /*
3539  * Build the absolute path for the user's registry in the form
3540  * "\Registry\User<SID>_Classes"
3541  */
3542  Status = RtlConvertSidToUnicodeString(&UserSidString,
3543  TokenUserData->User.Sid,
3544  TRUE);
3545 
3546  /* we don't need the user data anymore, free it */
3548  0,
3549  TokenUserData);
3550 
3551  if (!NT_SUCCESS(Status))
3552  {
3553  return RtlNtStatusToDosError(Status);
3554  }
3555 
3556  /* allocate enough memory for the entire key string */
3557  UserClassesKeyRoot.Length = 0;
3558  UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3559  sizeof(UserClassesKeyPrefix) +
3560  sizeof(UserClassesKeySuffix);
3561  UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3562  0,
3563  UserClassesKeyRoot.MaximumLength);
3564  if (UserClassesKeyRoot.Buffer == NULL)
3565  {
3566  RtlFreeUnicodeString(&UserSidString);
3567  return RtlNtStatusToDosError(Status);
3568  }
3569 
3570  /* build the string */
3571  RtlAppendUnicodeToString(&UserClassesKeyRoot,
3572  UserClassesKeyPrefix);
3573  RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3574  &UserSidString);
3575  RtlAppendUnicodeToString(&UserClassesKeyRoot,
3576  UserClassesKeySuffix);
3577 
3578  TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3579 
3580  /*
3581  * Open the key
3582  */
3584  &UserClassesKeyRoot,
3586  NULL,
3587  NULL);
3588 
3589  Status = NtOpenKey((PHANDLE)phkResult,
3590  samDesired,
3591  &ObjectAttributes);
3592 
3593  RtlFreeUnicodeString(&UserSidString);
3594  RtlFreeUnicodeString(&UserClassesKeyRoot);
3595 
3596  if (!NT_SUCCESS(Status))
3597  {
3598  return RtlNtStatusToDosError(Status);
3599  }
3600 
3601  return ERROR_SUCCESS;
3602 }
3603 
3604 
3605 /************************************************************************
3606  * RegQueryInfoKeyA
3607  *
3608  * @implemented
3609  */
3610 LONG WINAPI
3612  LPSTR lpClass,
3613  LPDWORD lpcClass,
3614  LPDWORD lpReserved,
3615  LPDWORD lpcSubKeys,
3616  LPDWORD lpcMaxSubKeyLen,
3617  LPDWORD lpcMaxClassLen,
3618  LPDWORD lpcValues,
3619  LPDWORD lpcMaxValueNameLen,
3620  LPDWORD lpcMaxValueLen,
3621  LPDWORD lpcbSecurityDescriptor,
3622  PFILETIME lpftLastWriteTime)
3623 {
3624  WCHAR ClassName[MAX_PATH];
3627  LONG ErrorCode;
3628  NTSTATUS Status;
3629  DWORD cClass = 0;
3630 
3631  if ((lpClass) && (!lpcClass))
3632  {
3633  return ERROR_INVALID_PARAMETER;
3634  }
3635 
3637  NULL);
3638  if (lpClass != NULL)
3639  {
3640  RtlInitEmptyUnicodeString(&UnicodeString,
3641  ClassName,
3642  sizeof(ClassName));
3643  cClass = sizeof(ClassName) / sizeof(WCHAR);
3644  }
3645 
3647  UnicodeString.Buffer,
3648  &cClass,
3649  lpReserved,
3650  lpcSubKeys,
3651  lpcMaxSubKeyLen,
3652  lpcMaxClassLen,
3653  lpcValues,
3654  lpcMaxValueNameLen,
3655  lpcMaxValueLen,
3656  lpcbSecurityDescriptor,
3657  lpftLastWriteTime);
3658  if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3659  {
3660  if (*lpcClass == 0)
3661  {
3662  return ErrorCode;
3663  }
3664 
3665  RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
3666  UnicodeString.Length = cClass * sizeof(WCHAR);
3668  &UnicodeString,
3669  FALSE);
3671  cClass = AnsiString.Length;
3672  lpClass[cClass] = ANSI_NULL;
3673  }
3674 
3675  if (lpcClass != NULL)
3676  {
3677  *lpcClass = cClass;
3678  }
3679 
3680  return ErrorCode;
3681 }
3682 
3683 
3684 /************************************************************************
3685  * RegQueryInfoKeyW
3686  *
3687  * @implemented
3688  */
3689 LONG WINAPI
3691  LPWSTR lpClass,
3692  LPDWORD lpcClass,
3693  LPDWORD lpReserved,
3694  LPDWORD lpcSubKeys,
3695  LPDWORD lpcMaxSubKeyLen,
3696  LPDWORD lpcMaxClassLen,
3697  LPDWORD lpcValues,
3698  LPDWORD lpcMaxValueNameLen,
3699  LPDWORD lpcMaxValueLen,
3700  LPDWORD lpcbSecurityDescriptor,
3701  PFILETIME lpftLastWriteTime)
3702 {
3703  KEY_FULL_INFORMATION FullInfoBuffer;
3704  PKEY_FULL_INFORMATION FullInfo;
3705  ULONG FullInfoSize;
3706  ULONG ClassLength = 0;
3707  HANDLE KeyHandle;
3708  NTSTATUS Status;
3709  ULONG Length;
3711 
3712  if ((lpClass) && (!lpcClass))
3713  {
3714  return ERROR_INVALID_PARAMETER;
3715  }
3716 
3718  hKey);
3719  if (!NT_SUCCESS(Status))
3720  {
3721  return RtlNtStatusToDosError(Status);
3722  }
3723 
3724  if (lpClass != NULL)
3725  {
3726  if (*lpcClass > 0)
3727  {
3728  ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3729  }
3730  else
3731  {
3732  ClassLength = 0;
3733  }
3734 
3735  FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3736  FullInfo = RtlAllocateHeap(ProcessHeap,
3737  0,
3738  FullInfoSize);
3739  if (FullInfo == NULL)
3740  {
3742  goto Cleanup;
3743  }
3744  }
3745  else
3746  {
3747  FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3748  FullInfo = &FullInfoBuffer;
3749  }
3750 
3751  if (lpcbSecurityDescriptor != NULL)
3752  *lpcbSecurityDescriptor = 0;
3753 
3756  FullInfo,
3757  FullInfoSize,
3758  &Length);
3759  TRACE("NtQueryKey() returned status 0x%X\n", Status);
3761  {
3763  goto Cleanup;
3764  }
3765 
3766  TRACE("SubKeys %d\n", FullInfo->SubKeys);
3767  if (lpcSubKeys != NULL)
3768  {
3769  *lpcSubKeys = FullInfo->SubKeys;
3770  }
3771 
3772  TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3773  if (lpcMaxSubKeyLen != NULL)
3774  {
3775  *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3776  }
3777 
3778  TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3779  if (lpcMaxClassLen != NULL)
3780  {
3781  *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3782  }
3783 
3784  TRACE("Values %lu\n", FullInfo->Values);
3785  if (lpcValues != NULL)
3786  {
3787  *lpcValues = FullInfo->Values;
3788  }
3789 
3790  TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3791  if (lpcMaxValueNameLen != NULL)
3792  {
3793  *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3794  }
3795 
3796  TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3797  if (lpcMaxValueLen != NULL)
3798  {
3799  *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3800  }
3801 
3802  if (lpcbSecurityDescriptor != NULL)
3803  {
3808  NULL,
3809  0,
3810  lpcbSecurityDescriptor);
3811  TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
3812  }
3813 
3814  if (lpftLastWriteTime != NULL)
3815  {
3816  lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3817  lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3818  }
3819 
3820  if (lpClass != NULL)
3821  {
3822  if (*lpcClass == 0)
3823  {
3824  goto Cleanup;
3825  }
3826 
3827  if (FullInfo->ClassLength > ClassLength)
3828  {
3830  }
3831  else
3832  {
3833  RtlCopyMemory(lpClass,
3834  FullInfo->Class,
3835  FullInfo->ClassLength);
3836  lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3837  }
3838  }
3839 
3840  if (lpcClass != NULL)
3841  {
3842  *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3843  }
3844 
3845 Cleanup:
3846  if (lpClass != NULL)
3847  {
3849  0,
3850  FullInfo);
3851  }
3852 
3854 
3855  return ErrorCode;
3856 }
3857 
3858 
3859 /************************************************************************
3860  * RegQueryMultipleValuesA
3861  *
3862  * @implemented
3863  */
3864 LONG WINAPI
3866  PVALENTA val_list,
3867  DWORD num_vals,
3868  LPSTR lpValueBuf,
3869  LPDWORD ldwTotsize)
3870 {
3871  ULONG i;
3872  DWORD maxBytes = *ldwTotsize;
3873  LPSTR bufptr = lpValueBuf;
3874  LONG ErrorCode;
3875 
3876  if (maxBytes >= (1024*1024))
3877  return ERROR_MORE_DATA;
3878 
3879  *ldwTotsize = 0;
3880 
3881  TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3882  hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3883 
3884  for (i = 0; i < num_vals; i++)
3885  {
3886  val_list[i].ve_valuelen = 0;
3888  val_list[i].ve_valuename,
3889  NULL,
3890  NULL,
3891  NULL,
3892  &val_list[i].ve_valuelen);
3893  if (ErrorCode != ERROR_SUCCESS)
3894  {
3895  return ErrorCode;
3896  }
3897 
3898  if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3899  {
3901  val_list[i].ve_valuename,
3902  NULL,
3903  &val_list[i].ve_type,
3904  (LPBYTE)bufptr,
3905  &val_list[i].ve_valuelen);
3906  if (ErrorCode != ERROR_SUCCESS)
3907  {
3908  return ErrorCode;
3909  }
3910 
3911  val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3912 
3913  bufptr += val_list[i].ve_valuelen;
3914  }
3915 
3916  *ldwTotsize += val_list[i].ve_valuelen;
3917  }
3918 
3919  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3920 }
3921 
3922 
3923 /************************************************************************
3924  * RegQueryMultipleValuesW
3925  *
3926  * @implemented
3927  */
3928 LONG WINAPI
3930  PVALENTW val_list,
3931  DWORD num_vals,
3932  LPWSTR lpValueBuf,
3933  LPDWORD ldwTotsize)
3934 {
3935  ULONG i;
3936  DWORD maxBytes = *ldwTotsize;
3937  LPSTR bufptr = (LPSTR)lpValueBuf;
3938  LONG ErrorCode;
3939 
3940  if (maxBytes >= (1024*1024))
3941  return ERROR_MORE_DATA;
3942 
3943  *ldwTotsize = 0;
3944 
3945  TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3946  hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3947 
3948  for (i = 0; i < num_vals; i++)
3949  {
3950  val_list[i].ve_valuelen = 0;
3952  val_list[i].ve_valuename,
3953  NULL,
3954  NULL,
3955  NULL,
3956  &val_list[i].ve_valuelen);
3957  if (ErrorCode != ERROR_SUCCESS)
3958  {
3959  return ErrorCode;
3960  }
3961 
3962  if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3963  {
3965  val_list[i].ve_valuename,
3966  NULL,
3967  &val_list[i].ve_type,
3968  (LPBYTE)bufptr,
3969  &val_list[i].ve_valuelen);
3970  if (ErrorCode != ERROR_SUCCESS)
3971  {
3972  return ErrorCode;
3973  }
3974 
3975  val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3976 
3977  bufptr += val_list[i].ve_valuelen;
3978  }
3979 
3980  *ldwTotsize += val_list[i].ve_valuelen;
3981  }
3982 
3983  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3984 }
3985 
3986 
3987 /************************************************************************
3988  * RegQueryReflectionKey
3989  *
3990  * @unimplemented
3991  */
3992 LONG WINAPI
3994  OUT BOOL* bIsReflectionDisabled)
3995 {
3996  FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3997  hBase, bIsReflectionDisabled);
3999 }
4000 
4001 
4002 /******************************************************************************
4003  * RegQueryValueExA [ADVAPI32.@]
4004  *
4005  * Get the type and contents of a specified value under with a key.
4006  *
4007  * PARAMS
4008  * hkey [I] Handle of the key to query
4009  * name [I] Name of value under hkey to query
4010  * reserved [I] Reserved - must be NULL
4011  * type [O] Destination for the value type, or NULL if not required
4012  * data [O] Destination for the values contents, or NULL if not required
4013  * count [I/O] Size of data, updated with the number of bytes returned
4014  *
4015  * RETURNS
4016  * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4017  * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4018  * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4019  * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4020  *
4021  * NOTES
4022  * MSDN states that if data is too small it is partially filled. In reality
4023  * it remains untouched.
4024  */
4025 LONG
4026 WINAPI
4028  _In_ HKEY hkeyorg,
4029  _In_ LPCSTR name,
4034 {
4036  DWORD DataLength;
4037  DWORD ErrorCode;
4038  DWORD BufferSize = 0;
4039  WCHAR* Buffer;
4040  CHAR* DataStr = (CHAR*)data;
4041  DWORD LocalType;
4042 
4043  /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4044  if ((data && !count) || reserved)
4045  return ERROR_INVALID_PARAMETER;
4046 
4047  if (name)
4048  {
4050  return ERROR_NOT_ENOUGH_MEMORY;
4051  }
4052  else
4053  RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4054 
4055  ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4056  if (ErrorCode != ERROR_SUCCESS)
4057  {
4058  if ((!data) && count)
4059  *count = 0;
4061  return ErrorCode;
4062  }
4063 
4064  /* See if we can directly handle the call without caring for conversion */
4065  if (!is_string(LocalType) || !count)
4066  {
4067  ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4069  return ErrorCode;
4070  }
4071 
4072  /* Allocate a unicode string to get the data */
4073  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4074  if (!Buffer)
4075  {
4077  return ERROR_NOT_ENOUGH_MEMORY;
4078  }
4079 
4081  if (ErrorCode != ERROR_SUCCESS)
4082  {
4083  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4085  return ErrorCode;
4086  }
4087 
4088  /* We don't need this anymore */
4090 
4091  /* Get the length for the multi-byte string (without the terminating NULL!) */
4092  DataLength = *count;
4094 
4095  if ((!data) || (DataLength < *count))
4096  {
4097  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4098  return data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4099  }
4100 
4101  /* We can finally do the conversion */
4103 
4104  /* NULL-terminate if there is enough room */
4105  if (DataLength > *count)
4106  DataStr[*count] = '\0';
4107 
4108  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4109 
4110  return ERROR_SUCCESS;
4111 }
4112 
4113 
4114 /************************************************************************
4115  * RegQueryValueExW
4116  *
4117  * @implemented
4118  */
4119 LONG
4120 WINAPI
4122  _In_ HKEY hkeyorg,
4123  _In_ LPCWSTR name,
4125  _In_ LPDWORD type,
4126  _In_ LPBYTE data,
4127  _In_ LPDWORD count)
4128 {
4129  HANDLE hkey;
4130  NTSTATUS status;
4131  UNICODE_STRING name_str;
4132  DWORD total_size;
4133  char buffer[256], *buf_ptr = buffer;
4135  static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4136 
4137  TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4138  hkeyorg, debugstr_w(name), reserved, type, data, count,
4139  (count && data) ? *count : 0 );
4140 
4141  if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4142 
4143  status = MapDefaultKey(&hkey, hkeyorg);
4144  if (!NT_SUCCESS(status))
4145  {
4146  return RtlNtStatusToDosError(status);
4147  }
4148 
4149  if (IsHKCRKey(hkey))
4150  {
4152  ClosePredefKey(hkey);
4153  return ErrorCode;
4154  }
4155 
4156  RtlInitUnicodeString( &name_str, name );
4157 
4158  if (data)
4159  total_size = min( sizeof(buffer), *count + info_size );
4160  else
4161  total_size = info_size;
4162 
4163 
4165  buffer, total_size, &total_size );
4166 
4168  {
4169  // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4170  // On windows these conditions are likely to be side effects of the implementation...
4171  if (status == STATUS_INVALID_HANDLE && hkey)
4172  {
4173  if (type) *type = REG_NONE;
4174  if (count) *count = 0;
4175  }
4177  {
4178  if (type) *type = REG_NONE;
4179  if (data == NULL && count) *count = 0;
4180  }
4181  goto done;
4182  }
4183 
4184  if (data)
4185  {
4186  /* retry with a dynamically allocated buffer */
4187  while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4188  {
4189  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4190  if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4191  {
4192  ClosePredefKey(hkey);
4193  return ERROR_NOT_ENOUGH_MEMORY;
4194  }
4195  info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4197  buf_ptr, total_size, &total_size );
4198  }
4199 
4200  if (NT_SUCCESS(status))
4201  {
4202  memcpy( data, buf_ptr + info_size, total_size - info_size );
4203  /* if the type is REG_SZ and data is not 0-terminated
4204  * and there is enough space in the buffer NT appends a \0 */
4205  if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4206  {
4207  WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4208  if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4209  }
4210  }
4211  else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4212  }
4213  else status = STATUS_SUCCESS;
4214 
4215  if (type) *type = info->Type;
4216  if (count) *count = total_size - info_size;
4217 
4218  done:
4219  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4220  ClosePredefKey(hkey);
4221  return RtlNtStatusToDosError(status);
4222 }
4223 
4224 
4225 /************************************************************************
4226  * RegQueryValueA
4227  *
4228  * @implemented
4229  */
4231 {
4232  DWORD ret;
4233  HKEY subkey = hkey;
4234 
4235  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4236 
4237  if (name && name[0])
4238  {
4239  if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4240  }
4241  ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4242  if (subkey != hkey) RegCloseKey( subkey );
4243  if (ret == ERROR_FILE_NOT_FOUND)
4244  {
4245  /* return empty string if default value not found */
4246  if (data) *data = 0;
4247  if (count) *count = 1;
4248  ret = ERROR_SUCCESS;
4249  }
4250  return ret;
4251 }
4252 
4253 
4254 /************************************************************************
4255  * RegQueryValueW
4256  *
4257  * @implemented
4258  */
4260 {
4261  DWORD ret;
4262  HKEY subkey = hkey;
4263 
4264  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4265  if (hkey == NULL)
4266  {
4267  return ERROR_INVALID_HANDLE;
4268  }
4269  if (name && name[0])
4270  {
4271  ret = RegOpenKeyW( hkey, name, &subkey);
4272  if (ret != ERROR_SUCCESS)
4273  {
4274  return ret;
4275  }
4276  }
4277 
4278  ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4279 
4280  if (subkey != hkey)
4281  {
4282  RegCloseKey( subkey );
4283  }
4284 
4285  if (ret == ERROR_FILE_NOT_FOUND)
4286  {
4287  /* return empty string if default value not found */
4288  if (data)
4289  *data = 0;
4290  if (count)
4291  *count = sizeof(WCHAR);
4292  ret = ERROR_SUCCESS;
4293  }
4294  return ret;
4295 }
4296 
4297 
4298 /************************************************************************
4299  * RegReplaceKeyA
4300  *
4301  * @implemented
4302  */
4303 LONG WINAPI
4305  LPCSTR lpSubKey,
4306  LPCSTR lpNewFile,
4307  LPCSTR lpOldFile)
4308 {
4309  UNICODE_STRING SubKey;
4310  UNICODE_STRING NewFile;
4311  UNICODE_STRING OldFile;
4312  LONG ErrorCode;
4313 
4314  RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4315  RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4316  RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4317 
4318  if (lpSubKey)
4319  {
4320  if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4321  {
4323  goto Exit;
4324  }
4325  }
4326 
4327  if (lpOldFile)
4328  {
4329  if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4330  {
4332  goto Exit;
4333  }
4334  }
4335 
4336  if (lpNewFile)
4337  {
4338  if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4339  {
4341  goto Exit;
4342  }
4343  }
4344 
4346  SubKey.Buffer,
4347  NewFile.Buffer,
4348  OldFile.Buffer);
4349 
4350 Exit:
4351  RtlFreeUnicodeString(&OldFile);
4352  RtlFreeUnicodeString(&NewFile);
4353  RtlFreeUnicodeString(&SubKey);
4354 
4355  return ErrorCode;
4356 }
4357 
4358 
4359 /************************************************************************
4360  * RegReplaceKeyW
4361  *
4362  * @unimplemented
4363  */
4364 LONG WINAPI
4366  LPCWSTR lpSubKey,
4367  LPCWSTR lpNewFile,
4368  LPCWSTR lpOldFile)
4369 {
4370  OBJECT_ATTRIBUTES KeyObjectAttributes;
4371  OBJECT_ATTRIBUTES NewObjectAttributes;
4372  OBJECT_ATTRIBUTES OldObjectAttributes;
4374  UNICODE_STRING NewFileName;
4375  UNICODE_STRING OldFileName;
4376  BOOLEAN CloseRealKey;
4377  HANDLE RealKeyHandle;
4378  HANDLE KeyHandle;
4379  NTSTATUS Status;
4381 
4382  if (hKey == HKEY_PERFORMANCE_DATA)
4383  {
4384  return ERROR_INVALID_HANDLE;
4385  }
4386 
4388  hKey);
4389  if (!NT_SUCCESS(Status))
4390  {
4391  return RtlNtStatusToDosError(Status);
4392  }
4393 
4394  /* Open the real key */
4395  if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4396  {
4397  RtlInitUnicodeString(&SubKeyName, lpSubKey);
4398  InitializeObjectAttributes(&KeyObjectAttributes,
4399  &SubKeyName,
4401  KeyHandle,
4402  NULL);
4403  Status = NtOpenKey(&RealKeyHandle,
4405  &KeyObjectAttributes);
4406  if (!NT_SUCCESS(Status))
4407  {
4409  goto Cleanup;
4410  }
4411 
4412  CloseRealKey = TRUE;
4413  }
4414  else
4415  {
4416  RealKeyHandle = KeyHandle;
4417  CloseRealKey = FALSE;
4418  }
4419 
4420  /* Convert new file name */
4421  if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4422  &NewFileName,
4423  NULL,
4424  NULL))
4425  {
4426  if (CloseRealKey)
4427  {
4428  NtClose(RealKeyHandle);
4429  }
4430 
4432  goto Cleanup;
4433  }
4434 
4435  InitializeObjectAttributes(&NewObjectAttributes,
4436  &NewFileName,
4438  NULL,
4439  NULL);
4440 
4441  /* Convert old file name */
4442  if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4443  &OldFileName,
4444  NULL,
4445  NULL))
4446  {
4447  RtlFreeHeap(RtlGetProcessHeap (),
4448  0,
4449  NewFileName.Buffer);
4450  if (CloseRealKey)
4451  {
4452  NtClose(RealKeyHandle);
4453  }
4454 
4456  goto Cleanup;
4457  }
4458 
4459  InitializeObjectAttributes(&OldObjectAttributes,
4460  &OldFileName,
4462  NULL,
4463  NULL);
4464 
4465  Status = NtReplaceKey(&NewObjectAttributes,
4466  RealKeyHandle,
4467  &OldObjectAttributes);
4468 
4469  RtlFreeHeap(RtlGetProcessHeap(),
4470  0,
4471  OldFileName.Buffer);
4472  RtlFreeHeap(RtlGetProcessHeap(),
4473  0,
4474  NewFileName.Buffer);
4475 
4476  if (CloseRealKey)
4477  {
4478  NtClose(RealKeyHandle);
4479  }
4480 
4481  if (!NT_SUCCESS(Status))
4482  {
4483  return RtlNtStatusToDosError(Status);
4484  }
4485 
4486 Cleanup:
4488 
4489  return ErrorCode;
4490 }
4491 
4492 
4493 /************************************************************************
4494  * RegRestoreKeyA
4495  *
4496  * @implemented
4497  */
4498 LONG WINAPI
4500  LPCSTR lpFile,
4501  DWORD dwFlags)
4502 {
4504  LONG ErrorCode;
4505 
4506  if (lpFile)
4507  {
4509  return ERROR_NOT_ENOUGH_MEMORY;
4510  }
4511  else
4512  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4513 
4515  FileName.Buffer,
4516  dwFlags);
4517 
4519 
4520  return ErrorCode;
4521 }
4522 
4523 
4524 /************************************************************************
4525  * RegRestoreKeyW
4526  *
4527  * @implemented
4528  */
4529 LONG WINAPI
4531  LPCWSTR lpFile,
4532  DWORD dwFlags)
4533 {
4538  HANDLE KeyHandle;
4539  NTSTATUS Status;
4540 
4541  if (hKey == HKEY_PERFORMANCE_DATA)
4542  {
4543  return ERROR_INVALID_HANDLE;
4544  }
4545 
4547  hKey);
4548  if (!NT_SUCCESS(Status))
4549  {
4550  return RtlNtStatusToDosError(Status);
4551  }
4552 
4553  if (!RtlDosPathNameToNtPathName_U(lpFile,
4554  &FileName,
4555  NULL,
4556  NULL))
4557  {
4559  goto Cleanup;
4560  }
4561 
4563  &FileName,
4565  NULL,
4566  NULL);
4567 
4571  &IoStatusBlock,
4574  RtlFreeHeap(RtlGetProcessHeap(),
4575  0,
4576  FileName.Buffer);
4577  if (!NT_SUCCESS(Status))
4578  {
4579  goto Cleanup;
4580  }
4581 
4583  FileHandle,
4584  (ULONG)dwFlags);
4585  NtClose (FileHandle);
4586 
4587 Cleanup:
4589 
4590  if (!NT_SUCCESS(Status))
4591  {
4592  return RtlNtStatusToDosError(Status);
4593  }
4594 
4595  return ERROR_SUCCESS;
4596 }
4597 
4598 
4599 /************************************************************************
4600  * RegSaveKeyA
4601  *
4602  * @implemented
4603  */
4604 LONG WINAPI
4606  LPCSTR lpFile,
4607  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4608 {
4610  LONG ErrorCode;
4611 
4612  if (lpFile)
4613  {
4615  return ERROR_NOT_ENOUGH_MEMORY;
4616  }
4617  else
4618  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4619 
4621  FileName.Buffer,
4622  lpSecurityAttributes);
4624 
4625  return ErrorCode;
4626 }
4627 
4628 
4629 /************************************************************************
4630  * RegSaveKeyW
4631  *
4632  * @implemented
4633  */
4634 LONG WINAPI
4636  LPCWSTR lpFile,
4637  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4638 {
4644  HANDLE KeyHandle;
4645  NTSTATUS Status;
4646 
4648  hKey);
4649  if (!NT_SUCCESS(Status))
4650  {
4651  return RtlNtStatusToDosError(Status);
4652  }
4653 
4654  if (!RtlDosPathNameToNtPathName_U(lpFile,
4655  &FileName,
4656  NULL,
4657  NULL))
4658  {
4660  goto Cleanup;
4661  }
4662 
4663  if (lpSecurityAttributes != NULL)
4664  {
4665  SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4666  }
4667 
4669  &FileName,
4671  NULL,
4676  &IoStatusBlock,
4677  NULL,
4680  FILE_CREATE,
4682  NULL,
4683  0);
4684  RtlFreeHeap(RtlGetProcessHeap(),
4685  0,
4686  FileName.Buffer);
4687  if (!NT_SUCCESS(Status))
4688  {
4689  goto Cleanup;
4690  }
4691 
4693  FileHandle);
4694  NtClose (FileHandle);
4695 
4696 Cleanup:
4698 
4699  if (!NT_SUCCESS(Status))
4700  {
4701  return RtlNtStatusToDosError(Status);
4702  }
4703 
4704  return ERROR_SUCCESS;
4705 }
4706 
4707 
4708 /************************************************************************
4709  * RegSaveKeyExA
4710  *
4711  * @implemented
4712  */
4713 LONG
4714 WINAPI
4716  LPCSTR lpFile,
4717  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4718  DWORD Flags)
4719 {
4721  LONG ErrorCode;
4722 
4723  if (lpFile)
4724  {
4726  return ERROR_NOT_ENOUGH_MEMORY;
4727  }
4728  else
4729  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4730 
4732  FileName.Buffer,
4733  lpSecurityAttributes,
4734  Flags);
4736 
4737  return ErrorCode;
4738 }
4739 
4740 
4741 /************************************************************************
4742  * RegSaveKeyExW
4743  *
4744  * @unimplemented
4745  */
4746 LONG
4747 WINAPI
4749  LPCWSTR lpFile,
4750  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4751  DWORD Flags)
4752 {
4753  switch (Flags)
4754  {
4755  case REG_STANDARD_FORMAT:
4756  case REG_LATEST_FORMAT:
4757  case REG_NO_COMPRESSION:
4758  break;
4759  default:
4760  return ERROR_INVALID_PARAMETER;
4761  }
4762 
4763  FIXME("RegSaveKeyExW(): Flags ignored!\n");
4764 
4765  return RegSaveKeyW(hKey,
4766  lpFile,
4767  lpSecurityAttributes);
4768 }
4769 
4770 
4771 /************************************************************************
4772  * RegSetKeySecurity
4773  *
4774  * @implemented
4775  */
4776 LONG WINAPI
4779  PSECURITY_DESCRIPTOR pSecurityDescriptor)
4780 {
4781  HANDLE KeyHandle;
4782  NTSTATUS Status;
4783 
4784  if (hKey == HKEY_PERFORMANCE_DATA)
4785  {
4786  return ERROR_INVALID_HANDLE;
4787  }
4788 
4790  hKey);
4791  if (!NT_SUCCESS(Status))
4792  {
4793  return RtlNtStatusToDosError(Status);
4794  }
4795 
4798  pSecurityDescriptor);
4799 
4801 
4802  if (!NT_SUCCESS(Status))
4803  {
4804  return RtlNtStatusToDosError(Status);
4805  }
4806 
4807  return ERROR_SUCCESS;
4808 }
4809 
4810 
4811 /************************************************************************
4812  * RegSetValueExA
4813  *
4814  * @implemented
4815  */
4816 LONG WINAPI
4818  LPCSTR lpValueName,
4819  DWORD Reserved,
4820  DWORD dwType,
4821  CONST BYTE* lpData,
4822  DWORD cbData)
4823 {
4825  LPWSTR pValueName;
4828  LONG ErrorCode;
4829  LPBYTE pData;
4830  DWORD DataSize;
4831  NTSTATUS Status;
4832 
4833  /* Convert SubKey name to Unicode */
4834  if (lpValueName != NULL && lpValueName[0] != '\0')
4835  {
4836  if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
4837  return ERROR_NOT_ENOUGH_MEMORY;
4838  }
4839  else
4840  {
4841  ValueName.Buffer = NULL;
4842  }
4843 
4844  pValueName = (LPWSTR)ValueName.Buffer;
4845 
4846 
4847  if (is_string(dwType) && (cbData != 0))
4848  {
4849  /* Convert ANSI string Data to Unicode */
4850  /* If last character NOT zero then increment length */
4851  LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4852  AnsiString.Buffer = (PSTR)lpData;
4853  AnsiString.Length = cbData + bNoNulledStr;
4854  AnsiString.MaximumLength = cbData + bNoNulledStr;
4856  &AnsiString,
4857  TRUE);
4858 
4859  if (!NT_SUCCESS(Status))
4860  {
4861  if (pValueName != NULL)
4863 
4864  return RtlNtStatusToDosError(Status);
4865  }
4866  pData = (LPBYTE)Data.Buffer;
4867  DataSize = cbData * sizeof(WCHAR);
4868  }
4869  else
4870  {
4871  Data.Buffer = NULL;
4872  pData = (LPBYTE)lpData;
4873  DataSize = cbData;
4874  }
4875 
4877  pValueName,
4878  Reserved,
4879  dwType,
4880  pData,
4881  DataSize);
4882 
4883  if (pValueName != NULL)
4885 
4886  if (Data.Buffer != NULL)
4888 
4889  return ErrorCode;
4890 }
4891 
4892 
4893 /************************************************************************
4894  * RegSetValueExW
4895  *
4896  * @implemented
4897  */
4898 LONG
4899 WINAPI
4901  _In_ HKEY hKey,
4902  _In_ LPCWSTR lpValueName,
4904  _In_ DWORD dwType,
4905  _In_ CONST BYTE* lpData,
4906  _In_ DWORD cbData)
4907 {
4909  HANDLE KeyHandle;
4910  NTSTATUS Status;
4911 
4913  hKey);
4914  if (!NT_SUCCESS(Status))
4915  {
4916  return RtlNtStatusToDosError(Status);
4917  }
4918 
4919  if (IsHKCRKey(KeyHandle))
4920  {
4921  LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4923  return ErrorCode;
4924  }
4925 
4926  if (is_string(dwType) && (cbData != 0))
4927  {
4928  PWSTR pwsData = (PWSTR)lpData;
4929 
4930  _SEH2_TRY
4931  {
4932  if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4933  (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4934  {
4935  /* Increment length if last character is not zero and next is zero */
4936  cbData += sizeof(WCHAR);
4937  }
4938  }
4940  {
4941  /* Do not fail if we fault where we were told not to go */
4942  }
4943  _SEH2_END;
4944  }
4945 
4946  RtlInitUnicodeString(&ValueName, lpValueName);
4947 
4949  &ValueName,
4950  0,
4951  dwType,
4952  (PVOID)lpData,
4953  (ULONG)cbData);
4954 
4956 
4957  if (!NT_SUCCESS(Status))
4958  {
4959  return RtlNtStatusToDosError(Status);
4960  }
4961 
4962  return ERROR_SUCCESS;
4963 }
4964 
4965 
4966 /************************************************************************
4967  * RegSetValueA
4968  *
4969  * @implemented
4970  */
4971 LONG WINAPI
4972 RegSetValueA(HKEY hKeyOriginal,
4973  LPCSTR lpSubKey,
4974  DWORD dwType,
4975  LPCSTR lpData,
4976  DWORD cbData)
4977 {
4978  HKEY subkey;
4979  HANDLE hKey;
4980  DWORD ret;
4981  NTSTATUS Status;
4982 
4983  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4984 
4985  if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4986 
4987  Status = MapDefaultKey(&hKey, hKeyOriginal);
4988  if (!NT_SUCCESS(Status))
4989  {
4990  return RtlNtStatusToDosError (Status);
4991  }
4992  subkey = hKey;
4993 
4994  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4995  {
4996  ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4997  if (ret != ERROR_SUCCESS)
4998  goto Cleanup;
4999  }
5000 
5001  ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
5002  if (subkey != hKey)
5003  RegCloseKey(subkey);
5004 
5005 Cleanup:
5007 
5008  return ret;
5009 }
5010 
5011 
5012 /************************************************************************
5013  * RegSetValueW
5014  *
5015  * @implemented
5016  */
5017 LONG WINAPI
5018 RegSetValueW(HKEY hKeyOriginal,
5019  LPCWSTR lpSubKey,
5020  DWORD dwType,
5021  LPCWSTR lpData,
5022  DWORD cbData)
5023 {
5024  HKEY subkey;
5025  HANDLE hKey;
5026  DWORD ret;
5027  NTSTATUS Status;
5028 
5029  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5030 
5031  if (dwType != REG_SZ || !lpData)
5032  return ERROR_INVALID_PARAMETER;
5033 
5035  hKeyOriginal);
5036  if (!NT_SUCCESS(Status))
5037  {
5038  return RtlNtStatusToDosError(Status);
5039  }
5040  subkey = hKey;
5041 
5042  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5043  {
5044  ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5045  if (ret != ERROR_SUCCESS)
5046  goto Cleanup;
5047  }
5048 
5049  ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5050  (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5051  if (subkey != hKey)
5052  RegCloseKey(subkey);
5053 
5054 Cleanup:
5056 
5057  return ret;
5058 }
5059 
5060 
5061 /************************************************************************
5062  * RegUnLoadKeyA
5063  *
5064  * @implemented
5065  */
5066 LONG WINAPI
5068  LPCSTR lpSubKey)
5069 {
5071  DWORD ErrorCode;
5072 
5073  if (lpSubKey)
5074  {
5075  if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5076  return ERROR_NOT_ENOUGH_MEMORY;
5077  }
5078  else
5079  RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5080 
5082  KeyName.Buffer);
5083 
5085 
5086  return ErrorCode;
5087 }
5088 
5089 
5090 /************************************************************************
5091  * RegUnLoadKeyW
5092  *
5093  * @implemented
5094  */
5095 LONG WINAPI
5097  LPCWSTR lpSubKey)
5098 {
5101  HANDLE KeyHandle;
5102  NTSTATUS