ReactOS  0.4.14-dev-55-g2da92ac
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 
42 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
43 static VOID CloseDefaultKeys(VOID);
44 #define ClosePredefKey(Handle) \
45  if ((ULONG_PTR)Handle & 0x1) { \
46  NtClose(Handle); \
47  }
48 #define IsPredefKey(HKey) \
49  (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey) \
51  ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
52 
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 ||
371  hKey == HKEY_CURRENT_CONFIG ||
372  hKey == HKEY_CURRENT_USER ||
373  hKey == HKEY_LOCAL_MACHINE ||
374  hKey == HKEY_PERFORMANCE_DATA ||
375  hKey == HKEY_USERS) &&
376  !IsPredefKey(hNewHKey))
377  {
378  PHANDLE Handle;
379  ULONG Index;
380 
381  Index = GetPredefKeyIndex(hKey);
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;
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 = 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 */
1115  Status = MapDefaultKey(&ParentKey,
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);
1136  ClosePredefKey(ParentKey);
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 
1159  ClosePredefKey(ParentKey);
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 
1303  Status = MapDefaultKey(&ParentKey,
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);
1313  ClosePredefKey(ParentKey);
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:
1342  ClosePredefKey(ParentKey);
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
1670 RegDeleteTreeW(IN HKEY hKey,
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 
2879  status = MapDefaultKey(&KeyHandle, hKey);
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 
3084  ErrorCode = RegLoadKeyW(hKey,
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 {
3106  OBJECT_ATTRIBUTES FileObjectAttributes;
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 
3135  InitializeObjectAttributes(&FileObjectAttributes,
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,
3150  &FileObjectAttributes);
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 && phkResult)
3268  {
3269  return ERROR_INVALID_HANDLE;
3270  }
3271 
3272  if (!lpSubKey || !*lpSubKey)
3273  {
3274  *phkResult = hKey;
3275  return ERROR_SUCCESS;
3276  }
3277 
3278  return RegOpenKeyExA(hKey,
3279  lpSubKey,
3280  0,
3282  phkResult);
3283 }
3284 
3285 
3286 /************************************************************************
3287  * RegOpenKeyW
3288  *
3289  * 19981101 Ariadne
3290  * 19990525 EA
3291  * 20050503 Fireball - imported from WINE
3292  *
3293  * @implemented
3294  */
3295 LONG WINAPI
3297  LPCWSTR lpSubKey,
3298  PHKEY phkResult)
3299 {
3300  TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3301  hKey, lpSubKey, phkResult);
3302 
3303  if (!phkResult)
3304  return ERROR_INVALID_PARAMETER;
3305 
3306  if (!hKey && lpSubKey && phkResult)
3307  {
3308  return ERROR_INVALID_HANDLE;
3309  }
3310 
3311  if (!lpSubKey || !*lpSubKey)
3312  {
3313  *phkResult = hKey;
3314  return ERROR_SUCCESS;
3315  }
3316 
3317  return RegOpenKeyExW(hKey,
3318  lpSubKey,
3319  0,
3321  phkResult);
3322 }
3323 
3324 
3325 /************************************************************************
3326  * RegOpenKeyExA
3327  *
3328  * @implemented
3329  */
3330 LONG WINAPI
3332  _In_ HKEY hKey,
3333  _In_ LPCSTR lpSubKey,
3334  _In_ DWORD ulOptions,
3335  _In_ REGSAM samDesired,
3336  _Out_ PHKEY phkResult)
3337 {
3338  UNICODE_STRING SubKeyString;
3339  LONG ErrorCode;
3340 
3341  TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3342  hKey, lpSubKey, ulOptions, samDesired, phkResult);
3343 
3344  if (lpSubKey)
3345  {
3346  if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
3347  return ERROR_NOT_ENOUGH_MEMORY;
3348  }
3349  else
3350  RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
3351 
3352  ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
3353 
3354  RtlFreeUnicodeString(&SubKeyString);
3355 
3356  return ErrorCode;
3357 }
3358 
3359 
3360 /************************************************************************
3361  * RegOpenKeyExW
3362  *
3363  * @implemented
3364  */
3365 LONG WINAPI
3367  LPCWSTR lpSubKey,
3368  DWORD ulOptions,
3369  REGSAM samDesired,
3370  PHKEY phkResult)
3371 {
3373  UNICODE_STRING SubKeyString;
3374  HANDLE KeyHandle;
3375  NTSTATUS Status;
3378 
3379  TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3380  hKey, lpSubKey, ulOptions, samDesired, phkResult);
3381  if (!phkResult)
3382  {
3383  return ERROR_INVALID_PARAMETER;
3384  }
3385 
3386  Status = MapDefaultKey(&KeyHandle, hKey);
3387  if (!NT_SUCCESS(Status))
3388  {
3389  return RtlNtStatusToDosError(Status);
3390  }
3391 
3392  if (IsHKCRKey(KeyHandle))
3393  {
3394  ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
3396  return ErrorCode;
3397  }
3398 
3399  if (ulOptions & REG_OPTION_OPEN_LINK)
3401 
3402  RtlInitUnicodeString(&SubKeyString, lpSubKey ? lpSubKey : L"");
3403 
3405  &SubKeyString,
3406  Attributes,
3407  KeyHandle,
3408  NULL);
3409 
3410  Status = NtOpenKey((PHANDLE)phkResult,
3411  samDesired,
3412  &ObjectAttributes);
3413 
3415  {
3416  HANDLE hAligned;
3417  UNICODE_STRING AlignedString;
3418 
3420  &SubKeyString,
3421  &AlignedString);
3422  if (NT_SUCCESS(Status))
3423  {
3424  /* Try again with aligned parameters */
3426  &AlignedString,
3427  Attributes,
3428  KeyHandle,
3429  NULL);
3430 
3431  Status = NtOpenKey(&hAligned,
3432  samDesired,
3433  &ObjectAttributes);
3434 
3435  RtlFreeUnicodeString(&AlignedString);
3436 
3437  if (NT_SUCCESS(Status))
3438  *phkResult = hAligned;
3439  }
3440  else
3441  {
3442  /* Restore the original error */
3444  }
3445  }
3446 
3447  if (!NT_SUCCESS(Status))
3448  {
3450  }
3451 
3452 
3454 
3455  return ErrorCode;
3456 }
3457 
3458 
3459 /************************************************************************
3460  * RegOpenUserClassesRoot
3461  *
3462  * @implemented
3463  */
3464 LONG WINAPI
3466  IN DWORD dwOptions,
3467  IN REGSAM samDesired,
3468  OUT PHKEY phkResult)
3469 {
3470  const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3471  const WCHAR UserClassesKeySuffix[] = L"_Classes";
3472  PTOKEN_USER TokenUserData;
3474  UNICODE_STRING UserSidString, UserClassesKeyRoot;
3476  NTSTATUS Status;
3477 
3478  /* check parameters */
3479  if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3480  {
3481  return ERROR_INVALID_PARAMETER;
3482  }
3483 
3484  /*
3485  * Get the user sid from the token
3486  */
3487 
3488 ReadTokenSid:
3489  /* determine how much memory we need */
3491  TokenUser,
3492  NULL,
3493  0,
3494  &RequiredLength);
3496  {
3497  /* NOTE - as opposed to all other registry functions windows does indeed
3498  change the last error code in case the caller supplied a invalid
3499  handle for example! */
3500  return RtlNtStatusToDosError(Status);
3501  }
3502  RegInitialize(); /* HACK until delay-loading is implemented */
3503  TokenUserData = RtlAllocateHeap(ProcessHeap,
3504  0,
3505  RequiredLength);
3506  if (TokenUserData == NULL)
3507  {
3508  return ERROR_NOT_ENOUGH_MEMORY;
3509  }
3510 
3511  /* attempt to read the information */
3513  TokenUser,
3514  TokenUserData,
3516  &RequiredLength);
3517  if (!NT_SUCCESS(Status))
3518  {
3520  0,
3521  TokenUserData);
3523  {
3524  /* the information appears to have changed?! try again */
3525  goto ReadTokenSid;
3526  }
3527 
3528  /* NOTE - as opposed to all other registry functions windows does indeed
3529  change the last error code in case the caller supplied a invalid
3530  handle for example! */
3531  return RtlNtStatusToDosError(Status);
3532  }
3533 
3534  /*
3535  * Build the absolute path for the user's registry in the form
3536  * "\Registry\User<SID>_Classes"
3537  */
3538  Status = RtlConvertSidToUnicodeString(&UserSidString,
3539  TokenUserData->User.Sid,
3540  TRUE);
3541 
3542  /* we don't need the user data anymore, free it */
3544  0,
3545  TokenUserData);
3546 
3547  if (!NT_SUCCESS(Status))
3548  {
3549  return RtlNtStatusToDosError(Status);
3550  }
3551 
3552  /* allocate enough memory for the entire key string */
3553  UserClassesKeyRoot.Length = 0;
3554  UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3555  sizeof(UserClassesKeyPrefix) +
3556  sizeof(UserClassesKeySuffix);
3557  UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3558  0,
3559  UserClassesKeyRoot.MaximumLength);
3560  if (UserClassesKeyRoot.Buffer == NULL)
3561  {
3562  RtlFreeUnicodeString(&UserSidString);
3563  return RtlNtStatusToDosError(Status);
3564  }
3565 
3566  /* build the string */
3567  RtlAppendUnicodeToString(&UserClassesKeyRoot,
3568  UserClassesKeyPrefix);
3569  RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3570  &UserSidString);
3571  RtlAppendUnicodeToString(&UserClassesKeyRoot,
3572  UserClassesKeySuffix);
3573 
3574  TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3575 
3576  /*
3577  * Open the key
3578  */
3580  &UserClassesKeyRoot,
3582  NULL,
3583  NULL);
3584 
3585  Status = NtOpenKey((PHANDLE)phkResult,
3586  samDesired,
3587  &ObjectAttributes);
3588 
3589  RtlFreeUnicodeString(&UserSidString);
3590  RtlFreeUnicodeString(&UserClassesKeyRoot);
3591 
3592  if (!NT_SUCCESS(Status))
3593  {
3594  return RtlNtStatusToDosError(Status);
3595  }
3596 
3597  return ERROR_SUCCESS;
3598 }
3599 
3600 
3601 /************************************************************************
3602  * RegQueryInfoKeyA
3603  *
3604  * @implemented
3605  */
3606 LONG WINAPI
3608  LPSTR lpClass,
3609  LPDWORD lpcClass,
3610  LPDWORD lpReserved,
3611  LPDWORD lpcSubKeys,
3612  LPDWORD lpcMaxSubKeyLen,
3613  LPDWORD lpcMaxClassLen,
3614  LPDWORD lpcValues,
3615  LPDWORD lpcMaxValueNameLen,
3616  LPDWORD lpcMaxValueLen,
3617  LPDWORD lpcbSecurityDescriptor,
3618  PFILETIME lpftLastWriteTime)
3619 {
3620  WCHAR ClassName[MAX_PATH];
3623  LONG ErrorCode;
3624  NTSTATUS Status;
3625  DWORD cClass = 0;
3626 
3627  if ((lpClass) && (!lpcClass))
3628  {
3629  return ERROR_INVALID_PARAMETER;
3630  }
3631 
3633  NULL);
3634  if (lpClass != NULL)
3635  {
3636  RtlInitEmptyUnicodeString(&UnicodeString,
3637  ClassName,
3638  sizeof(ClassName));
3639  cClass = sizeof(ClassName) / sizeof(WCHAR);
3640  }
3641 
3642  ErrorCode = RegQueryInfoKeyW(hKey,
3643  UnicodeString.Buffer,
3644  &cClass,
3645  lpReserved,
3646  lpcSubKeys,
3647  lpcMaxSubKeyLen,
3648  lpcMaxClassLen,
3649  lpcValues,
3650  lpcMaxValueNameLen,
3651  lpcMaxValueLen,
3652  lpcbSecurityDescriptor,
3653  lpftLastWriteTime);
3654  if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3655  {
3656  if (*lpcClass == 0)
3657  {
3658  return ErrorCode;
3659  }
3660 
3661  RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
3662  UnicodeString.Length = cClass * sizeof(WCHAR);
3664  &UnicodeString,
3665  FALSE);
3667  cClass = AnsiString.Length;
3668  lpClass[cClass] = ANSI_NULL;
3669  }
3670 
3671  if (lpcClass != NULL)
3672  {
3673  *lpcClass = cClass;
3674  }
3675 
3676  return ErrorCode;
3677 }
3678 
3679 
3680 /************************************************************************
3681  * RegQueryInfoKeyW
3682  *
3683  * @implemented
3684  */
3685 LONG WINAPI
3687  LPWSTR lpClass,
3688  LPDWORD lpcClass,
3689  LPDWORD lpReserved,
3690  LPDWORD lpcSubKeys,
3691  LPDWORD lpcMaxSubKeyLen,
3692  LPDWORD lpcMaxClassLen,
3693  LPDWORD lpcValues,
3694  LPDWORD lpcMaxValueNameLen,
3695  LPDWORD lpcMaxValueLen,
3696  LPDWORD lpcbSecurityDescriptor,
3697  PFILETIME lpftLastWriteTime)
3698 {
3699  KEY_FULL_INFORMATION FullInfoBuffer;
3700  PKEY_FULL_INFORMATION FullInfo;
3701  ULONG FullInfoSize;
3702  ULONG ClassLength = 0;
3703  HANDLE KeyHandle;
3704  NTSTATUS Status;
3705  ULONG Length;
3707 
3708  if ((lpClass) && (!lpcClass))
3709  {
3710  return ERROR_INVALID_PARAMETER;
3711  }
3712 
3714  hKey);
3715  if (!NT_SUCCESS(Status))
3716  {
3717  return RtlNtStatusToDosError(Status);
3718  }
3719 
3720  if (lpClass != NULL)
3721  {
3722  if (*lpcClass > 0)
3723  {
3724  ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3725  }
3726  else
3727  {
3728  ClassLength = 0;
3729  }
3730 
3731  FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3732  FullInfo = RtlAllocateHeap(ProcessHeap,
3733  0,
3734  FullInfoSize);
3735  if (FullInfo == NULL)
3736  {
3738  goto Cleanup;
3739  }
3740  }
3741  else
3742  {
3743  FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3744  FullInfo = &FullInfoBuffer;
3745  }
3746 
3747  if (lpcbSecurityDescriptor != NULL)
3748  *lpcbSecurityDescriptor = 0;
3749 
3752  FullInfo,
3753  FullInfoSize,
3754  &Length);
3755  TRACE("NtQueryKey() returned status 0x%X\n", Status);
3757  {
3759  goto Cleanup;
3760  }
3761 
3762  TRACE("SubKeys %d\n", FullInfo->SubKeys);
3763  if (lpcSubKeys != NULL)
3764  {
3765  *lpcSubKeys = FullInfo->SubKeys;
3766  }
3767 
3768  TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3769  if (lpcMaxSubKeyLen != NULL)
3770  {
3771  *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3772  }
3773 
3774  TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3775  if (lpcMaxClassLen != NULL)
3776  {
3777  *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3778  }
3779 
3780  TRACE("Values %lu\n", FullInfo->Values);
3781  if (lpcValues != NULL)
3782  {
3783  *lpcValues = FullInfo->Values;
3784  }
3785 
3786  TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3787  if (lpcMaxValueNameLen != NULL)
3788  {
3789  *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3790  }
3791 
3792  TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3793  if (lpcMaxValueLen != NULL)
3794  {
3795  *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3796  }
3797 
3798  if (lpcbSecurityDescriptor != NULL)
3799  {
3804  NULL,
3805  0,
3806  lpcbSecurityDescriptor);
3807  TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
3808  }
3809 
3810  if (lpftLastWriteTime != NULL)
3811  {
3812  lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3813  lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3814  }
3815 
3816  if (lpClass != NULL)
3817  {
3818  if (*lpcClass == 0)
3819  {
3820  goto Cleanup;
3821  }
3822 
3823  if (FullInfo->ClassLength > ClassLength)
3824  {
3826  }
3827  else
3828  {
3829  RtlCopyMemory(lpClass,
3830  FullInfo->Class,
3831  FullInfo->ClassLength);
3832  lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3833  }
3834  }
3835 
3836  if (lpcClass != NULL)
3837  {
3838  *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3839  }
3840 
3841 Cleanup:
3842  if (lpClass != NULL)
3843  {
3845  0,
3846  FullInfo);
3847  }
3848 
3850 
3851  return ErrorCode;
3852 }
3853 
3854 
3855 /************************************************************************
3856  * RegQueryMultipleValuesA
3857  *
3858  * @implemented
3859  */
3860 LONG WINAPI
3862  PVALENTA val_list,
3863  DWORD num_vals,
3864  LPSTR lpValueBuf,
3865  LPDWORD ldwTotsize)
3866 {
3867  ULONG i;
3868  DWORD maxBytes = *ldwTotsize;
3869  LPSTR bufptr = lpValueBuf;
3870  LONG ErrorCode;
3871 
3872  if (maxBytes >= (1024*1024))
3873  return ERROR_MORE_DATA;
3874 
3875  *ldwTotsize = 0;
3876 
3877  TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3878  hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3879 
3880  for (i = 0; i < num_vals; i++)
3881  {
3882  val_list[i].ve_valuelen = 0;
3883  ErrorCode = RegQueryValueExA(hKey,
3884  val_list[i].ve_valuename,
3885  NULL,
3886  NULL,
3887  NULL,
3888  &val_list[i].ve_valuelen);
3889  if (ErrorCode != ERROR_SUCCESS)
3890  {
3891  return ErrorCode;
3892  }
3893 
3894  if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3895  {
3896  ErrorCode = RegQueryValueExA(hKey,
3897  val_list[i].ve_valuename,
3898  NULL,
3899  &val_list[i].ve_type,
3900  (LPBYTE)bufptr,
3901  &val_list[i].ve_valuelen);
3902  if (ErrorCode != ERROR_SUCCESS)
3903  {
3904  return ErrorCode;
3905  }
3906 
3907  val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3908 
3909  bufptr += val_list[i].ve_valuelen;
3910  }
3911 
3912  *ldwTotsize += val_list[i].ve_valuelen;
3913  }
3914 
3915  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3916 }
3917 
3918 
3919 /************************************************************************
3920  * RegQueryMultipleValuesW
3921  *
3922  * @implemented
3923  */
3924 LONG WINAPI
3926  PVALENTW val_list,
3927  DWORD num_vals,
3928  LPWSTR lpValueBuf,
3929  LPDWORD ldwTotsize)
3930 {
3931  ULONG i;
3932  DWORD maxBytes = *ldwTotsize;
3933  LPSTR bufptr = (LPSTR)lpValueBuf;
3934  LONG ErrorCode;
3935 
3936  if (maxBytes >= (1024*1024))
3937  return ERROR_MORE_DATA;
3938 
3939  *ldwTotsize = 0;
3940 
3941  TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3942  hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3943 
3944  for (i = 0; i < num_vals; i++)
3945  {
3946  val_list[i].ve_valuelen = 0;
3947  ErrorCode = RegQueryValueExW(hKey,
3948  val_list[i].ve_valuename,
3949  NULL,
3950  NULL,
3951  NULL,
3952  &val_list[i].ve_valuelen);
3953  if (ErrorCode != ERROR_SUCCESS)
3954  {
3955  return ErrorCode;
3956  }
3957 
3958  if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3959  {
3960  ErrorCode = RegQueryValueExW(hKey,
3961  val_list[i].ve_valuename,
3962  NULL,
3963  &val_list[i].ve_type,
3964  (LPBYTE)bufptr,
3965  &val_list[i].ve_valuelen);
3966  if (ErrorCode != ERROR_SUCCESS)
3967  {
3968  return ErrorCode;
3969  }
3970 
3971  val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3972 
3973  bufptr += val_list[i].ve_valuelen;
3974  }
3975 
3976  *ldwTotsize += val_list[i].ve_valuelen;
3977  }
3978 
3979  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3980 }
3981 
3982 
3983 /************************************************************************
3984  * RegQueryReflectionKey
3985  *
3986  * @unimplemented
3987  */
3988 LONG WINAPI
3990  OUT BOOL* bIsReflectionDisabled)
3991 {
3992  FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3993  hBase, bIsReflectionDisabled);
3995 }
3996 
3997 
3998 /******************************************************************************
3999  * RegQueryValueExA [ADVAPI32.@]
4000  *
4001  * Get the type and contents of a specified value under with a key.
4002  *
4003  * PARAMS
4004  * hkey [I] Handle of the key to query
4005  * name [I] Name of value under hkey to query
4006  * reserved [I] Reserved - must be NULL
4007  * type [O] Destination for the value type, or NULL if not required
4008  * data [O] Destination for the values contents, or NULL if not required
4009  * count [I/O] Size of data, updated with the number of bytes returned
4010  *
4011  * RETURNS
4012  * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4013  * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4014  * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4015  * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4016  *
4017  * NOTES
4018  * MSDN states that if data is too small it is partially filled. In reality
4019  * it remains untouched.
4020  */
4021 LONG
4022 WINAPI
4024  _In_ HKEY hkeyorg,
4025  _In_ LPCSTR name,
4030 {
4032  DWORD DataLength;
4033  DWORD ErrorCode;
4034  DWORD BufferSize = 0;
4035  WCHAR* Buffer;
4036  CHAR* DataStr = (CHAR*)data;
4037  DWORD LocalType;
4038 
4039  /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4040  if ((data && !count) || reserved)
4041  return ERROR_INVALID_PARAMETER;
4042 
4043  if (name)
4044  {
4046  return ERROR_NOT_ENOUGH_MEMORY;
4047  }
4048  else
4049  RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4050 
4051  ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4052  if (ErrorCode != ERROR_SUCCESS)
4053  {
4054  if ((!data) && count)
4055  *count = 0;
4057  return ErrorCode;
4058  }
4059 
4060  /* See if we can directly handle the call without caring for conversion */
4061  if (!is_string(LocalType) || !count)
4062  {
4063  ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4065  return ErrorCode;
4066  }
4067 
4068  /* Allocate a unicode string to get the data */
4069  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4070  if (!Buffer)
4071  {
4073  return ERROR_NOT_ENOUGH_MEMORY;
4074  }
4075 
4077  if (ErrorCode != ERROR_SUCCESS)
4078  {
4079  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4081  return ErrorCode;
4082  }
4083 
4084  /* We don't need this anymore */
4086 
4087  DataLength = *count;
4089 
4090  if ((!data) || (DataLength < *count))
4091  {
4092  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4093  return data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4094  }
4095 
4096  /* We can finally do the conversion */
4098 
4099  /* NULL-terminate if there is enough room */
4100  if ((DataLength > *count) && (DataStr[*count - 1] != '\0'))
4101  DataStr[*count] = '\0';
4102 
4103  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4104 
4105  return ERROR_SUCCESS;
4106 }
4107 
4108 
4109 /************************************************************************
4110  * RegQueryValueExW
4111  *
4112  * @implemented
4113  */
4114 LONG
4115 WINAPI
4117  _In_ HKEY hkeyorg,
4118  _In_ LPCWSTR name,
4120  _In_ LPDWORD type,
4121  _In_ LPBYTE data,
4122  _In_ LPDWORD count)
4123 {
4124  HANDLE hkey;
4125  NTSTATUS status;
4126  UNICODE_STRING name_str;
4127  DWORD total_size;
4128  char buffer[256], *buf_ptr = buffer;
4130  static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4131 
4132  TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4133  hkeyorg, debugstr_w(name), reserved, type, data, count,
4134  (count && data) ? *count : 0 );
4135 
4136  if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4137 
4138  status = MapDefaultKey(&hkey, hkeyorg);
4139  if (!NT_SUCCESS(status))
4140  {
4141  return RtlNtStatusToDosError(status);
4142  }
4143 
4144  if (IsHKCRKey(hkey))
4145  {
4147  ClosePredefKey(hkey);
4148  return ErrorCode;
4149  }
4150 
4151  RtlInitUnicodeString( &name_str, name );
4152 
4153  if (data)
4154  total_size = min( sizeof(buffer), *count + info_size );
4155  else
4156  total_size = info_size;
4157 
4158 
4160  buffer, total_size, &total_size );
4161 
4163  {
4164  // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4165  // On windows these conditions are likely to be side effects of the implementation...
4166  if (status == STATUS_INVALID_HANDLE && hkey)
4167  {
4168  if (type) *type = REG_NONE;
4169  if (count) *count = 0;
4170  }
4172  {
4173  if (type) *type = REG_NONE;
4174  if (data == NULL && count) *count = 0;
4175  }
4176  goto done;
4177  }
4178 
4179  if (data)
4180  {
4181  /* retry with a dynamically allocated buffer */
4182  while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4183  {
4184  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4185  if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4186  {
4187  ClosePredefKey(hkey);
4188  return ERROR_NOT_ENOUGH_MEMORY;
4189  }
4190  info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4192  buf_ptr, total_size, &total_size );
4193  }
4194 
4195  if (NT_SUCCESS(status))
4196  {
4197  memcpy( data, buf_ptr + info_size, total_size - info_size );
4198  /* if the type is REG_SZ and data is not 0-terminated
4199  * and there is enough space in the buffer NT appends a \0 */
4200  if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4201  {
4202  WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4203  if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4204  }
4205  }
4206  else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4207  }
4208  else status = STATUS_SUCCESS;
4209 
4210  if (type) *type = info->Type;
4211  if (count) *count = total_size - info_size;
4212 
4213  done:
4214  if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4215  ClosePredefKey(hkey);
4216  return RtlNtStatusToDosError(status);
4217 }
4218 
4219 
4220 /************************************************************************
4221  * RegQueryValueA
4222  *
4223  * @implemented
4224  */
4226 {
4227  DWORD ret;
4228  HKEY subkey = hkey;
4229 
4230  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4231 
4232  if (name && name[0])
4233  {
4234  if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4235  }
4236  ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4237  if (subkey != hkey) RegCloseKey( subkey );
4238  if (ret == ERROR_FILE_NOT_FOUND)
4239  {
4240  /* return empty string if default value not found */
4241  if (data) *data = 0;
4242  if (count) *count = 1;
4243  ret = ERROR_SUCCESS;
4244  }
4245  return ret;
4246 }
4247 
4248 
4249 /************************************************************************
4250  * RegQueryValueW
4251  *
4252  * @implemented
4253  */
4255 {
4256  DWORD ret;
4257  HKEY subkey = hkey;
4258 
4259  TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4260  if (hkey == NULL)
4261  {
4262  return ERROR_INVALID_HANDLE;
4263  }
4264  if (name && name[0])
4265  {
4266  ret = RegOpenKeyW( hkey, name, &subkey);
4267  if (ret != ERROR_SUCCESS)
4268  {
4269  return ret;
4270  }
4271  }
4272 
4273  ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4274 
4275  if (subkey != hkey)
4276  {
4277  RegCloseKey( subkey );
4278  }
4279 
4280  if (ret == ERROR_FILE_NOT_FOUND)
4281  {
4282  /* return empty string if default value not found */
4283  if (data)
4284  *data = 0;
4285  if (count)
4286  *count = sizeof(WCHAR);
4287  ret = ERROR_SUCCESS;
4288  }
4289  return ret;
4290 }
4291 
4292 
4293 /************************************************************************
4294  * RegReplaceKeyA
4295  *
4296  * @implemented
4297  */
4298 LONG WINAPI
4300  LPCSTR lpSubKey,
4301  LPCSTR lpNewFile,
4302  LPCSTR lpOldFile)
4303 {
4304  UNICODE_STRING SubKey;
4305  UNICODE_STRING NewFile;
4306  UNICODE_STRING OldFile;
4307  LONG ErrorCode;
4308 
4309  RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4310  RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4311  RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4312 
4313  if (lpSubKey)
4314  {
4315  if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4316  {
4318  goto Exit;
4319  }
4320  }
4321 
4322  if (lpOldFile)
4323  {
4324  if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4325  {
4327  goto Exit;
4328  }
4329  }
4330 
4331  if (lpNewFile)
4332  {
4333  if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4334  {
4336  goto Exit;
4337  }
4338  }
4339 
4340  ErrorCode = RegReplaceKeyW(hKey,
4341  SubKey.Buffer,
4342  NewFile.Buffer,
4343  OldFile.Buffer);
4344 
4345 Exit:
4346  RtlFreeUnicodeString(&OldFile);
4347  RtlFreeUnicodeString(&NewFile);
4348  RtlFreeUnicodeString(&SubKey);
4349 
4350  return ErrorCode;
4351 }
4352 
4353 
4354 /************************************************************************
4355  * RegReplaceKeyW
4356  *
4357  * @unimplemented
4358  */
4359 LONG WINAPI
4361  LPCWSTR lpSubKey,
4362  LPCWSTR lpNewFile,
4363  LPCWSTR lpOldFile)
4364 {
4365  OBJECT_ATTRIBUTES KeyObjectAttributes;
4366  OBJECT_ATTRIBUTES NewObjectAttributes;
4367  OBJECT_ATTRIBUTES OldObjectAttributes;
4369  UNICODE_STRING NewFileName;
4370  UNICODE_STRING OldFileName;
4371  BOOLEAN CloseRealKey;
4372  HANDLE RealKeyHandle;
4373  HANDLE KeyHandle;
4374  NTSTATUS Status;
4376 
4377  if (hKey == HKEY_PERFORMANCE_DATA)
4378  {
4379  return ERROR_INVALID_HANDLE;
4380  }
4381 
4383  hKey);
4384  if (!NT_SUCCESS(Status))
4385  {
4386  return RtlNtStatusToDosError(Status);
4387  }
4388 
4389  /* Open the real key */
4390  if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4391  {
4392  RtlInitUnicodeString(&SubKeyName, lpSubKey);
4393  InitializeObjectAttributes(&KeyObjectAttributes,
4394  &SubKeyName,
4396  KeyHandle,
4397  NULL);
4398  Status = NtOpenKey(&RealKeyHandle,
4400  &KeyObjectAttributes);
4401  if (!NT_SUCCESS(Status))
4402  {
4404  goto Cleanup;
4405  }
4406 
4407  CloseRealKey = TRUE;
4408  }
4409  else
4410  {
4411  RealKeyHandle = KeyHandle;
4412  CloseRealKey = FALSE;
4413  }
4414 
4415  /* Convert new file name */
4416  if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4417  &NewFileName,
4418  NULL,
4419  NULL))
4420  {
4421  if (CloseRealKey)
4422  {
4423  NtClose(RealKeyHandle);
4424  }
4425 
4427  goto Cleanup;
4428  }
4429 
4430  InitializeObjectAttributes(&NewObjectAttributes,
4431  &NewFileName,
4433  NULL,
4434  NULL);
4435 
4436  /* Convert old file name */
4437  if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4438  &OldFileName,
4439  NULL,
4440  NULL))
4441  {
4442  RtlFreeHeap(RtlGetProcessHeap (),
4443  0,
4444  NewFileName.Buffer);
4445  if (CloseRealKey)
4446  {
4447  NtClose(RealKeyHandle);
4448  }
4449 
4451  goto Cleanup;
4452  }
4453 
4454  InitializeObjectAttributes(&OldObjectAttributes,
4455  &OldFileName,
4457  NULL,
4458  NULL);
4459 
4460  Status = NtReplaceKey(&NewObjectAttributes,
4461  RealKeyHandle,
4462  &OldObjectAttributes);
4463 
4464  RtlFreeHeap(RtlGetProcessHeap(),
4465  0,
4466  OldFileName.Buffer);
4467  RtlFreeHeap(RtlGetProcessHeap(),
4468  0,
4469  NewFileName.Buffer);
4470 
4471  if (CloseRealKey)
4472  {
4473  NtClose(RealKeyHandle);
4474  }
4475 
4476  if (!NT_SUCCESS(Status))
4477  {
4478  return RtlNtStatusToDosError(Status);
4479  }
4480 
4481 Cleanup:
4483 
4484  return ErrorCode;
4485 }
4486 
4487 
4488 /************************************************************************
4489  * RegRestoreKeyA
4490  *
4491  * @implemented
4492  */
4493 LONG WINAPI
4495  LPCSTR lpFile,
4496  DWORD dwFlags)
4497 {
4499  LONG ErrorCode;
4500 
4501  if (lpFile)
4502  {
4504  return ERROR_NOT_ENOUGH_MEMORY;
4505  }
4506  else
4507  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4508 
4509  ErrorCode = RegRestoreKeyW(hKey,
4510  FileName.Buffer,
4511  dwFlags);
4512 
4514 
4515  return ErrorCode;
4516 }
4517 
4518 
4519 /************************************************************************
4520  * RegRestoreKeyW
4521  *
4522  * @implemented
4523  */
4524 LONG WINAPI
4526  LPCWSTR lpFile,
4527  DWORD dwFlags)
4528 {
4533  HANDLE KeyHandle;
4534  NTSTATUS Status;
4535 
4536  if (hKey == HKEY_PERFORMANCE_DATA)
4537  {
4538  return ERROR_INVALID_HANDLE;
4539  }
4540 
4542  hKey);
4543  if (!NT_SUCCESS(Status))
4544  {
4545  return RtlNtStatusToDosError(Status);
4546  }
4547 
4548  if (!RtlDosPathNameToNtPathName_U(lpFile,
4549  &FileName,
4550  NULL,
4551  NULL))
4552  {
4554  goto Cleanup;
4555  }
4556 
4558  &FileName,
4560  NULL,
4561  NULL);
4562 
4566  &IoStatusBlock,
4569  RtlFreeHeap(RtlGetProcessHeap(),
4570  0,
4571  FileName.Buffer);
4572  if (!NT_SUCCESS(Status))
4573  {
4574  goto Cleanup;
4575  }
4576 
4578  FileHandle,
4579  (ULONG)dwFlags);
4580  NtClose (FileHandle);
4581 
4582 Cleanup:
4584 
4585  if (!NT_SUCCESS(Status))
4586  {
4587  return RtlNtStatusToDosError(Status);
4588  }
4589 
4590  return ERROR_SUCCESS;
4591 }
4592 
4593 
4594 /************************************************************************
4595  * RegSaveKeyA
4596  *
4597  * @implemented
4598  */
4599 LONG WINAPI
4601  LPCSTR lpFile,
4602  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4603 {
4605  LONG ErrorCode;
4606 
4607  if (lpFile)
4608  {
4610  return ERROR_NOT_ENOUGH_MEMORY;
4611  }
4612  else
4613  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4614 
4615  ErrorCode = RegSaveKeyW(hKey,
4616  FileName.Buffer,
4617  lpSecurityAttributes);
4619 
4620  return ErrorCode;
4621 }
4622 
4623 
4624 /************************************************************************
4625  * RegSaveKeyW
4626  *
4627  * @implemented
4628  */
4629 LONG WINAPI
4631  LPCWSTR lpFile,
4632  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4633 {
4639  HANDLE KeyHandle;
4640  NTSTATUS Status;
4641 
4643  hKey);
4644  if (!NT_SUCCESS(Status))
4645  {
4646  return RtlNtStatusToDosError(Status);
4647  }
4648 
4649  if (!RtlDosPathNameToNtPathName_U(lpFile,
4650  &FileName,
4651  NULL,
4652  NULL))
4653  {
4655  goto Cleanup;
4656  }
4657 
4658  if (lpSecurityAttributes != NULL)
4659  {
4660  SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4661  }
4662 
4664  &FileName,
4666  NULL,
4671  &IoStatusBlock,
4672  NULL,
4675  FILE_CREATE,
4677  NULL,
4678  0);
4679  RtlFreeHeap(RtlGetProcessHeap(),
4680  0,
4681  FileName.Buffer);
4682  if (!NT_SUCCESS(Status))
4683  {
4684  goto Cleanup;
4685  }
4686 
4688  FileHandle);
4689  NtClose (FileHandle);
4690 
4691 Cleanup:
4693 
4694  if (!NT_SUCCESS(Status))
4695  {
4696  return RtlNtStatusToDosError(Status);
4697  }
4698 
4699  return ERROR_SUCCESS;
4700 }
4701 
4702 
4703 /************************************************************************
4704  * RegSaveKeyExA
4705  *
4706  * @implemented
4707  */
4708 LONG
4709 WINAPI
4711  LPCSTR lpFile,
4712  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4713  DWORD Flags)
4714 {
4716  LONG ErrorCode;
4717 
4718  if (lpFile)
4719  {
4721  return ERROR_NOT_ENOUGH_MEMORY;
4722  }
4723  else
4724  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4725 
4726  ErrorCode = RegSaveKeyExW(hKey,
4727  FileName.Buffer,
4728  lpSecurityAttributes,
4729  Flags);
4731 
4732  return ErrorCode;
4733 }
4734 
4735 
4736 /************************************************************************
4737  * RegSaveKeyExW
4738  *
4739  * @unimplemented
4740  */
4741 LONG
4742 WINAPI
4744  LPCWSTR lpFile,
4745  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4746  DWORD Flags)
4747 {
4748  switch (Flags)
4749  {
4750  case REG_STANDARD_FORMAT:
4751  case REG_LATEST_FORMAT:
4752  case REG_NO_COMPRESSION:
4753  break;
4754  default:
4755  return ERROR_INVALID_PARAMETER;
4756  }
4757 
4758  FIXME("RegSaveKeyExW(): Flags ignored!\n");
4759 
4760  return RegSaveKeyW(hKey,
4761  lpFile,
4762  lpSecurityAttributes);
4763 }
4764 
4765 
4766 /************************************************************************
4767  * RegSetKeySecurity
4768  *
4769  * @implemented
4770  */
4771 LONG WINAPI
4774  PSECURITY_DESCRIPTOR pSecurityDescriptor)
4775 {
4776  HANDLE KeyHandle;
4777  NTSTATUS Status;
4778 
4779  if (hKey == HKEY_PERFORMANCE_DATA)
4780  {
4781  return ERROR_INVALID_HANDLE;
4782  }
4783 
4785  hKey);
4786  if (!NT_SUCCESS(Status))
4787  {
4788  return RtlNtStatusToDosError(Status);
4789  }
4790 
4793  pSecurityDescriptor);
4794 
4796 
4797  if (!NT_SUCCESS(Status))
4798  {
4799  return RtlNtStatusToDosError(Status);
4800  }
4801 
4802  return ERROR_SUCCESS;
4803 }
4804 
4805 
4806 /************************************************************************
4807  * RegSetValueExA
4808  *
4809  * @implemented
4810  */
4811 LONG WINAPI
4813  LPCSTR lpValueName,
4814  DWORD Reserved,
4815  DWORD dwType,
4816  CONST BYTE* lpData,
4817  DWORD cbData)
4818 {
4820  LPWSTR pValueName;
4823  LONG ErrorCode;
4824  LPBYTE pData;
4825  DWORD DataSize;
4826  NTSTATUS Status;
4827 
4828  /* Convert SubKey name to Unicode */
4829  if (lpValueName != NULL && lpValueName[0] != '\0')
4830  {
4831  if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
4832  return ERROR_NOT_ENOUGH_MEMORY;
4833  }
4834  else
4835  {
4836  ValueName.Buffer = NULL;
4837  }
4838 
4839  pValueName = (LPWSTR)ValueName.Buffer;
4840 
4841 
4842  if (is_string(dwType) && (cbData != 0))
4843  {
4844  /* Convert ANSI string Data to Unicode */
4845  /* If last character NOT zero then increment length */
4846  LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4847  AnsiString.Buffer = (PSTR)lpData;
4848  AnsiString.Length = cbData + bNoNulledStr;
4849  AnsiString.MaximumLength = cbData + bNoNulledStr;
4851  &AnsiString,
4852  TRUE);
4853 
4854  if (!NT_SUCCESS(Status))
4855  {
4856  if (pValueName != NULL)
4858 
4859  return RtlNtStatusToDosError(Status);
4860  }
4861  pData = (LPBYTE)Data.Buffer;
4862  DataSize = cbData * sizeof(WCHAR);
4863  }
4864  else
4865  {
4866  Data.Buffer = NULL;
4867  pData = (LPBYTE)lpData;
4868  DataSize = cbData;
4869  }
4870 
4871  ErrorCode = RegSetValueExW(hKey,
4872  pValueName,
4873  Reserved,
4874  dwType,
4875  pData,
4876  DataSize);
4877 
4878  if (pValueName != NULL)
4880 
4881  if (Data.Buffer != NULL)
4883 
4884  return ErrorCode;
4885 }
4886 
4887 
4888 /************************************************************************
4889  * RegSetValueExW
4890  *
4891  * @implemented
4892  */
4893 LONG
4894 WINAPI
4896  _In_ HKEY hKey,
4897  _In_ LPCWSTR lpValueName,
4899  _In_ DWORD dwType,
4900  _In_ CONST BYTE* lpData,
4901  _In_ DWORD cbData)
4902 {
4904  HANDLE KeyHandle;
4905  NTSTATUS Status;
4906 
4908  hKey);
4909  if (!NT_SUCCESS(Status))
4910  {
4911  return RtlNtStatusToDosError(Status);
4912  }
4913 
4914  if (IsHKCRKey(KeyHandle))
4915  {
4916  LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4918  return ErrorCode;
4919  }
4920 
4921  if (is_string(dwType) && (cbData != 0))
4922  {
4923  PWSTR pwsData = (PWSTR)lpData;
4924 
4925  _SEH2_TRY
4926  {
4927  if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4928  (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4929  {
4930  /* Increment length if last character is not zero and next is zero */
4931  cbData += sizeof(WCHAR);
4932  }
4933  }
4935  {
4937  return ERROR_NOACCESS;
4938  }
4939  _SEH2_END;
4940  }
4941 
4942  RtlInitUnicodeString(&ValueName, lpValueName);
4943 
4945  &ValueName,
4946  0,
4947  dwType,
4948  (PVOID)lpData,
4949  (ULONG)cbData);
4950 
4952 
4953  if (!NT_SUCCESS(Status))
4954  {
4955  return RtlNtStatusToDosError(Status);
4956  }
4957 
4958  return ERROR_SUCCESS;
4959 }
4960 
4961 
4962 /************************************************************************
4963  * RegSetValueA
4964  *
4965  * @implemented
4966  */
4967 LONG WINAPI
4968 RegSetValueA(HKEY hKeyOriginal,
4969  LPCSTR lpSubKey,
4970  DWORD dwType,
4971  LPCSTR lpData,
4972  DWORD cbData)
4973 {
4974  HKEY subkey;
4975  HANDLE hKey;
4976  DWORD ret;
4977  NTSTATUS Status;
4978 
4979  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4980 
4981  if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4982 
4983  Status = MapDefaultKey(&hKey, hKeyOriginal);
4984  if (!NT_SUCCESS(Status))
4985  {
4986  return RtlNtStatusToDosError (Status);
4987  }
4988  subkey = hKey;
4989 
4990  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4991  {
4992  ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4993  if (ret != ERROR_SUCCESS)
4994  goto Cleanup;
4995  }
4996 
4997  ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
4998  if (subkey != hKey)
4999  RegCloseKey(subkey);
5000 
5001 Cleanup:
5002  ClosePredefKey(hKey);
5003 
5004  return ret;
5005 }
5006 
5007 
5008 /************************************************************************
5009  * RegSetValueW
5010  *
5011  * @implemented
5012  */
5013 LONG WINAPI
5014 RegSetValueW(HKEY hKeyOriginal,
5015  LPCWSTR lpSubKey,
5016  DWORD dwType,
5017  LPCWSTR lpData,
5018  DWORD cbData)
5019 {
5020  HKEY subkey;
5021  HANDLE hKey;
5022  DWORD ret;
5023  NTSTATUS Status;
5024 
5025  TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5026 
5027  if (dwType != REG_SZ || !lpData)
5028  return ERROR_INVALID_PARAMETER;
5029 
5030  Status = MapDefaultKey(&hKey,
5031  hKeyOriginal);
5032  if (!NT_SUCCESS(Status))
5033  {
5034  return RtlNtStatusToDosError(Status);
5035  }
5036  subkey = hKey;
5037 
5038  if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5039  {
5040  ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5041  if (ret != ERROR_SUCCESS)
5042  goto Cleanup;
5043  }
5044 
5045  ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5046  (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5047  if (subkey != hKey)
5048  RegCloseKey(subkey);
5049 
5050 Cleanup:
5051  ClosePredefKey(hKey);
5052 
5053  return ret;
5054 }
5055 
5056 
5057 /************************************************************************
5058  * RegUnLoadKeyA
5059  *
5060  * @implemented
5061  */
5062 LONG WINAPI
5064  LPCSTR lpSubKey)
5065 {
5067  DWORD ErrorCode;
5068 
5069  if (lpSubKey)
5070  {
5071  if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5072  return ERROR_NOT_ENOUGH_MEMORY;
5073  }
5074  else
5075  RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5076 
5077  ErrorCode = RegUnLoadKeyW(hKey,
5078  KeyName.Buffer);
5079 
5081 
5082  return ErrorCode;
5083 }
5084 
5085 
5086 /************************************************************************
5087  * RegUnLoadKeyW
5088  *
5089  * @implemented
5090  */
5091 LONG WINAPI
5093  LPCWSTR lpSubKey)
5094 {
5097  HANDLE KeyHandle;
5098  NTSTATUS Status;
5099 
5100  if (hKey == HKEY_PERFORMANCE_DATA)
5101  {
5102  return ERROR_INVALID_HANDLE;
5103  }
5104 
5105  Status = MapDefaultKey(&KeyHandle, hKey);
5106  if (!NT_SUCCESS(Status))
5107  {
5108  return RtlNtStatusToDosError(Status);
5109  }
5110 
5111  RtlInitUnicodeString(&KeyName, lpSubKey);
5112 
5114  &KeyName,
5116  KeyHandle,
5117  NULL);
5118 
5120 
5122 
5123  if (!NT_SUCCESS(Status))
5124  {
5125  return RtlNtStatusToDosError(Status);
5126  }
5127 
5128  return ERROR_SUCCESS;
5129 }
5130 
5131 /* EOF */
LSTATUS WINAPI RegGetValueW(HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData)
Definition: reg.c:1965
#define HKEY_USERS
Definition: winreg.h:13
LONG WINAPI RegDeleteKeyValueA(IN HKEY hKey, IN LPCSTR lpSubKey OPTIONAL, IN LPCSTR lpValueName OPTIONAL)
Definition: reg.c:1428
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle)
#define FILE_GENERIC_READ
Definition: nt_native.h:653
LONG WINAPI RegSaveKeyExW(HKEY hKey, LPCWSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD Flags)
Definition: reg.c:4743
#define MAXIMUM_ALLOWED
Definition: nt_native.h:83
DWORD dwOptions
Definition: solitaire.cpp:23
LONG WINAPI RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3257
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
LONG WINAPI RegQueryValueExA(_In_ HKEY hkeyorg, _In_ LPCSTR name, _In_ LPDWORD reserved, _Out_opt_ LPDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ LPDWORD count)
Definition: reg.c:4023
#define IN
Definition: typedefs.h:38
#define max(a, b)
Definition: svc.c:63
static VOID CloseDefaultKeys(VOID)
Definition: reg.c:216
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
static IN PWSTR
Definition: reg.c:123
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
#define REG_STANDARD_FORMAT
Definition: cmtypes.h:97
*BytesInUnicodeString PWCH UnicodeString
Definition: rtlfuncs.h:1980
NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
Definition: ntapi.c:240
LSTATUS WINAPI RegQueryValueA(HKEY hkey, LPCSTR name, LPSTR data, LPLONG count)
Definition: reg.c:4225
LONG WINAPI RegOverridePredefKey(IN HKEY hKey, IN HKEY hNewHKey OPTIONAL)
Definition: reg.c:365
LONG WINAPI SetHKCRValue(_In_ HKEY hKey, _In_ LPCWSTR Name, _In_ DWORD Reserved, _In_ DWORD Type, _In_ CONST BYTE *Data, _In_ DWORD DataSize)
Definition: hkcr.c:523
#define STATUS_NO_MORE_ENTRIES
Definition: ntstatus.h:193
#define ERROR_SUCCESS
Definition: deptool.c:10
#define DWORD_PTR
Definition: treelist.c:76
static unsigned int bufptr
Definition: tncon.cpp:77
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ PNDIS_STRING SubKeyName
Definition: ndis.h:4723
#define KEY_SET_VALUE
Definition: nt_native.h:1017
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4711
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
LONG WINAPI RegDeleteKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ REGSAM samDesired, _In_ DWORD Reserved)
Definition: reg.c:1252
USHORT MaximumLength
Definition: env_spec_w32.h:370
FORCEINLINE void MakeHKCRKey(_Inout_ HKEY *hKey)
Definition: reg.h:20
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
LONG WINAPI RegUnLoadKeyA(HKEY hKey, LPCSTR lpSubKey)
Definition: reg.c:5063
#define REG_BINARY
Definition: nt_native.h:1496
#define KEY_READ
Definition: nt_native.h:1023
_In_ USHORT _In_ ULONG _In_ PSOCKADDR _In_ PSOCKADDR _Reserved_ ULONG _In_opt_ PVOID _In_opt_ const WSK_CLIENT_CONNECTION_DISPATCH _In_opt_ PEPROCESS _In_opt_ PETHREAD _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor
Definition: wsk.h:182
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135