ReactOS  0.4.15-dev-5120-gfb68e76
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  DataLength = *count;
4093 
4094  if ((!data) || (DataLength < *count))
4095  {
4096  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4097  return data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4098  }
4099 
4100  /* We can finally do the conversion */
4102 
4103  /* NULL-terminate if there is enough room */
4104  if ((DataLength > *count) && (DataStr[*count - 1] != '\0'))
4105  DataStr[*count] = '\0';
4106 
4107  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4108 
4109  return ERROR_SUCCESS;
4110 }
4111 
4112 
4113 /************************************************************************
4114  * RegQueryValueExW
4115  *
4116  * @implemented
4117  */
4118 LONG
4119 WINAPI
4121  _In_ HKEY hkeyorg,
4122  _In_ LPCWSTR name,
4124  _In_ LPDWORD type,
4125  _In_ LPBYTE data,
4126  _In_ LPDWORD count)
4127 {
4128  HANDLE hkey;
4129  NTSTATUS status;
4130  UNICODE_STRING name_str;
4131  DWORD total_size;
4132  char buffer[256], *buf_ptr = buffer;
4134  static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4135 
4136  TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4137  hkeyorg, debugstr_w(name), reserved, type, data, count,
4138  (count && data) ? *count : 0 );
4139 
4140  if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4141 
4142  status = MapDefaultKey(&hkey, hkeyorg);
4143  if (!NT_SUCCESS(status))
4144  {
4145  return RtlNtStatusToDosError(status);
4146  }
4147 
4148  if (IsHKCRKey(hkey))
4149  {
4151  ClosePredefKey(hkey);
4152  return ErrorCode;
4153  }
4154 
4155  RtlInitUnicodeString( &name_str, name );
4156 
4157  if (data)
4158  total_size = min( sizeof(buffer), *count + info_size );
4159  else
4160  total_size = info_size;
4161 
4162 
4164  buffer, total_size, &total_size );
4165 
4167  {
4168  // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4169  // On windows these conditions are likely to be side effects of the implementation...
4170  if (status == STATUS_INVALID_HANDLE && hkey)
4171  {
4172  if (type) *type = REG_NONE;
4173  if (count) *count = 0;
4174  }
4176  {
4177  if (type) *type = REG_NONE;
4178  if (data == NULL && count) *count = 0;
4179  }
4180  goto done;
4181  }
4182 
4183  if (data)
4184  {
4185  /* retry with a dynamically allocated buffer */
4186  while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4187  {
4188  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4189  if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4190  {
4191  ClosePredefKey(hkey);
4192  return ERROR_NOT_ENOUGH_MEMORY;
4193  }
4194  info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4196  buf_ptr, total_size, &total_size );
4197  }
4198 
4199  if (NT_SUCCESS(status))
4200  {
4201  memcpy( data, buf_ptr + info_size, total_size - info_size );
4202  /* if the type is REG_SZ and data is not 0-terminated
4203  * and there is enough space in the buffer NT appends a \0 */
4204  if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4205  {
4206  WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4207  if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4208  }
4209  }
4210  else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4211  }
4212  else status = STATUS_SUCCESS;
4213 
4214  if (type) *type = info->Type;
4215  if (count) *count = total_size - info_size;
4216 
4217  done:
4218  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4219  ClosePredefKey(hkey);
4220  return RtlNtStatusToDosError(status);
4221 }
4222 
4223 
4224 /************************************************************************
4225  * RegQueryValueA
4226  *
4227  * @implemented
4228  */
4230 {
4231  DWORD ret;
4232  HKEY subkey = hkey;
4233 
4234  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4235 
4236  if (name && name[0])
4237  {
4238  if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4239  }
4240  ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4241  if (subkey != hkey) RegCloseKey( subkey );
4242  if (ret == ERROR_FILE_NOT_FOUND)
4243  {
4244  /* return empty string if default value not found */
4245  if (data) *data = 0;
4246  if (count) *count = 1;
4247  ret = ERROR_SUCCESS;
4248  }
4249  return ret;
4250 }
4251 
4252 
4253 /************************************************************************
4254  * RegQueryValueW
4255  *
4256  * @implemented
4257  */
4259 {
4260  DWORD ret;
4261  HKEY subkey = hkey;
4262 
4263  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4264  if (hkey == NULL)
4265  {
4266  return ERROR_INVALID_HANDLE;
4267  }
4268  if (name && name[0])
4269  {
4270  ret = RegOpenKeyW( hkey, name, &subkey);
4271  if (ret != ERROR_SUCCESS)
4272  {
4273  return ret;
4274  }
4275  }
4276 
4277  ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4278 
4279  if (subkey != hkey)
4280  {
4281  RegCloseKey( subkey );
4282  }
4283 
4284  if (ret == ERROR_FILE_NOT_FOUND)
4285  {
4286  /* return empty string if default value not found */
4287  if (data)
4288  *data = 0;
4289  if (count)
4290  *count = sizeof(WCHAR);
4291  ret = ERROR_SUCCESS;
4292  }
4293  return ret;
4294 }
4295 
4296 
4297 /************************************************************************
4298  * RegReplaceKeyA
4299  *
4300  * @implemented
4301  */
4302 LONG WINAPI
4304  LPCSTR lpSubKey,
4305  LPCSTR lpNewFile,
4306  LPCSTR lpOldFile)
4307 {
4308  UNICODE_STRING SubKey;
4309  UNICODE_STRING NewFile;
4310  UNICODE_STRING OldFile;
4311  LONG ErrorCode;
4312 
4313  RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4314  RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4315  RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4316 
4317  if (lpSubKey)
4318  {
4319  if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4320  {
4322  goto Exit;
4323  }
4324  }
4325 
4326  if (lpOldFile)
4327  {
4328  if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4329  {
4331  goto Exit;
4332  }
4333  }
4334 
4335  if (lpNewFile)
4336  {
4337  if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4338  {
4340  goto Exit;
4341  }
4342  }
4343 
4345  SubKey.Buffer,
4346  NewFile.Buffer,
4347  OldFile.Buffer);
4348 
4349 Exit:
4350  RtlFreeUnicodeString(&OldFile);
4351  RtlFreeUnicodeString(&NewFile);
4352  RtlFreeUnicodeString(&SubKey);
4353 
4354  return ErrorCode;
4355 }
4356 
4357 
4358 /************************************************************************
4359  * RegReplaceKeyW
4360  *
4361  * @unimplemented
4362  */
4363 LONG WINAPI
4365  LPCWSTR lpSubKey,
4366  LPCWSTR lpNewFile,
4367  LPCWSTR lpOldFile)
4368 {
4369  OBJECT_ATTRIBUTES KeyObjectAttributes;
4370  OBJECT_ATTRIBUTES NewObjectAttributes;
4371  OBJECT_ATTRIBUTES OldObjectAttributes;
4373  UNICODE_STRING NewFileName;
4374  UNICODE_STRING OldFileName;
4375  BOOLEAN CloseRealKey;
4376  HANDLE RealKeyHandle;
4377  HANDLE KeyHandle;
4378  NTSTATUS Status;
4380 
4381  if (hKey == HKEY_PERFORMANCE_DATA)
4382  {
4383  return ERROR_INVALID_HANDLE;
4384  }
4385 
4387  hKey);
4388  if (!NT_SUCCESS(Status))
4389  {
4390  return RtlNtStatusToDosError(Status);
4391  }
4392 
4393  /* Open the real key */
4394  if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4395  {
4396  RtlInitUnicodeString(&SubKeyName, lpSubKey);
4397  InitializeObjectAttributes(&KeyObjectAttributes,
4398  &SubKeyName,
4400  KeyHandle,
4401  NULL);
4402  Status = NtOpenKey(&RealKeyHandle,
4404  &KeyObjectAttributes);
4405  if (!NT_SUCCESS(Status))
4406  {
4408  goto Cleanup;
4409  }
4410 
4411  CloseRealKey = TRUE;
4412  }
4413  else
4414  {
4415  RealKeyHandle = KeyHandle;
4416  CloseRealKey = FALSE;
4417  }
4418 
4419  /* Convert new file name */
4420  if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4421  &NewFileName,
4422  NULL,
4423  NULL))
4424  {
4425  if (CloseRealKey)
4426  {
4427  NtClose(RealKeyHandle);
4428  }
4429 
4431  goto Cleanup;
4432  }
4433 
4434  InitializeObjectAttributes(&NewObjectAttributes,
4435  &NewFileName,
4437  NULL,
4438  NULL);
4439 
4440  /* Convert old file name */
4441  if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4442  &OldFileName,
4443  NULL,
4444  NULL))
4445  {
4446  RtlFreeHeap(RtlGetProcessHeap (),
4447  0,
4448  NewFileName.Buffer);
4449  if (CloseRealKey)
4450  {
4451  NtClose(RealKeyHandle);
4452  }
4453 
4455  goto Cleanup;
4456  }
4457 
4458  InitializeObjectAttributes(&OldObjectAttributes,
4459  &OldFileName,
4461  NULL,
4462  NULL);
4463 
4464  Status = NtReplaceKey(&NewObjectAttributes,
4465  RealKeyHandle,
4466  &OldObjectAttributes);
4467 
4468  RtlFreeHeap(RtlGetProcessHeap(),
4469  0,
4470  OldFileName.Buffer);
4471  RtlFreeHeap(RtlGetProcessHeap(),
4472  0,
4473  NewFileName.Buffer);
4474 
4475  if (CloseRealKey)
4476  {
4477  NtClose(RealKeyHandle);
4478  }
4479 
4480  if (!NT_SUCCESS(Status))
4481  {
4482  return RtlNtStatusToDosError(Status);
4483  }
4484 
4485 Cleanup:
4487 
4488  return ErrorCode;
4489 }
4490 
4491 
4492 /************************************************************************
4493  * RegRestoreKeyA
4494  *
4495  * @implemented
4496  */
4497 LONG WINAPI
4499  LPCSTR lpFile,
4500  DWORD dwFlags)
4501 {
4503  LONG ErrorCode;
4504 
4505  if (lpFile)
4506  {
4508  return ERROR_NOT_ENOUGH_MEMORY;
4509  }
4510  else
4511  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4512 
4514  FileName.Buffer,
4515  dwFlags);
4516 
4518 
4519  return ErrorCode;
4520 }
4521 
4522 
4523 /************************************************************************
4524  * RegRestoreKeyW
4525  *
4526  * @implemented
4527  */
4528 LONG WINAPI
4530  LPCWSTR lpFile,
4531  DWORD dwFlags)
4532 {
4537  HANDLE KeyHandle;
4538  NTSTATUS Status;
4539 
4540  if (hKey == HKEY_PERFORMANCE_DATA)
4541  {
4542  return ERROR_INVALID_HANDLE;
4543  }
4544 
4546  hKey);
4547  if (!NT_SUCCESS(Status))
4548  {
4549  return RtlNtStatusToDosError(Status);
4550  }
4551 
4552  if (!RtlDosPathNameToNtPathName_U(lpFile,
4553  &FileName,
4554  NULL,
4555  NULL))
4556  {
4558  goto Cleanup;
4559  }
4560 
4562  &FileName,
4564  NULL,
4565  NULL);
4566 
4570  &IoStatusBlock,
4573  RtlFreeHeap(RtlGetProcessHeap(),
4574  0,
4575  FileName.Buffer);
4576  if (!NT_SUCCESS(Status))
4577  {
4578  goto Cleanup;
4579  }
4580 
4582  FileHandle,
4583  (ULONG)dwFlags);
4584  NtClose (FileHandle);
4585 
4586 Cleanup:
4588 
4589  if (!NT_SUCCESS(Status))
4590  {
4591  return RtlNtStatusToDosError(Status);
4592  }
4593 
4594  return ERROR_SUCCESS;
4595 }
4596 
4597 
4598 /************************************************************************
4599  * RegSaveKeyA
4600  *
4601  * @implemented
4602  */
4603 LONG WINAPI
4605  LPCSTR lpFile,
4606  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4607 {
4609  LONG ErrorCode;
4610 
4611  if (lpFile)
4612  {
4614  return ERROR_NOT_ENOUGH_MEMORY;
4615  }
4616  else
4617  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4618 
4620  FileName.Buffer,
4621  lpSecurityAttributes);
4623 
4624  return ErrorCode;
4625 }
4626 
4627 
4628 /************************************************************************
4629  * RegSaveKeyW
4630  *
4631  * @implemented
4632  */
4633 LONG WINAPI
4635  LPCWSTR lpFile,
4636  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4637 {
4643  HANDLE KeyHandle;
4644  NTSTATUS Status;
4645 
4647  hKey);
4648  if (!NT_SUCCESS(Status))
4649  {
4650  return RtlNtStatusToDosError(Status);
4651  }
4652 
4653  if (!RtlDosPathNameToNtPathName_U(lpFile,
4654  &FileName,
4655  NULL,
4656  NULL))
4657  {
4659  goto Cleanup;
4660  }
4661 
4662  if (lpSecurityAttributes != NULL)
4663  {
4664  SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4665  }
4666 
4668  &FileName,
4670  NULL,
4675  &IoStatusBlock,
4676  NULL,
4679  FILE_CREATE,
4681  NULL,
4682  0);
4683  RtlFreeHeap(RtlGetProcessHeap(),
4684  0,
4685  FileName.Buffer);
4686  if (!NT_SUCCESS(Status))
4687  {
4688  goto Cleanup;
4689  }
4690 
4692  FileHandle);
4693  NtClose (FileHandle);
4694 
4695 Cleanup:
4697 
4698  if (!NT_SUCCESS(Status))
4699  {
4700  return RtlNtStatusToDosError(Status);
4701  }
4702 
4703  return ERROR_SUCCESS;
4704 }
4705 
4706 
4707 /************************************************************************
4708  * RegSaveKeyExA
4709  *
4710  * @implemented
4711  */
4712 LONG
4713 WINAPI
4715  LPCSTR lpFile,
4716  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4717  DWORD Flags)
4718 {
4720  LONG ErrorCode;
4721 
4722  if (lpFile)
4723  {
4725  return ERROR_NOT_ENOUGH_MEMORY;
4726  }
4727  else
4728  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4729 
4731  FileName.Buffer,
4732  lpSecurityAttributes,
4733  Flags);
4735 
4736  return ErrorCode;
4737 }
4738 
4739 
4740 /************************************************************************
4741  * RegSaveKeyExW
4742  *
4743  * @unimplemented
4744  */
4745 LONG
4746 WINAPI
4748  LPCWSTR lpFile,
4749  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4750  DWORD Flags)
4751 {
4752  switch (Flags)
4753  {
4754  case REG_STANDARD_FORMAT:
4755  case REG_LATEST_FORMAT:
4756  case REG_NO_COMPRESSION:
4757  break;
4758  default:
4759  return ERROR_INVALID_PARAMETER;
4760  }
4761 
4762  FIXME("RegSaveKeyExW(): Flags ignored!\n");
4763 
4764  return RegSaveKeyW(hKey,
4765  lpFile,
4766  lpSecurityAttributes);
4767 }
4768 
4769 
4770 /************************************************************************
4771  * RegSetKeySecurity
4772  *
4773  * @implemented
4774  */
4775 LONG WINAPI
4778  PSECURITY_DESCRIPTOR pSecurityDescriptor)
4779 {
4780  HANDLE KeyHandle;
4781  NTSTATUS Status;
4782 
4783  if (hKey == HKEY_PERFORMANCE_DATA)
4784  {
4785  return ERROR_INVALID_HANDLE;
4786  }
4787 
4789  hKey);
4790  if (!NT_SUCCESS(Status))
4791  {
4792  return RtlNtStatusToDosError(Status);
4793  }
4794 
4797  pSecurityDescriptor);
4798 
4800 
4801  if (!NT_SUCCESS(Status))
4802  {
4803  return RtlNtStatusToDosError(Status);
4804  }
4805 
4806  return ERROR_SUCCESS;
4807 }
4808 
4809 
4810 /************************************************************************
4811  * RegSetValueExA
4812  *
4813  * @implemented
4814  */
4815 LONG WINAPI
4817  LPCSTR lpValueName,
4818  DWORD Reserved,
4819  DWORD dwType,
4820  CONST BYTE* lpData,
4821  DWORD cbData)
4822 {
4824  LPWSTR pValueName;
4827  LONG ErrorCode;
4828  LPBYTE pData;
4829  DWORD DataSize;
4830  NTSTATUS Status;
4831 
4832  /* Convert SubKey name to Unicode */
4833  if (lpValueName != NULL && lpValueName[0] != '\0')
4834  {
4835  if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
4836  return ERROR_NOT_ENOUGH_MEMORY;
4837  }
4838  else
4839  {
4840  ValueName.Buffer = NULL;
4841  }
4842 
4843  pValueName = (LPWSTR)ValueName.Buffer;
4844 
4845 
4846  if (is_string(dwType) && (cbData != 0))
4847  {
4848  /* Convert ANSI string Data to Unicode */
4849  /* If last character NOT zero then increment length */
4850  LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4851  AnsiString.Buffer = (PSTR)lpData;
4852  AnsiString.Length = cbData + bNoNulledStr;
4853  AnsiString.MaximumLength = cbData + bNoNulledStr;
4855  &AnsiString,
4856  TRUE);
4857 
4858  if (!NT_SUCCESS(Status))
4859  {
4860  if (pValueName != NULL)
4862 
4863  return RtlNtStatusToDosError(Status);
4864  }
4865  pData = (LPBYTE)Data.Buffer;
4866  DataSize = cbData * sizeof(WCHAR);
4867  }
4868  else
4869  {
4870  Data.Buffer = NULL;
4871  pData = (LPBYTE)lpData;
4872  DataSize = cbData;
4873  }
4874 
4876  pValueName,
4877  Reserved,
4878  dwType,
4879  pData,
4880  DataSize);
4881 
4882  if (pValueName != NULL)
4884 
4885  if (Data.Buffer != NULL)
4887 
4888  return ErrorCode;
4889 }
4890 
4891 
4892 /************************************************************************
4893  * RegSetValueExW
4894  *
4895  * @implemented
4896  */
4897 LONG
4898 WINAPI
4900  _In_ HKEY hKey,
4901  _In_ LPCWSTR lpValueName,
4903  _In_ DWORD dwType,
4904  _In_ CONST BYTE* lpData,
4905  _In_ DWORD cbData)
4906 {
4908  HANDLE KeyHandle;
4909  NTSTATUS Status;
4910 
4912  hKey);
4913  if (!NT_SUCCESS(Status))
4914  {
4915  return RtlNtStatusToDosError(Status);
4916  }
4917 
4918  if (IsHKCRKey(KeyHandle))
4919  {
4920  LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4922  return ErrorCode;
4923  }
4924 
4925  if (is_string(dwType) && (cbData != 0))
4926  {
4927  PWSTR pwsData = (PWSTR)lpData;
4928 
4929  _SEH2_TRY
4930  {
4931  if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4932  (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4933  {
4934  /* Increment length if last character is not zero and next is zero */
4935  cbData += sizeof(WCHAR);
4936  }
4937  }
4939  {
4940  /* Do not fail if we fault where we were told not to go */
4941  }
4942  _SEH2_END;
4943  }
4944 
4945  RtlInitUnicodeString(&ValueName, lpValueName);
4946 
4948  &ValueName,
4949  0,
4950  dwType,
4951  (PVOID)lpData,
4952  (ULONG)cbData);
4953 
4955 
4956  if (!NT_SUCCESS(Status))
4957  {
4958  return RtlNtStatusToDosError(Status);
4959  }
4960 
4961  return ERROR_SUCCESS;
4962 }
4963 
4964 
4965 /************************************************************************
4966  * RegSetValueA
4967  *
4968  * @implemented
4969  */
4970 LONG WINAPI
4971 RegSetValueA(HKEY hKeyOriginal,
4972  LPCSTR lpSubKey,
4973  DWORD dwType,
4974  LPCSTR lpData,
4975  DWORD cbData)
4976 {
4977  HKEY subkey;
4978  HANDLE hKey;
4979  DWORD ret;
4980  NTSTATUS Status;
4981 
4982  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4983 
4984  if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4985 
4986  Status = MapDefaultKey(&hKey, hKeyOriginal);
4987  if (!NT_SUCCESS(Status))
4988  {
4989  return RtlNtStatusToDosError (Status);
4990  }
4991  subkey = hKey;
4992 
4993  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4994  {
4995  ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4996  if (ret != ERROR_SUCCESS)
4997  goto Cleanup;
4998  }
4999 
5000  ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
5001  if (subkey != hKey)
5002  RegCloseKey(subkey);
5003 
5004 Cleanup:
5006 
5007  return ret;
5008 }
5009 
5010 
5011 /************************************************************************
5012  * RegSetValueW
5013  *
5014  * @implemented
5015  */
5016 LONG WINAPI
5017 RegSetValueW(HKEY hKeyOriginal,
5018  LPCWSTR lpSubKey,
5019  DWORD dwType,
5020  LPCWSTR lpData,
5021  DWORD cbData)
5022 {
5023  HKEY subkey;
5024  HANDLE hKey;
5025  DWORD ret;
5026  NTSTATUS Status;
5027 
5028  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5029 
5030  if (dwType != REG_SZ || !lpData)
5031  return ERROR_INVALID_PARAMETER;
5032 
5034  hKeyOriginal);
5035  if (!NT_SUCCESS(Status))
5036  {
5037  return RtlNtStatusToDosError(Status);
5038  }
5039  subkey = hKey;
5040 
5041  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5042  {
5043  ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5044  if (ret != ERROR_SUCCESS)
5045  goto Cleanup;
5046  }
5047 
5048  ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5049  (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5050  if (subkey != hKey)
5051  RegCloseKey(subkey);
5052 
5053 Cleanup:
5055 
5056  return ret;
5057 }
5058 
5059 
5060 /************************************************************************
5061  * RegUnLoadKeyA
5062  *
5063  * @implemented
5064  */
5065 LONG WINAPI
5067  LPCSTR lpSubKey)
5068 {
5070  DWORD ErrorCode;
5071 
5072  if (lpSubKey)
5073  {
5074  if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5075  return ERROR_NOT_ENOUGH_MEMORY;
5076  }
5077  else
5078  RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5079 
5081  KeyName.Buffer);
5082 
5084 
5085  return ErrorCode;
5086 }
5087 
5088 
5089 /************************************************************************
5090  * RegUnLoadKeyW
5091  *
5092  * @implemented
5093  */
5094 LONG WINAPI
5096  LPCWSTR lpSubKey)
5097 {
5100  HANDLE KeyHandle;
5101  NTSTATUS