xref: /reactos/dll/win32/advapi32/reg/reg.c (revision 2449ed5d)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/advapi32/reg/reg.c
5  * PURPOSE:         Registry functions
6  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
7  *                  Thomas Weidenmueller <w3seek@reactos.com>
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  *                  19990309 EA Stubs
11  *                  20050502 Fireball imported some stuff from WINE
12  */
13 
14 /* INCLUDES *****************************************************************/
15 
16 #include <advapi32.h>
17 
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
20 
21 #include "reg.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(reg);
24 
25 /* DEFINES ******************************************************************/
26 
27 #define MAX_DEFAULT_HANDLES   6
28 #define REG_MAX_NAME_SIZE     256
29 #define REG_MAX_DATA_SIZE     2048
30 
31 /* GLOBALS ******************************************************************/
32 
33 static RTL_CRITICAL_SECTION HandleTableCS;
34 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
35 static HANDLE ProcessHeap;
36 static BOOLEAN DefaultHandlesDisabled = FALSE;
37 static BOOLEAN DefaultHandleHKUDisabled = FALSE;
38 static BOOLEAN DllInitialized = FALSE; /* HACK */
39 
40 /* PROTOTYPES ***************************************************************/
41 
42 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
43 static VOID CloseDefaultKeys(VOID);
44 #define ClosePredefKey(Handle)                                                 \
45     if ((ULONG_PTR)Handle & 0x1) {                                             \
46         NtClose(Handle);                                                       \
47     }
48 #define IsPredefKey(HKey)                                                      \
49     (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey)                                                \
51     ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
52 
53 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
54 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
55 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
56 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
57 
58 
59 /* FUNCTIONS ****************************************************************/
60 /* check if value type needs string conversion (Ansi<->Unicode) */
is_string(DWORD type)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
RegInitialize(VOID)70 RegInitialize(VOID)
71 {
72     TRACE("RegInitialize()\n");
73 
74     /* Lazy init hack */
75     if (!DllInitialized)
76     {
77         ProcessHeap = RtlGetProcessHeap();
78         RtlZeroMemory(DefaultHandleTable,
79                       MAX_DEFAULT_HANDLES * sizeof(HANDLE));
80         RtlInitializeCriticalSection(&HandleTableCS);
81 
82         DllInitialized = TRUE;
83     }
84 
85     return TRUE;
86 }
87 
88 
89 /************************************************************************
90  *  RegInit
91  */
92 BOOL
RegCleanup(VOID)93 RegCleanup(VOID)
94 {
95     TRACE("RegCleanup()\n");
96 
97     CloseDefaultKeys();
98     RtlDeleteCriticalSection(&HandleTableCS);
99 
100     return TRUE;
101 }
102 
103 
104 static NTSTATUS
OpenPredefinedKey(IN ULONG Index,OUT HANDLE Handle)105 OpenPredefinedKey(IN ULONG Index,
106                   OUT HANDLE Handle)
107 {
108     NTSTATUS Status;
109 
110     switch (Index)
111     {
112         case 0: /* HKEY_CLASSES_ROOT */
113             Status = OpenClassesRootKey (Handle);
114             break;
115 
116         case 1: /* HKEY_CURRENT_USER */
117             Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
118                                          Handle);
119             break;
120 
121         case 2: /* HKEY_LOCAL_MACHINE */
122             Status = OpenLocalMachineKey (Handle);
123             break;
124 
125         case 3: /* HKEY_USERS */
126             Status = OpenUsersKey (Handle);
127             break;
128 #if 0
129         case 4: /* HKEY_PERFORMANCE_DATA */
130             Status = OpenPerformanceDataKey (Handle);
131             break;
132 #endif
133 
134         case 5: /* HKEY_CURRENT_CONFIG */
135             Status = OpenCurrentConfigKey (Handle);
136             break;
137 
138         case 6: /* HKEY_DYN_DATA */
139             Status = STATUS_NOT_IMPLEMENTED;
140             break;
141 
142         default:
143             WARN("MapDefaultHandle() no handle creator\n");
144             Status = STATUS_INVALID_PARAMETER;
145             break;
146     }
147 
148     return Status;
149 }
150 
151 
152 static NTSTATUS
MapDefaultKey(OUT PHANDLE RealKey,IN HKEY Key)153 MapDefaultKey(OUT PHANDLE RealKey,
154               IN HKEY Key)
155 {
156     PHANDLE Handle;
157     ULONG Index;
158     BOOLEAN DoOpen, DefDisabled;
159     NTSTATUS Status = STATUS_SUCCESS;
160 
161     TRACE("MapDefaultKey (Key %x)\n", Key);
162 
163     if (!IsPredefKey(Key))
164     {
165         *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
166         return STATUS_SUCCESS;
167     }
168 
169     /* Handle special cases here */
170     Index = GetPredefKeyIndex(Key);
171     if (Index >= MAX_DEFAULT_HANDLES)
172     {
173         return STATUS_INVALID_PARAMETER;
174     }
175     RegInitialize(); /* HACK until delay-loading is implemented */
176     RtlEnterCriticalSection (&HandleTableCS);
177 
178     if (Key == HKEY_CURRENT_USER)
179         DefDisabled = DefaultHandleHKUDisabled;
180     else
181         DefDisabled = DefaultHandlesDisabled;
182 
183     if (!DefDisabled)
184     {
185         Handle = &DefaultHandleTable[Index];
186         DoOpen = (*Handle == NULL);
187     }
188     else
189     {
190         Handle = RealKey;
191         DoOpen = TRUE;
192     }
193 
194     if (DoOpen)
195     {
196         /* create/open the default handle */
197         Status = OpenPredefinedKey(Index,
198                                    Handle);
199     }
200 
201     if (NT_SUCCESS(Status))
202     {
203         if (!DefDisabled)
204             *RealKey = *Handle;
205         else
206             *(PULONG_PTR)Handle |= 0x1;
207     }
208 
209     RtlLeaveCriticalSection (&HandleTableCS);
210 
211     return Status;
212 }
213 
214 
215 static VOID
CloseDefaultKeys(VOID)216 CloseDefaultKeys(VOID)
217 {
218     ULONG i;
219     RegInitialize(); /* HACK until delay-loading is implemented */
220     RtlEnterCriticalSection(&HandleTableCS);
221 
222     for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
223     {
224         if (DefaultHandleTable[i] != NULL)
225         {
226             NtClose(DefaultHandleTable[i]);
227             DefaultHandleTable[i] = NULL;
228         }
229     }
230 
231     RtlLeaveCriticalSection(&HandleTableCS);
232 }
233 
234 
235 static NTSTATUS
OpenClassesRootKey(_Out_ PHANDLE KeyHandle)236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle)
237 {
238     OBJECT_ATTRIBUTES Attributes;
239     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
240     NTSTATUS Status;
241 
242     TRACE("OpenClassesRootKey()\n");
243 
244     InitializeObjectAttributes(&Attributes,
245                                &KeyName,
246                                OBJ_CASE_INSENSITIVE,
247                                NULL,
248                                NULL);
249     Status = NtOpenKey(KeyHandle,
250                        MAXIMUM_ALLOWED,
251                        &Attributes);
252 
253     if (!NT_SUCCESS(Status))
254         return Status;
255 
256     /* Mark it as HKCR */
257     MakeHKCRKey((HKEY*)KeyHandle);
258 
259     return Status;
260 }
261 
262 
263 static NTSTATUS
OpenLocalMachineKey(PHANDLE KeyHandle)264 OpenLocalMachineKey(PHANDLE KeyHandle)
265 {
266     OBJECT_ATTRIBUTES Attributes;
267     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
268     NTSTATUS Status;
269 
270     TRACE("OpenLocalMachineKey()\n");
271 
272     InitializeObjectAttributes(&Attributes,
273                                &KeyName,
274                                OBJ_CASE_INSENSITIVE,
275                                NULL,
276                                NULL);
277     Status = NtOpenKey(KeyHandle,
278                        MAXIMUM_ALLOWED,
279                        &Attributes);
280 
281     TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
282 
283     return Status;
284 }
285 
286 
287 static NTSTATUS
OpenUsersKey(PHANDLE KeyHandle)288 OpenUsersKey(PHANDLE KeyHandle)
289 {
290     OBJECT_ATTRIBUTES Attributes;
291     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
292 
293     TRACE("OpenUsersKey()\n");
294 
295     InitializeObjectAttributes(&Attributes,
296                                &KeyName,
297                                OBJ_CASE_INSENSITIVE,
298                                NULL,
299                                NULL);
300     return NtOpenKey(KeyHandle,
301                      MAXIMUM_ALLOWED,
302                      &Attributes);
303 }
304 
305 
306 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle)307 OpenCurrentConfigKey (PHANDLE KeyHandle)
308 {
309     OBJECT_ATTRIBUTES Attributes;
310     UNICODE_STRING KeyName =
311         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
312 
313     TRACE("OpenCurrentConfigKey()\n");
314 
315     InitializeObjectAttributes(&Attributes,
316                                &KeyName,
317                                OBJ_CASE_INSENSITIVE,
318                                NULL,
319                                NULL);
320     return NtOpenKey(KeyHandle,
321                      MAXIMUM_ALLOWED,
322                      &Attributes);
323 }
324 
325 #ifndef _ADVAPI32_VISTA_
326 
327 /************************************************************************
328  *  RegDisablePredefinedCache
329  *
330  * @implemented
331  */
332 LONG WINAPI
RegDisablePredefinedCache(VOID)333 RegDisablePredefinedCache(VOID)
334 {
335     RegInitialize(); /* HACK until delay-loading is implemented */
336     RtlEnterCriticalSection(&HandleTableCS);
337     DefaultHandleHKUDisabled = TRUE;
338     RtlLeaveCriticalSection(&HandleTableCS);
339     return ERROR_SUCCESS;
340 }
341 
342 
343 /************************************************************************
344  *  RegDisablePredefinedCacheEx
345  *
346  * @implemented
347  */
348 LONG WINAPI
RegDisablePredefinedCacheEx(VOID)349 RegDisablePredefinedCacheEx(VOID)
350 {
351     RegInitialize(); /* HACK until delay-loading is implemented */
352     RtlEnterCriticalSection(&HandleTableCS);
353     DefaultHandlesDisabled = TRUE;
354     DefaultHandleHKUDisabled = TRUE;
355     RtlLeaveCriticalSection(&HandleTableCS);
356     return ERROR_SUCCESS;
357 }
358 
359 
360 /************************************************************************
361  *  RegOverridePredefKey
362  *
363  * @implemented
364  */
365 LONG WINAPI
RegOverridePredefKey(IN HKEY hKey,IN HKEY hNewHKey OPTIONAL)366 RegOverridePredefKey(IN HKEY hKey,
367                      IN HKEY hNewHKey  OPTIONAL)
368 {
369     LONG ErrorCode = ERROR_SUCCESS;
370 
371     if ((hKey == HKEY_CLASSES_ROOT ||
372          hKey == HKEY_CURRENT_CONFIG ||
373          hKey == HKEY_CURRENT_USER ||
374          hKey == HKEY_LOCAL_MACHINE ||
375          hKey == HKEY_PERFORMANCE_DATA ||
376          hKey == HKEY_USERS) &&
377         !IsPredefKey(hNewHKey))
378     {
379         PHANDLE Handle;
380         ULONG Index;
381 
382         Index = GetPredefKeyIndex(hKey);
383         Handle = &DefaultHandleTable[Index];
384 
385         if (hNewHKey == NULL)
386         {
387             /* restore the default mapping */
388             NTSTATUS Status = OpenPredefinedKey(Index,
389                                                 &hNewHKey);
390             if (!NT_SUCCESS(Status))
391             {
392                 return RtlNtStatusToDosError(Status);
393             }
394 
395             ASSERT(hNewHKey != NULL);
396         }
397         RegInitialize(); /* HACK until delay-loading is implemented */
398         RtlEnterCriticalSection(&HandleTableCS);
399 
400         /* close the currently mapped handle if existing */
401         if (*Handle != NULL)
402         {
403             NtClose(*Handle);
404         }
405 
406         /* update the mapping */
407         *Handle = hNewHKey;
408 
409         RtlLeaveCriticalSection(&HandleTableCS);
410     }
411     else
412         ErrorCode = ERROR_INVALID_HANDLE;
413 
414     return ErrorCode;
415 }
416 
417 
418 /************************************************************************
419  *  RegCloseKey
420  *
421  * @implemented
422  */
423 LONG WINAPI
RegCloseKey(HKEY hKey)424 RegCloseKey(HKEY hKey)
425 {
426     NTSTATUS Status;
427 
428     /* don't close null handle or a pseudo handle */
429     if (!hKey)
430     {
431         return ERROR_INVALID_HANDLE;
432     }
433 
434     if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)
435     {
436         return ERROR_SUCCESS;
437     }
438 
439     Status = NtClose(hKey);
440     if (!NT_SUCCESS(Status))
441     {
442         return RtlNtStatusToDosError(Status);
443     }
444 
445   return ERROR_SUCCESS;
446 }
447 
448 #endif // _ADVAPI32_VISTA_
449 
450 static NTSTATUS
RegpCopyTree(IN HKEY hKeySrc,IN HKEY hKeyDest)451 RegpCopyTree(IN HKEY hKeySrc,
452              IN HKEY hKeyDest)
453 {
454     typedef struct
455     {
456         LIST_ENTRY ListEntry;
457         HANDLE hKeySrc;
458         HANDLE hKeyDest;
459     } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
460 
461     LIST_ENTRY copyQueueHead;
462     PREGP_COPY_KEYS copyKeys, newCopyKeys;
463     union
464     {
465         KEY_VALUE_FULL_INFORMATION *KeyValue;
466         KEY_NODE_INFORMATION *KeyNode;
467         PVOID Buffer;
468     } Info;
469     ULONG Index, BufferSizeRequired, BufferSize = 0x200;
470     NTSTATUS Status = STATUS_SUCCESS;
471     NTSTATUS Status2 = STATUS_SUCCESS;
472 
473     InitializeListHead(&copyQueueHead);
474 
475     Info.Buffer = RtlAllocateHeap(ProcessHeap,
476                                   0,
477                                   BufferSize);
478     if (Info.Buffer == NULL)
479     {
480         return STATUS_INSUFFICIENT_RESOURCES;
481     }
482 
483     copyKeys = RtlAllocateHeap(ProcessHeap,
484                                0,
485                                sizeof(REGP_COPY_KEYS));
486     if (copyKeys != NULL)
487     {
488         copyKeys->hKeySrc = hKeySrc;
489         copyKeys->hKeyDest = hKeyDest;
490         InsertHeadList(&copyQueueHead,
491                        &copyKeys->ListEntry);
492 
493         /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
494 
495         do
496         {
497             copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
498                                          REGP_COPY_KEYS,
499                                          ListEntry);
500 
501             /* enumerate all values and copy them */
502             Index = 0;
503             for (;;)
504             {
505                 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
506                                               Index,
507                                               KeyValueFullInformation,
508                                               Info.KeyValue,
509                                               BufferSize,
510                                               &BufferSizeRequired);
511                 if (NT_SUCCESS(Status2))
512                 {
513                     UNICODE_STRING ValueName;
514                     PVOID Data;
515 
516                     /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
517                     ValueName.Length = Info.KeyValue->NameLength;
518                     ValueName.MaximumLength = ValueName.Length;
519                     ValueName.Buffer = Info.KeyValue->Name;
520 
521                     Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
522 
523                     Status2 = NtSetValueKey(copyKeys->hKeyDest,
524                                             &ValueName,
525                                             Info.KeyValue->TitleIndex,
526                                             Info.KeyValue->Type,
527                                             Data,
528                                             Info.KeyValue->DataLength);
529 
530                     /* don't break, let's try to copy as many values as possible */
531                     if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
532                     {
533                         Status = Status2;
534                     }
535 
536                     Index++;
537                 }
538                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
539                 {
540                     PVOID Buffer;
541 
542                     ASSERT(BufferSize < BufferSizeRequired);
543 
544                     Buffer = RtlReAllocateHeap(ProcessHeap,
545                                                0,
546                                                Info.Buffer,
547                                                BufferSizeRequired);
548                     if (Buffer != NULL)
549                     {
550                         Info.Buffer = Buffer;
551                         BufferSize = BufferSizeRequired;
552                         /* try again */
553                     }
554                     else
555                     {
556                         /* don't break, let's try to copy as many values as possible */
557                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
558                         Index++;
559 
560                         if (NT_SUCCESS(Status))
561                         {
562                             Status = Status2;
563                         }
564                     }
565                 }
566                 else
567                 {
568                     /* break to avoid an infinite loop in case of denied access or
569                        other errors! */
570                     if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
571                     {
572                         Status = Status2;
573                     }
574 
575                     break;
576                 }
577             }
578 
579             /* enumerate all subkeys and open and enqueue them */
580             Index = 0;
581             for (;;)
582             {
583                 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
584                                          Index,
585                                          KeyNodeInformation,
586                                          Info.KeyNode,
587                                          BufferSize,
588                                          &BufferSizeRequired);
589                 if (NT_SUCCESS(Status2))
590                 {
591                     HANDLE KeyHandle, NewKeyHandle;
592                     OBJECT_ATTRIBUTES ObjectAttributes;
593                     UNICODE_STRING SubKeyName, ClassName;
594 
595                     /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
596                     SubKeyName.Length = Info.KeyNode->NameLength;
597                     SubKeyName.MaximumLength = SubKeyName.Length;
598                     SubKeyName.Buffer = Info.KeyNode->Name;
599                     ClassName.Length = Info.KeyNode->ClassLength;
600                     ClassName.MaximumLength = ClassName.Length;
601                     ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
602 
603                     /* open the subkey with sufficient rights */
604 
605                     InitializeObjectAttributes(&ObjectAttributes,
606                                                &SubKeyName,
607                                                OBJ_CASE_INSENSITIVE,
608                                                copyKeys->hKeySrc,
609                                                NULL);
610 
611                     Status2 = NtOpenKey(&KeyHandle,
612                                         KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
613                                         &ObjectAttributes);
614                     if (NT_SUCCESS(Status2))
615                     {
616                         /* FIXME - attempt to query the security information */
617 
618                         InitializeObjectAttributes(&ObjectAttributes,
619                                                &SubKeyName,
620                                                OBJ_CASE_INSENSITIVE,
621                                                copyKeys->hKeyDest,
622                                                NULL);
623 
624                         Status2 = NtCreateKey(&NewKeyHandle,
625                                               KEY_ALL_ACCESS,
626                                               &ObjectAttributes,
627                                               Info.KeyNode->TitleIndex,
628                                               &ClassName,
629                                               0,
630                                               NULL);
631                         if (NT_SUCCESS(Status2))
632                         {
633                             newCopyKeys = RtlAllocateHeap(ProcessHeap,
634                                                           0,
635                                                           sizeof(REGP_COPY_KEYS));
636                             if (newCopyKeys != NULL)
637                             {
638                                 /* save the handles and enqueue the subkey */
639                                 newCopyKeys->hKeySrc = KeyHandle;
640                                 newCopyKeys->hKeyDest = NewKeyHandle;
641                                 InsertTailList(&copyQueueHead,
642                                                &newCopyKeys->ListEntry);
643                             }
644                             else
645                             {
646                                 NtClose(KeyHandle);
647                                 NtClose(NewKeyHandle);
648 
649                                 Status2 = STATUS_INSUFFICIENT_RESOURCES;
650                             }
651                         }
652                         else
653                         {
654                             NtClose(KeyHandle);
655                         }
656                     }
657 
658                     if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
659                     {
660                         Status = Status2;
661                     }
662 
663                     Index++;
664                 }
665                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
666                 {
667                     PVOID Buffer;
668 
669                     ASSERT(BufferSize < BufferSizeRequired);
670 
671                     Buffer = RtlReAllocateHeap(ProcessHeap,
672                                                0,
673                                                Info.Buffer,
674                                                BufferSizeRequired);
675                     if (Buffer != NULL)
676                     {
677                         Info.Buffer = Buffer;
678                         BufferSize = BufferSizeRequired;
679                         /* try again */
680                     }
681                     else
682                     {
683                         /* don't break, let's try to copy as many keys as possible */
684                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
685                         Index++;
686 
687                         if (NT_SUCCESS(Status))
688                         {
689                             Status = Status2;
690                         }
691                     }
692                 }
693                 else
694                 {
695                     /* break to avoid an infinite loop in case of denied access or
696                        other errors! */
697                     if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
698                     {
699                         Status = Status2;
700                     }
701 
702                     break;
703                 }
704             }
705 
706             /* close the handles and remove the entry from the list */
707             if (copyKeys->hKeySrc != hKeySrc)
708             {
709                 NtClose(copyKeys->hKeySrc);
710             }
711             if (copyKeys->hKeyDest != hKeyDest)
712             {
713                 NtClose(copyKeys->hKeyDest);
714             }
715 
716             RemoveEntryList(&copyKeys->ListEntry);
717 
718             RtlFreeHeap(ProcessHeap,
719                         0,
720                         copyKeys);
721         } while (!IsListEmpty(&copyQueueHead));
722     }
723     else
724         Status = STATUS_INSUFFICIENT_RESOURCES;
725 
726     RtlFreeHeap(ProcessHeap,
727                 0,
728                 Info.Buffer);
729 
730     return Status;
731 }
732 
733 
734 /************************************************************************
735  *  RegCopyTreeW
736  *
737  * @implemented
738  */
739 LONG WINAPI
RegCopyTreeW(IN HKEY hKeySrc,IN LPCWSTR lpSubKey OPTIONAL,IN HKEY hKeyDest)740 RegCopyTreeW(IN HKEY hKeySrc,
741              IN LPCWSTR lpSubKey  OPTIONAL,
742              IN HKEY hKeyDest)
743 {
744     HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
745     NTSTATUS Status;
746 
747     Status = MapDefaultKey(&KeyHandle,
748                            hKeySrc);
749     if (!NT_SUCCESS(Status))
750     {
751         return RtlNtStatusToDosError(Status);
752     }
753 
754     Status = MapDefaultKey(&DestKeyHandle,
755                            hKeyDest);
756     if (!NT_SUCCESS(Status))
757     {
758         goto Cleanup2;
759     }
760 
761     if (lpSubKey != NULL)
762     {
763         OBJECT_ATTRIBUTES ObjectAttributes;
764         UNICODE_STRING SubKeyName;
765 
766         RtlInitUnicodeString(&SubKeyName, lpSubKey);
767 
768         InitializeObjectAttributes(&ObjectAttributes,
769                                    &SubKeyName,
770                                    OBJ_CASE_INSENSITIVE,
771                                    KeyHandle,
772                                    NULL);
773 
774         Status = NtOpenKey(&SubKeyHandle,
775                            KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
776                            &ObjectAttributes);
777         if (!NT_SUCCESS(Status))
778         {
779             goto Cleanup;
780         }
781 
782         CurKey = SubKeyHandle;
783     }
784     else
785         CurKey = KeyHandle;
786 
787     Status = RegpCopyTree(CurKey,
788                           hKeyDest);
789 
790     if (SubKeyHandle != NULL)
791     {
792         NtClose(SubKeyHandle);
793     }
794 
795 Cleanup:
796     ClosePredefKey(DestKeyHandle);
797 Cleanup2:
798     ClosePredefKey(KeyHandle);
799 
800     if (!NT_SUCCESS(Status))
801     {
802         return RtlNtStatusToDosError(Status);
803     }
804 
805     return ERROR_SUCCESS;
806 }
807 
808 #ifndef _ADVAPI32_VISTA_
809 
810 /************************************************************************
811  *  RegCopyTreeA
812  *
813  * @implemented
814  */
815 LONG WINAPI
RegCopyTreeA(IN HKEY hKeySrc,IN LPCSTR lpSubKey OPTIONAL,IN HKEY hKeyDest)816 RegCopyTreeA(IN HKEY hKeySrc,
817              IN LPCSTR lpSubKey  OPTIONAL,
818              IN HKEY hKeyDest)
819 {
820     UNICODE_STRING SubKeyName = { 0, 0, NULL };
821     LONG Ret;
822 
823     if (lpSubKey != NULL &&
824         !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
825     {
826         return ERROR_NOT_ENOUGH_MEMORY;
827     }
828 
829     Ret = RegCopyTreeW(hKeySrc,
830                        SubKeyName.Buffer,
831                        hKeyDest);
832 
833     RtlFreeUnicodeString(&SubKeyName);
834 
835     return Ret;
836 }
837 
838 
839 /************************************************************************
840  *  RegConnectRegistryA
841  *
842  * @implemented
843  */
844 LONG WINAPI
RegConnectRegistryA(IN LPCSTR lpMachineName,IN HKEY hKey,OUT PHKEY phkResult)845 RegConnectRegistryA(IN LPCSTR lpMachineName,
846                     IN HKEY hKey,
847                     OUT PHKEY phkResult)
848 {
849     UNICODE_STRING MachineName = { 0, 0, NULL };
850     LONG Ret;
851 
852     if (lpMachineName != NULL &&
853         !RtlCreateUnicodeStringFromAsciiz(&MachineName, lpMachineName))
854     {
855         return ERROR_NOT_ENOUGH_MEMORY;
856     }
857 
858     Ret = RegConnectRegistryW(MachineName.Buffer,
859                               hKey,
860                               phkResult);
861 
862     RtlFreeUnicodeString(&MachineName);
863 
864     return Ret;
865 }
866 
867 
868 /************************************************************************
869  *  RegConnectRegistryW
870  *
871  * @unimplemented
872  */
873 LONG WINAPI
RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult)874 RegConnectRegistryW(LPCWSTR lpMachineName,
875                     HKEY hKey,
876                     PHKEY phkResult)
877 {
878     LONG ret;
879 
880     TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
881 
882     if (!lpMachineName || !*lpMachineName)
883     {
884         /* Use the local machine name */
885         ret = RegOpenKeyW( hKey, NULL, phkResult );
886     }
887     else
888     {
889         WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
890         DWORD len = sizeof(compName) / sizeof(WCHAR);
891 
892         /* MSDN says lpMachineName must start with \\ : not so */
893         if( lpMachineName[0] == '\\' &&  lpMachineName[1] == '\\')
894             lpMachineName += 2;
895 
896         if (GetComputerNameW(compName, &len))
897         {
898             if (!_wcsicmp(lpMachineName, compName))
899                 ret = RegOpenKeyW(hKey, NULL, phkResult);
900             else
901             {
902                 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
903                 ret = ERROR_BAD_NETPATH;
904             }
905         }
906         else
907             ret = GetLastError();
908     }
909 
910     return ret;
911 }
912 
913 
914 /************************************************************************
915  *  CreateNestedKey
916  *
917  *  Create key and all necessary intermediate keys
918  */
919 static NTSTATUS
CreateNestedKey(PHKEY KeyHandle,POBJECT_ATTRIBUTES ObjectAttributes,PUNICODE_STRING ClassString,DWORD dwOptions,REGSAM samDesired,DWORD * lpdwDisposition)920 CreateNestedKey(PHKEY KeyHandle,
921                 POBJECT_ATTRIBUTES ObjectAttributes,
922                 PUNICODE_STRING ClassString,
923                 DWORD dwOptions,
924                 REGSAM samDesired,
925                 DWORD *lpdwDisposition)
926 {
927     OBJECT_ATTRIBUTES LocalObjectAttributes;
928     UNICODE_STRING LocalKeyName;
929     ULONG Disposition;
930     NTSTATUS Status;
931     ULONG FullNameLength;
932     ULONG Length;
933     PWCHAR Ptr;
934     HANDLE LocalKeyHandle;
935 
936     Status = NtCreateKey((PHANDLE) KeyHandle,
937                          samDesired,
938                          ObjectAttributes,
939                          0,
940                          ClassString,
941                          dwOptions,
942                          (PULONG)lpdwDisposition);
943     TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
944     if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
945         return Status;
946 
947     /* Copy object attributes */
948     RtlCopyMemory(&LocalObjectAttributes,
949                   ObjectAttributes,
950                   sizeof(OBJECT_ATTRIBUTES));
951     RtlCreateUnicodeString(&LocalKeyName,
952                            ObjectAttributes->ObjectName->Buffer);
953     LocalObjectAttributes.ObjectName = &LocalKeyName;
954     FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
955 
956     LocalKeyHandle = NULL;
957 
958     /* Remove the last part of the key name and try to create the key again. */
959     while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
960     {
961         Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
962         if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
963         {
964             Status = STATUS_UNSUCCESSFUL;
965             break;
966         }
967 
968         *Ptr = (WCHAR)0;
969         LocalKeyName.Length = (USHORT)wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
970 
971         Status = NtCreateKey(&LocalKeyHandle,
972                              KEY_CREATE_SUB_KEY,
973                              &LocalObjectAttributes,
974                              0,
975                              NULL,
976                              0,
977                              &Disposition);
978         TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
979     }
980 
981     if (!NT_SUCCESS(Status))
982     {
983         RtlFreeUnicodeString(&LocalKeyName);
984         return Status;
985     }
986 
987     /* Add removed parts of the key name and create them too. */
988     Length = wcslen(LocalKeyName.Buffer);
989     while (TRUE)
990     {
991         if (LocalKeyHandle)
992             NtClose (LocalKeyHandle);
993 
994         LocalKeyName.Buffer[Length] = L'\\';
995         Length = wcslen (LocalKeyName.Buffer);
996         LocalKeyName.Length = Length * sizeof(WCHAR);
997 
998         if (Length == FullNameLength)
999         {
1000             Status = NtCreateKey((PHANDLE) KeyHandle,
1001                                  samDesired,
1002                                  ObjectAttributes,
1003                                  0,
1004                                  ClassString,
1005                                  dwOptions,
1006                                  (PULONG)lpdwDisposition);
1007             break;
1008         }
1009 
1010         Status = NtCreateKey(&LocalKeyHandle,
1011                              KEY_CREATE_SUB_KEY,
1012                              &LocalObjectAttributes,
1013                              0,
1014                              NULL,
1015                              0,
1016                              &Disposition);
1017         TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
1018         if (!NT_SUCCESS(Status))
1019             break;
1020     }
1021 
1022     RtlFreeUnicodeString(&LocalKeyName);
1023 
1024     return Status;
1025 }
1026 
1027 
1028 /************************************************************************
1029  *  RegCreateKeyExA
1030  *
1031  * @implemented
1032  */
1033 LONG WINAPI
RegCreateKeyExA(_In_ HKEY hKey,_In_ LPCSTR lpSubKey,_In_ DWORD Reserved,_In_ LPSTR lpClass,_In_ DWORD dwOptions,_In_ REGSAM samDesired,_In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,_Out_ PHKEY phkResult,_Out_ LPDWORD lpdwDisposition)1034 RegCreateKeyExA(
1035     _In_ HKEY hKey,
1036     _In_ LPCSTR lpSubKey,
1037     _In_ DWORD Reserved,
1038     _In_ LPSTR lpClass,
1039     _In_ DWORD dwOptions,
1040     _In_ REGSAM samDesired,
1041     _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1042     _Out_ PHKEY phkResult,
1043     _Out_ LPDWORD lpdwDisposition)
1044 {
1045     UNICODE_STRING SubKeyString;
1046     UNICODE_STRING ClassString;
1047     DWORD ErrorCode;
1048 
1049     RtlInitEmptyUnicodeString(&ClassString, NULL, 0);
1050     RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
1051 
1052     if (lpClass)
1053     {
1054         if (!RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass))
1055         {
1056             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1057             goto Exit;
1058         }
1059     }
1060 
1061     if (lpSubKey)
1062     {
1063         if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
1064         {
1065             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1066             goto Exit;
1067         }
1068     }
1069 
1070     ErrorCode = RegCreateKeyExW(
1071         hKey,
1072         SubKeyString.Buffer,
1073         Reserved,
1074         ClassString.Buffer,
1075         dwOptions,
1076         samDesired,
1077         lpSecurityAttributes,
1078         phkResult,
1079         lpdwDisposition);
1080 
1081 Exit:
1082     RtlFreeUnicodeString(&SubKeyString);
1083     RtlFreeUnicodeString(&ClassString);
1084 
1085     return ErrorCode;
1086 }
1087 
1088 
1089 /************************************************************************
1090  *  RegCreateKeyExW
1091  *
1092  * @implemented
1093  */
1094 LONG
1095 WINAPI
RegCreateKeyExW(_In_ HKEY hKey,_In_ LPCWSTR lpSubKey,_In_ DWORD Reserved,_In_opt_ LPWSTR lpClass,_In_ DWORD dwOptions,_In_ REGSAM samDesired,_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,_Out_ PHKEY phkResult,_Out_opt_ LPDWORD lpdwDisposition)1096 RegCreateKeyExW(
1097     _In_ HKEY hKey,
1098     _In_ LPCWSTR lpSubKey,
1099     _In_ DWORD Reserved,
1100     _In_opt_ LPWSTR lpClass,
1101     _In_ DWORD dwOptions,
1102     _In_ REGSAM samDesired,
1103     _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1104     _Out_ PHKEY phkResult,
1105     _Out_opt_ LPDWORD lpdwDisposition)
1106 {
1107     UNICODE_STRING SubKeyString;
1108     UNICODE_STRING ClassString;
1109     OBJECT_ATTRIBUTES ObjectAttributes;
1110     HANDLE ParentKey;
1111     ULONG Attributes = OBJ_CASE_INSENSITIVE;
1112     NTSTATUS Status;
1113 
1114     TRACE("RegCreateKeyExW() called\n");
1115 
1116     /* get the real parent key */
1117     Status = MapDefaultKey(&ParentKey,
1118                            hKey);
1119     if (!NT_SUCCESS(Status))
1120     {
1121         return RtlNtStatusToDosError(Status);
1122     }
1123 
1124     TRACE("ParentKey %p\n", ParentKey);
1125 
1126     if (IsHKCRKey(ParentKey))
1127     {
1128         LONG ErrorCode = CreateHKCRKey(
1129             ParentKey,
1130             lpSubKey,
1131             Reserved,
1132             lpClass,
1133             dwOptions,
1134             samDesired,
1135             lpSecurityAttributes,
1136             phkResult,
1137             lpdwDisposition);
1138         ClosePredefKey(ParentKey);
1139         return ErrorCode;
1140     }
1141 
1142     if (dwOptions & REG_OPTION_OPEN_LINK)
1143         Attributes |= OBJ_OPENLINK;
1144 
1145     RtlInitUnicodeString(&ClassString,
1146                          lpClass);
1147     RtlInitUnicodeString(&SubKeyString,
1148                          lpSubKey);
1149     InitializeObjectAttributes(&ObjectAttributes,
1150                                &SubKeyString,
1151                                Attributes,
1152                                (HANDLE)ParentKey,
1153                                lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1154     Status = CreateNestedKey(phkResult,
1155                              &ObjectAttributes,
1156                              (lpClass == NULL)? NULL : &ClassString,
1157                              dwOptions,
1158                              samDesired,
1159                              lpdwDisposition);
1160 
1161     ClosePredefKey(ParentKey);
1162 
1163     TRACE("Status %x\n", Status);
1164     if (!NT_SUCCESS(Status))
1165     {
1166         return RtlNtStatusToDosError(Status);
1167     }
1168 
1169     return ERROR_SUCCESS;
1170 }
1171 
1172 
1173 /************************************************************************
1174  *  RegCreateKeyA
1175  *
1176  * @implemented
1177  */
1178 LONG WINAPI
RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult)1179 RegCreateKeyA(HKEY hKey,
1180               LPCSTR lpSubKey,
1181               PHKEY phkResult)
1182 {
1183     return RegCreateKeyExA(hKey,
1184                            lpSubKey,
1185                            0,
1186                            NULL,
1187                            0,
1188                            MAXIMUM_ALLOWED,
1189                            NULL,
1190                            phkResult,
1191                            NULL);
1192 }
1193 
1194 
1195 /************************************************************************
1196  *  RegCreateKeyW
1197  *
1198  * @implemented
1199  */
1200 LONG WINAPI
RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult)1201 RegCreateKeyW(HKEY hKey,
1202               LPCWSTR lpSubKey,
1203               PHKEY phkResult)
1204 {
1205     return RegCreateKeyExW(hKey,
1206                            lpSubKey,
1207                            0,
1208                            NULL,
1209                            0,
1210                            MAXIMUM_ALLOWED,
1211                            NULL,
1212                            phkResult,
1213                            NULL);
1214 }
1215 
1216 
1217 /************************************************************************
1218  *  RegDeleteKeyA
1219  *
1220  * @implemented
1221  */
1222 LONG
1223 WINAPI
RegDeleteKeyA(_In_ HKEY hKey,_In_ LPCSTR lpSubKey)1224 RegDeleteKeyA(
1225     _In_ HKEY hKey,
1226     _In_ LPCSTR lpSubKey)
1227 {
1228     return RegDeleteKeyExA(hKey, lpSubKey, 0, 0);
1229 }
1230 
1231 
1232 /************************************************************************
1233  *  RegDeleteKeyW
1234  *
1235  * @implemented
1236  */
1237 LONG
1238 WINAPI
RegDeleteKeyW(_In_ HKEY hKey,_In_ LPCWSTR lpSubKey)1239 RegDeleteKeyW(
1240     _In_ HKEY hKey,
1241     _In_ LPCWSTR lpSubKey)
1242 {
1243     return RegDeleteKeyExW(hKey, lpSubKey, 0, 0);
1244 }
1245 
1246 
1247 /************************************************************************
1248  *  RegDeleteKeyExA
1249  *
1250  * @implemented
1251  */
1252 LONG
1253 WINAPI
RegDeleteKeyExA(_In_ HKEY hKey,_In_ LPCSTR lpSubKey,_In_ REGSAM samDesired,_In_ DWORD Reserved)1254 RegDeleteKeyExA(
1255     _In_ HKEY hKey,
1256     _In_ LPCSTR lpSubKey,
1257     _In_ REGSAM samDesired,
1258     _In_ DWORD Reserved)
1259 {
1260     LONG ErrorCode;
1261     UNICODE_STRING SubKeyName;
1262 
1263     if (lpSubKey)
1264     {
1265         if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
1266             return ERROR_NOT_ENOUGH_MEMORY;
1267     }
1268     else
1269         RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0);
1270 
1271     ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved);
1272 
1273     RtlFreeUnicodeString(&SubKeyName);
1274 
1275     return ErrorCode;
1276 }
1277 
1278 
1279 /************************************************************************
1280  *  RegDeleteKeyExW
1281  *
1282  * @implemented
1283  */
1284 LONG
1285 WINAPI
RegDeleteKeyExW(_In_ HKEY hKey,_In_ LPCWSTR lpSubKey,_In_ REGSAM samDesired,_In_ DWORD Reserved)1286 RegDeleteKeyExW(
1287     _In_ HKEY hKey,
1288     _In_ LPCWSTR lpSubKey,
1289     _In_ REGSAM samDesired,
1290     _In_ DWORD Reserved)
1291 {
1292     OBJECT_ATTRIBUTES ObjectAttributes;
1293     UNICODE_STRING SubKeyName;
1294     HANDLE ParentKey;
1295     HANDLE TargetKey;
1296     NTSTATUS Status;
1297 
1298     /* Make sure we got a subkey */
1299     if (!lpSubKey)
1300     {
1301         /* Fail */
1302         return ERROR_INVALID_PARAMETER;
1303     }
1304 
1305     Status = MapDefaultKey(&ParentKey,
1306                            hKey);
1307     if (!NT_SUCCESS(Status))
1308     {
1309         return RtlNtStatusToDosError(Status);
1310     }
1311 
1312     if (IsHKCRKey(ParentKey))
1313     {
1314         LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
1315         ClosePredefKey(ParentKey);
1316         return ErrorCode;
1317     }
1318 
1319     if (samDesired & KEY_WOW64_32KEY)
1320         ERR("Wow64 not yet supported!\n");
1321 
1322     if (samDesired & KEY_WOW64_64KEY)
1323         ERR("Wow64 not yet supported!\n");
1324 
1325 
1326     RtlInitUnicodeString(&SubKeyName, lpSubKey);
1327     InitializeObjectAttributes(&ObjectAttributes,
1328                                &SubKeyName,
1329                                OBJ_CASE_INSENSITIVE,
1330                                ParentKey,
1331                                NULL);
1332     Status = NtOpenKey(&TargetKey,
1333                        DELETE,
1334                        &ObjectAttributes);
1335     if (!NT_SUCCESS(Status))
1336     {
1337         goto Cleanup;
1338     }
1339 
1340     Status = NtDeleteKey(TargetKey);
1341     NtClose(TargetKey);
1342 
1343 Cleanup:
1344     ClosePredefKey(ParentKey);
1345 
1346     if (!NT_SUCCESS(Status))
1347     {
1348         return RtlNtStatusToDosError(Status);
1349     }
1350 
1351     return ERROR_SUCCESS;
1352 }
1353 
1354 
1355 /************************************************************************
1356  *  RegDeleteKeyValueW
1357  *
1358  * @implemented
1359  */
1360 LONG WINAPI
RegDeleteKeyValueW(IN HKEY hKey,IN LPCWSTR lpSubKey OPTIONAL,IN LPCWSTR lpValueName OPTIONAL)1361 RegDeleteKeyValueW(IN HKEY hKey,
1362                    IN LPCWSTR lpSubKey  OPTIONAL,
1363                    IN LPCWSTR lpValueName  OPTIONAL)
1364 {
1365     HKEY hSubKey = hKey;
1366     LONG ErrorCode;
1367 
1368     if (lpSubKey)
1369     {
1370         ErrorCode = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey);
1371         if (ErrorCode)
1372         {
1373             return ErrorCode;
1374         }
1375     }
1376     ErrorCode = RegDeleteValueW(hSubKey, lpValueName);
1377 
1378     if (hSubKey != hKey)
1379     {
1380         RegCloseKey(hSubKey);
1381     }
1382     return ErrorCode;
1383 }
1384 
1385 
1386 /************************************************************************
1387  *  RegDeleteKeyValueA
1388  *
1389  * @implemented
1390  */
1391 LONG WINAPI
RegDeleteKeyValueA(IN HKEY hKey,IN LPCSTR lpSubKey OPTIONAL,IN LPCSTR lpValueName OPTIONAL)1392 RegDeleteKeyValueA(IN HKEY hKey,
1393                    IN LPCSTR lpSubKey  OPTIONAL,
1394                    IN LPCSTR lpValueName  OPTIONAL)
1395 {
1396     UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
1397     LONG Ret;
1398 
1399     if (lpSubKey != NULL &&
1400         !RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
1401     {
1402         return ERROR_NOT_ENOUGH_MEMORY;
1403     }
1404 
1405     if (lpValueName != NULL &&
1406         !RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
1407     {
1408         RtlFreeUnicodeString(&SubKey);
1409         return ERROR_NOT_ENOUGH_MEMORY;
1410     }
1411 
1412     Ret = RegDeleteKeyValueW(hKey,
1413                              SubKey.Buffer,
1414                              ValueName.Buffer);
1415 
1416     RtlFreeUnicodeString(&SubKey);
1417     RtlFreeUnicodeString(&ValueName);
1418 
1419     return Ret;
1420 }
1421 
1422 #if 0
1423 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1424 static NTSTATUS
1425 RegpDeleteTree(IN HKEY hKey)
1426 {
1427     typedef struct
1428     {
1429         LIST_ENTRY ListEntry;
1430         HANDLE KeyHandle;
1431     } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1432 
1433     LIST_ENTRY delQueueHead;
1434     PREG_DEL_KEYS delKeys, newDelKeys;
1435     HANDLE ProcessHeap;
1436     ULONG BufferSize;
1437     PKEY_BASIC_INFORMATION BasicInfo;
1438     PREG_DEL_KEYS KeyDelRoot;
1439     NTSTATUS Status = STATUS_SUCCESS;
1440     NTSTATUS Status2 = STATUS_SUCCESS;
1441 
1442     InitializeListHead(&delQueueHead);
1443 
1444     ProcessHeap = RtlGetProcessHeap();
1445 
1446     /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1447              structure for the root key, we only do that for subkeys as we need to
1448              allocate REGP_DEL_KEYS structures anyway! */
1449     KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1450                                  0,
1451                                  sizeof(REGP_DEL_KEYS));
1452     if (KeyDelRoot != NULL)
1453     {
1454         KeyDelRoot->KeyHandle = hKey;
1455         InsertTailList(&delQueueHead,
1456                        &KeyDelRoot->ListEntry);
1457 
1458         do
1459         {
1460             delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1461                                         REGP_DEL_KEYS,
1462                                         ListEntry);
1463 
1464             BufferSize = 0;
1465             BasicInfo = NULL;
1466             newDelKeys = NULL;
1467 
1468 ReadFirstSubKey:
1469             /* check if this key contains subkeys and delete them first by queuing
1470                them at the head of the list */
1471             Status2 = NtEnumerateKey(delKeys->KeyHandle,
1472                                      0,
1473                                      KeyBasicInformation,
1474                                      BasicInfo,
1475                                      BufferSize,
1476                                      &BufferSize);
1477 
1478             if (NT_SUCCESS(Status2))
1479             {
1480                 OBJECT_ATTRIBUTES ObjectAttributes;
1481                 UNICODE_STRING SubKeyName;
1482 
1483                 ASSERT(newDelKeys != NULL);
1484                 ASSERT(BasicInfo != NULL);
1485 
1486                 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1487                 SubKeyName.Length = BasicInfo->NameLength;
1488                 SubKeyName.MaximumLength = BasicInfo->NameLength;
1489                 SubKeyName.Buffer = BasicInfo->Name;
1490 
1491                 InitializeObjectAttributes(&ObjectAttributes,
1492                                            &SubKeyName,
1493                                            OBJ_CASE_INSENSITIVE,
1494                                            delKeys->KeyHandle,
1495                                            NULL);
1496 
1497                 /* open the subkey */
1498                 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1499                                     DELETE | KEY_ENUMERATE_SUB_KEYS,
1500                                     &ObjectAttributes);
1501                 if (!NT_SUCCESS(Status2))
1502                 {
1503                     goto SubKeyFailure;
1504                 }
1505 
1506                 /* enqueue this key to the head of the deletion queue */
1507                 InsertHeadList(&delQueueHead,
1508                                &newDelKeys->ListEntry);
1509 
1510                 /* try again from the head of the list */
1511                 continue;
1512             }
1513             else
1514             {
1515                 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1516                 {
1517                     newDelKeys = RtlAllocateHeap(ProcessHeap,
1518                                                  0,
1519                                                  BufferSize + sizeof(REGP_DEL_KEYS));
1520                     if (newDelKeys != NULL)
1521                     {
1522                         BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1523 
1524                         /* try again */
1525                         goto ReadFirstSubKey;
1526                     }
1527                     else
1528                     {
1529                         /* don't break, let's try to delete as many keys as possible */
1530                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
1531                         goto SubKeyFailureNoFree;
1532                     }
1533                 }
1534                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1535                 {
1536                     PREG_DEL_KEYS newDelKeys2;
1537 
1538                     ASSERT(newDelKeys != NULL);
1539 
1540                     /* we need more memory to query the key name */
1541                     newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1542                                                     0,
1543                                                     newDelKeys,
1544                                                     BufferSize + sizeof(REGP_DEL_KEYS));
1545                     if (newDelKeys2 != NULL)
1546                     {
1547                         newDelKeys = newDelKeys2;
1548                         BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1549 
1550                         /* try again */
1551                         goto ReadFirstSubKey;
1552                     }
1553                     else
1554                     {
1555                         /* don't break, let's try to delete as many keys as possible */
1556                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
1557                     }
1558                 }
1559                 else if (Status2 == STATUS_NO_MORE_ENTRIES)
1560                 {
1561                     /* in some race conditions where another thread would delete
1562                        the same tree at the same time, newDelKeys could actually
1563                        be != NULL! */
1564                     if (newDelKeys != NULL)
1565                     {
1566                         RtlFreeHeap(ProcessHeap,
1567                                     0,
1568                                     newDelKeys);
1569                     }
1570                     break;
1571                 }
1572 
1573 SubKeyFailure:
1574                 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1575                    error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1576                 if (newDelKeys != NULL)
1577                 {
1578                     RtlFreeHeap(ProcessHeap,
1579                                 0,
1580                                 newDelKeys);
1581                 }
1582 
1583 SubKeyFailureNoFree:
1584                 /* don't break, let's try to delete as many keys as possible */
1585                 if (NT_SUCCESS(Status))
1586                 {
1587                     Status = Status2;
1588                 }
1589             }
1590 
1591             Status2 = NtDeleteKey(delKeys->KeyHandle);
1592 
1593             /* NOTE: do NOT close the handle anymore, it's invalid already! */
1594 
1595             if (!NT_SUCCESS(Status2))
1596             {
1597                 /* close the key handle so we don't leak handles for keys we were
1598                    unable to delete. But only do this for handles not supplied
1599                    by the caller! */
1600 
1601                 if (delKeys->KeyHandle != hKey)
1602                 {
1603                     NtClose(delKeys->KeyHandle);
1604                 }
1605 
1606                 if (NT_SUCCESS(Status))
1607                 {
1608                     /* don't break, let's try to delete as many keys as possible */
1609                     Status = Status2;
1610                 }
1611             }
1612 
1613             /* remove the entry from the list */
1614             RemoveEntryList(&delKeys->ListEntry);
1615 
1616             RtlFreeHeap(ProcessHeap,
1617                         0,
1618                         delKeys);
1619         } while (!IsListEmpty(&delQueueHead));
1620     }
1621     else
1622         Status = STATUS_INSUFFICIENT_RESOURCES;
1623 
1624     return Status;
1625 }
1626 
1627 
1628 /************************************************************************
1629  *  RegDeleteTreeW
1630  *
1631  * @implemented
1632  */
1633 LONG WINAPI
1634 RegDeleteTreeW(IN HKEY hKey,
1635                IN LPCWSTR lpSubKey  OPTIONAL)
1636 {
1637     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1638     NTSTATUS Status;
1639 
1640     Status = MapDefaultKey(&KeyHandle,
1641                            hKey);
1642     if (!NT_SUCCESS(Status))
1643     {
1644         return RtlNtStatusToDosError(Status);
1645     }
1646 
1647     if (lpSubKey != NULL)
1648     {
1649         OBJECT_ATTRIBUTES ObjectAttributes;
1650         UNICODE_STRING SubKeyName;
1651 
1652         RtlInitUnicodeString(&SubKeyName, lpSubKey);
1653 
1654         InitializeObjectAttributes(&ObjectAttributes,
1655                                    &SubKeyName,
1656                                    OBJ_CASE_INSENSITIVE,
1657                                    KeyHandle,
1658                                    NULL);
1659 
1660         Status = NtOpenKey(&SubKeyHandle,
1661                            DELETE | KEY_ENUMERATE_SUB_KEYS,
1662                            &ObjectAttributes);
1663         if (!NT_SUCCESS(Status))
1664         {
1665             goto Cleanup;
1666         }
1667 
1668         CurKey = SubKeyHandle;
1669     }
1670     else
1671         CurKey = KeyHandle;
1672 
1673     Status = RegpDeleteTree(CurKey);
1674 
1675     if (NT_SUCCESS(Status))
1676     {
1677         /* make sure we only close hKey (KeyHandle) when the caller specified a
1678            subkey, because the handle would be invalid already! */
1679         if (CurKey != KeyHandle)
1680         {
1681             ClosePredefKey(KeyHandle);
1682         }
1683 
1684         return ERROR_SUCCESS;
1685     }
1686     else
1687     {
1688         /* make sure we close all handles we created! */
1689         if (SubKeyHandle != NULL)
1690         {
1691             NtClose(SubKeyHandle);
1692         }
1693 
1694 Cleanup:
1695         ClosePredefKey(KeyHandle);
1696 
1697         return RtlNtStatusToDosError(Status);
1698     }
1699 }
1700 #endif
1701 
1702 #endif // _ADVAPI32_VISTA_
1703 
1704 /************************************************************************
1705  *  RegDeleteTreeW
1706  *
1707  * @implemented
1708  */
1709 LSTATUS
1710 WINAPI
RegDeleteTreeW(HKEY hKey,LPCWSTR lpszSubKey)1711 RegDeleteTreeW(HKEY hKey,
1712                LPCWSTR lpszSubKey)
1713 {
1714     LONG ret;
1715     DWORD dwMaxSubkeyLen, dwMaxValueLen;
1716     DWORD dwMaxLen, dwSize;
1717     NTSTATUS Status;
1718     HANDLE KeyHandle;
1719     HKEY hSubKey;
1720     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1721 
1722     TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
1723 
1724     Status = MapDefaultKey(&KeyHandle,
1725                            hKey);
1726     if (!NT_SUCCESS(Status))
1727     {
1728         return RtlNtStatusToDosError(Status);
1729     }
1730 
1731     hSubKey = KeyHandle;
1732 
1733     if(lpszSubKey)
1734     {
1735         ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
1736         if (ret)
1737         {
1738             ClosePredefKey(KeyHandle);
1739             return ret;
1740         }
1741     }
1742 
1743     /* Get highest length for keys, values */
1744     ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1745             &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
1746     if (ret) goto cleanup;
1747 
1748     dwMaxSubkeyLen++;
1749     dwMaxValueLen++;
1750     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
1751     if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
1752     {
1753         /* Name too big: alloc a buffer for it */
1754         if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
1755         {
1756             ret = ERROR_NOT_ENOUGH_MEMORY;
1757             goto cleanup;
1758         }
1759     }
1760 
1761 
1762     /* Recursively delete all the subkeys */
1763     while (TRUE)
1764     {
1765         dwSize = dwMaxLen;
1766         if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
1767                           NULL, NULL, NULL)) break;
1768 
1769         ret = RegDeleteTreeW(hSubKey, lpszName);
1770         if (ret) goto cleanup;
1771     }
1772 
1773     if (lpszSubKey)
1774         ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
1775     else
1776         while (TRUE)
1777         {
1778             dwSize = dwMaxLen;
1779             if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
1780                   NULL, NULL, NULL, NULL)) break;
1781 
1782             ret = RegDeleteValueW(KeyHandle, lpszName);
1783             if (ret) goto cleanup;
1784         }
1785 
1786 cleanup:
1787     /* Free buffer if allocated */
1788     if (lpszName != szNameBuf)
1789         RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
1790     if(lpszSubKey)
1791         RegCloseKey(hSubKey);
1792 
1793     ClosePredefKey(KeyHandle);
1794 
1795     return ret;
1796 }
1797 
1798 
1799 /************************************************************************
1800  *  RegDeleteTreeA
1801  *
1802  * @implemented
1803  */
1804 LONG WINAPI
RegDeleteTreeA(IN HKEY hKey,IN LPCSTR lpSubKey OPTIONAL)1805 RegDeleteTreeA(IN HKEY hKey,
1806                IN LPCSTR lpSubKey  OPTIONAL)
1807 {
1808     UNICODE_STRING SubKeyName = { 0, 0, NULL };
1809     LONG Ret;
1810 
1811     if (lpSubKey != NULL &&
1812         !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
1813     {
1814         return ERROR_NOT_ENOUGH_MEMORY;
1815     }
1816 
1817     Ret = RegDeleteTreeW(hKey,
1818                          SubKeyName.Buffer);
1819 
1820     RtlFreeUnicodeString(&SubKeyName);
1821 
1822     return Ret;
1823 }
1824 
1825 #ifndef _ADVAPI32_VISTA_
1826 
1827 /************************************************************************
1828  *  RegDisableReflectionKey
1829  *
1830  * @unimplemented
1831  */
1832 LONG WINAPI
RegDisableReflectionKey(IN HKEY hBase)1833 RegDisableReflectionKey(IN HKEY hBase)
1834 {
1835     FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1836     return ERROR_CALL_NOT_IMPLEMENTED;
1837 }
1838 
1839 
1840 /************************************************************************
1841  *  RegEnableReflectionKey
1842  *
1843  * @unimplemented
1844  */
1845 LONG WINAPI
RegEnableReflectionKey(IN HKEY hBase)1846 RegEnableReflectionKey(IN HKEY hBase)
1847 {
1848     FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1849     return ERROR_CALL_NOT_IMPLEMENTED;
1850 }
1851 
1852 
1853 /******************************************************************************
1854  * RegpApplyRestrictions   [internal]
1855  *
1856  * Helper function for RegGetValueA/W.
1857  */
1858 static VOID
RegpApplyRestrictions(DWORD dwFlags,DWORD dwType,DWORD cbData,PLONG ret)1859 RegpApplyRestrictions(DWORD dwFlags,
1860                       DWORD dwType,
1861                       DWORD cbData,
1862                       PLONG ret)
1863 {
1864     /* Check if the type is restricted by the passed flags */
1865     if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1866     {
1867         DWORD dwMask = 0;
1868 
1869         switch (dwType)
1870         {
1871         case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1872         case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1873         case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1874         case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1875         case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1876         case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1877         case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1878         }
1879 
1880         if (dwFlags & dwMask)
1881         {
1882             /* Type is not restricted, check for size mismatch */
1883             if (dwType == REG_BINARY)
1884             {
1885                 DWORD cbExpect = 0;
1886 
1887                 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1888                     cbExpect = 4;
1889                 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1890                     cbExpect = 8;
1891 
1892                 if (cbExpect && cbData != cbExpect)
1893                     *ret = ERROR_DATATYPE_MISMATCH;
1894             }
1895         }
1896         else *ret = ERROR_UNSUPPORTED_TYPE;
1897     }
1898 }
1899 
1900 
1901 /******************************************************************************
1902  * RegGetValueW   [ADVAPI32.@]
1903  *
1904  * Retrieves the type and data for a value name associated with a key,
1905  * optionally expanding its content and restricting its type.
1906  *
1907  * PARAMS
1908  *  hKey      [I] Handle to an open key.
1909  *  pszSubKey [I] Name of the subkey of hKey.
1910  *  pszValue  [I] Name of value under hKey/szSubKey to query.
1911  *  dwFlags   [I] Flags restricting the value type to retrieve.
1912  *  pdwType   [O] Destination for the values type, may be NULL.
1913  *  pvData    [O] Destination for the values content, may be NULL.
1914  *  pcbData   [I/O] Size of pvData, updated with the size in bytes required to
1915  *                  retrieve the whole content, including the trailing '\0'
1916  *                  for strings.
1917  *
1918  * RETURNS
1919  *  Success: ERROR_SUCCESS
1920  *  Failure: nonzero error code from Winerror.h
1921  *
1922  * NOTES
1923  *  - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1924  *    expanded and pdwType is set to REG_SZ instead.
1925  *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1926  *    without RRF_NOEXPAND is thus not allowed.
1927  *    An exception is the case where RRF_RT_ANY is specified, because then
1928  *    RRF_NOEXPAND is allowed.
1929  */
1930 LSTATUS WINAPI
RegGetValueW(HKEY hKey,LPCWSTR pszSubKey,LPCWSTR pszValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData)1931 RegGetValueW(HKEY hKey,
1932              LPCWSTR pszSubKey,
1933              LPCWSTR pszValue,
1934              DWORD dwFlags,
1935              LPDWORD pdwType,
1936              PVOID pvData,
1937              LPDWORD pcbData)
1938 {
1939     DWORD dwType, cbData = pcbData ? *pcbData : 0;
1940     PVOID pvBuf = NULL;
1941     LONG ret;
1942 
1943     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1944           hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1945           pvData, pcbData, cbData);
1946 
1947     if (pvData && !pcbData)
1948         return ERROR_INVALID_PARAMETER;
1949     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1950             ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1951         return ERROR_INVALID_PARAMETER;
1952 
1953     if (pszSubKey && pszSubKey[0])
1954     {
1955         ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1956         if (ret != ERROR_SUCCESS) return ret;
1957     }
1958 
1959     ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1960 
1961     /* If we are going to expand we need to read in the whole the value even
1962      * if the passed buffer was too small as the expanded string might be
1963      * smaller than the unexpanded one and could fit into cbData bytes. */
1964     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1965         dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1966     {
1967         do
1968         {
1969             HeapFree(GetProcessHeap(), 0, pvBuf);
1970 
1971             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1972             if (!pvBuf)
1973             {
1974                 ret = ERROR_NOT_ENOUGH_MEMORY;
1975                 break;
1976             }
1977 
1978             if (ret == ERROR_MORE_DATA || !pvData)
1979                 ret = RegQueryValueExW(hKey, pszValue, NULL,
1980                                        &dwType, pvBuf, &cbData);
1981             else
1982             {
1983                 /* Even if cbData was large enough we have to copy the
1984                  * string since ExpandEnvironmentStrings can't handle
1985                  * overlapping buffers. */
1986                 CopyMemory(pvBuf, pvData, cbData);
1987             }
1988 
1989             /* Both the type or the value itself could have been modified in
1990              * between so we have to keep retrying until the buffer is large
1991              * enough or we no longer have to expand the value. */
1992         }
1993         while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1994 
1995         if (ret == ERROR_SUCCESS)
1996         {
1997             /* Recheck dwType in case it changed since the first call */
1998             if (dwType == REG_EXPAND_SZ)
1999             {
2000                 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2001                                                    pcbData ? *pcbData : 0) * sizeof(WCHAR);
2002                 dwType = REG_SZ;
2003                 if (pvData && pcbData && cbData > *pcbData)
2004                     ret = ERROR_MORE_DATA;
2005             }
2006             else if (pvData)
2007                 CopyMemory(pvData, pvBuf, *pcbData);
2008         }
2009 
2010         HeapFree(GetProcessHeap(), 0, pvBuf);
2011     }
2012 
2013     if (pszSubKey && pszSubKey[0])
2014         RegCloseKey(hKey);
2015 
2016     RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2017 
2018     if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2019         ZeroMemory(pvData, *pcbData);
2020 
2021     if (pdwType)
2022         *pdwType = dwType;
2023 
2024     if (pcbData)
2025         *pcbData = cbData;
2026 
2027     return ret;
2028 }
2029 
2030 
2031 /******************************************************************************
2032  * RegGetValueA   [ADVAPI32.@]
2033  *
2034  * See RegGetValueW.
2035  */
2036 LSTATUS WINAPI
RegGetValueA(HKEY hKey,LPCSTR pszSubKey,LPCSTR pszValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData)2037 RegGetValueA(HKEY hKey,
2038              LPCSTR pszSubKey,
2039              LPCSTR pszValue,
2040              DWORD dwFlags,
2041              LPDWORD pdwType,
2042              PVOID pvData,
2043              LPDWORD pcbData)
2044 {
2045     DWORD dwType, cbData = pcbData ? *pcbData : 0;
2046     PVOID pvBuf = NULL;
2047     LONG ret;
2048 
2049     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2050           hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2051           cbData);
2052 
2053     if (pvData && !pcbData)
2054         return ERROR_INVALID_PARAMETER;
2055     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2056             ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2057         return ERROR_INVALID_PARAMETER;
2058 
2059     if (pszSubKey && pszSubKey[0])
2060     {
2061         ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2062         if (ret != ERROR_SUCCESS) return ret;
2063     }
2064 
2065     ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2066 
2067     /* If we are going to expand we need to read in the whole the value even
2068      * if the passed buffer was too small as the expanded string might be
2069      * smaller than the unexpanded one and could fit into cbData bytes. */
2070     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2071         (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2072     {
2073         do {
2074             HeapFree(GetProcessHeap(), 0, pvBuf);
2075 
2076             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2077             if (!pvBuf)
2078             {
2079                 ret = ERROR_NOT_ENOUGH_MEMORY;
2080                 break;
2081             }
2082 
2083             if (ret == ERROR_MORE_DATA || !pvData)
2084                 ret = RegQueryValueExA(hKey, pszValue, NULL,
2085                                        &dwType, pvBuf, &cbData);
2086             else
2087             {
2088                 /* Even if cbData was large enough we have to copy the
2089                  * string since ExpandEnvironmentStrings can't handle
2090                  * overlapping buffers. */
2091                 CopyMemory(pvBuf, pvData, cbData);
2092             }
2093 
2094             /* Both the type or the value itself could have been modified in
2095              * between so we have to keep retrying until the buffer is large
2096              * enough or we no longer have to expand the value. */
2097         } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2098 
2099         if (ret == ERROR_SUCCESS)
2100         {
2101             /* Recheck dwType in case it changed since the first call */
2102             if (dwType == REG_EXPAND_SZ)
2103             {
2104                 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2105                                                    pcbData ? *pcbData : 0);
2106                 dwType = REG_SZ;
2107                 if(pvData && pcbData && cbData > *pcbData)
2108                     ret = ERROR_MORE_DATA;
2109             }
2110             else if (pvData)
2111                 CopyMemory(pvData, pvBuf, *pcbData);
2112         }
2113 
2114         HeapFree(GetProcessHeap(), 0, pvBuf);
2115     }
2116 
2117     if (pszSubKey && pszSubKey[0])
2118         RegCloseKey(hKey);
2119 
2120     RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2121 
2122     if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2123         ZeroMemory(pvData, *pcbData);
2124 
2125     if (pdwType) *pdwType = dwType;
2126     if (pcbData) *pcbData = cbData;
2127 
2128     return ret;
2129 }
2130 
2131 #endif // _ADVAPI32_VISTA_
2132 
2133 /************************************************************************
2134  *  RegSetKeyValueW
2135  *
2136  * @implemented
2137  */
2138 LONG WINAPI
RegSetKeyValueW(IN HKEY hKey,IN LPCWSTR lpSubKey OPTIONAL,IN LPCWSTR lpValueName OPTIONAL,IN DWORD dwType,IN LPCVOID lpData OPTIONAL,IN DWORD cbData)2139 RegSetKeyValueW(IN HKEY hKey,
2140                 IN LPCWSTR lpSubKey  OPTIONAL,
2141                 IN LPCWSTR lpValueName  OPTIONAL,
2142                 IN DWORD dwType,
2143                 IN LPCVOID lpData  OPTIONAL,
2144                 IN DWORD cbData)
2145 {
2146     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2147     NTSTATUS Status;
2148     LONG Ret;
2149 
2150     Status = MapDefaultKey(&KeyHandle,
2151                            hKey);
2152     if (!NT_SUCCESS(Status))
2153     {
2154         return RtlNtStatusToDosError(Status);
2155     }
2156 
2157     if (lpSubKey != NULL)
2158     {
2159         OBJECT_ATTRIBUTES ObjectAttributes;
2160         UNICODE_STRING SubKeyName;
2161 
2162         RtlInitUnicodeString(&SubKeyName, lpSubKey);
2163 
2164         InitializeObjectAttributes(&ObjectAttributes,
2165                                    &SubKeyName,
2166                                    OBJ_CASE_INSENSITIVE,
2167                                    KeyHandle,
2168                                    NULL);
2169 
2170         Status = NtOpenKey(&SubKeyHandle,
2171                            KEY_SET_VALUE,
2172                            &ObjectAttributes);
2173         if (!NT_SUCCESS(Status))
2174         {
2175             Ret = RtlNtStatusToDosError(Status);
2176             goto Cleanup;
2177         }
2178 
2179         CurKey = SubKeyHandle;
2180     }
2181     else
2182         CurKey = KeyHandle;
2183 
2184     Ret = RegSetValueExW(CurKey,
2185                          lpValueName,
2186                          0,
2187                          dwType,
2188                          lpData,
2189                          cbData);
2190 
2191     if (SubKeyHandle != NULL)
2192     {
2193         NtClose(SubKeyHandle);
2194     }
2195 
2196 Cleanup:
2197     ClosePredefKey(KeyHandle);
2198 
2199     return Ret;
2200 }
2201 
2202 #ifndef _ADVAPI32_VISTA_
2203 
2204 /************************************************************************
2205  *  RegSetKeyValueA
2206  *
2207  * @implemented
2208  */
2209 LONG WINAPI
RegSetKeyValueA(IN HKEY hKey,IN LPCSTR lpSubKey OPTIONAL,IN LPCSTR lpValueName OPTIONAL,IN DWORD dwType,IN LPCVOID lpData OPTIONAL,IN DWORD cbData)2210 RegSetKeyValueA(IN HKEY hKey,
2211                 IN LPCSTR lpSubKey  OPTIONAL,
2212                 IN LPCSTR lpValueName  OPTIONAL,
2213                 IN DWORD dwType,
2214                 IN LPCVOID lpData  OPTIONAL,
2215                 IN DWORD cbData)
2216 {
2217     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2218     NTSTATUS Status;
2219     LONG Ret;
2220 
2221     Status = MapDefaultKey(&KeyHandle,
2222                            hKey);
2223     if (!NT_SUCCESS(Status))
2224     {
2225         return RtlNtStatusToDosError(Status);
2226     }
2227 
2228     if (lpSubKey != NULL)
2229     {
2230         OBJECT_ATTRIBUTES ObjectAttributes;
2231         UNICODE_STRING SubKeyName;
2232 
2233         if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
2234         {
2235             Ret = ERROR_NOT_ENOUGH_MEMORY;
2236             goto Cleanup;
2237         }
2238 
2239         InitializeObjectAttributes(&ObjectAttributes,
2240                                    &SubKeyName,
2241                                    OBJ_CASE_INSENSITIVE,
2242                                    KeyHandle,
2243                                    NULL);
2244 
2245         Status = NtOpenKey(&SubKeyHandle,
2246                            KEY_SET_VALUE,
2247                            &ObjectAttributes);
2248 
2249         RtlFreeUnicodeString(&SubKeyName);
2250 
2251         if (!NT_SUCCESS(Status))
2252         {
2253             Ret = RtlNtStatusToDosError(Status);
2254             goto Cleanup;
2255         }
2256 
2257         CurKey = SubKeyHandle;
2258     }
2259     else
2260         CurKey = KeyHandle;
2261 
2262     Ret = RegSetValueExA(CurKey,
2263                          lpValueName,
2264                          0,
2265                          dwType,
2266                          lpData,
2267                          cbData);
2268 
2269     if (SubKeyHandle != NULL)
2270     {
2271         NtClose(SubKeyHandle);
2272     }
2273 
2274 Cleanup:
2275     ClosePredefKey(KeyHandle);
2276 
2277     return Ret;
2278 }
2279 
2280 
2281 /************************************************************************
2282  *  RegDeleteValueA
2283  *
2284  * @implemented
2285  */
2286 LONG WINAPI
RegDeleteValueA(HKEY hKey,LPCSTR lpValueName)2287 RegDeleteValueA(HKEY hKey,
2288                 LPCSTR lpValueName)
2289 {
2290     UNICODE_STRING ValueName;
2291     HANDLE KeyHandle;
2292     NTSTATUS Status;
2293     LONG ErrorCode = ERROR_SUCCESS;
2294 
2295     Status = MapDefaultKey(&KeyHandle,
2296                            hKey);
2297     if (!NT_SUCCESS(Status))
2298     {
2299         return RtlNtStatusToDosError(Status);
2300     }
2301 
2302     if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
2303     {
2304         ClosePredefKey(KeyHandle);
2305         return ERROR_NOT_ENOUGH_MEMORY;
2306     }
2307 
2308     if (IsHKCRKey(KeyHandle))
2309     {
2310         ErrorCode = DeleteHKCRValue(KeyHandle, &ValueName);
2311     }
2312     else
2313     {
2314         Status = NtDeleteValueKey(KeyHandle, &ValueName);
2315         if (!NT_SUCCESS(Status))
2316             ErrorCode = RtlNtStatusToDosError(Status);
2317     }
2318     RtlFreeUnicodeString(&ValueName);
2319     ClosePredefKey(KeyHandle);
2320     return ErrorCode;
2321 }
2322 
2323 
2324 /************************************************************************
2325  *  RegDeleteValueW
2326  *
2327  * @implemented
2328  */
2329 LONG WINAPI
RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName)2330 RegDeleteValueW(HKEY hKey,
2331                 LPCWSTR lpValueName)
2332 {
2333     UNICODE_STRING ValueName;
2334     NTSTATUS Status;
2335     HANDLE KeyHandle;
2336     LONG ErrorCode = ERROR_SUCCESS;
2337 
2338     Status = MapDefaultKey(&KeyHandle,
2339                            hKey);
2340     if (!NT_SUCCESS(Status))
2341     {
2342         return RtlNtStatusToDosError(Status);
2343     }
2344 
2345     RtlInitUnicodeString(&ValueName, lpValueName);
2346 
2347     if (IsHKCRKey(KeyHandle))
2348     {
2349         ErrorCode = DeleteHKCRValue(KeyHandle, &ValueName);
2350     }
2351     else
2352     {
2353         Status = NtDeleteValueKey(KeyHandle, &ValueName);
2354         if (!NT_SUCCESS(Status))
2355             ErrorCode = RtlNtStatusToDosError(Status);
2356     }
2357     ClosePredefKey(KeyHandle);
2358     return ErrorCode;
2359 }
2360 
2361 
2362 /************************************************************************
2363  *  RegEnumKeyA
2364  *
2365  * @implemented
2366  */
2367 LONG WINAPI
RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cbName)2368 RegEnumKeyA(HKEY hKey,
2369             DWORD dwIndex,
2370             LPSTR lpName,
2371             DWORD cbName)
2372 {
2373     DWORD dwLength;
2374 
2375     dwLength = cbName;
2376     return RegEnumKeyExA(hKey,
2377                          dwIndex,
2378                          lpName,
2379                          &dwLength,
2380                          NULL,
2381                          NULL,
2382                          NULL,
2383                          NULL);
2384 }
2385 
2386 
2387 /************************************************************************
2388  *  RegEnumKeyW
2389  *
2390  * @implemented
2391  */
2392 LONG WINAPI
RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cbName)2393 RegEnumKeyW(HKEY hKey,
2394             DWORD dwIndex,
2395             LPWSTR lpName,
2396             DWORD cbName)
2397 {
2398     DWORD dwLength;
2399 
2400     dwLength = cbName;
2401     return RegEnumKeyExW(hKey,
2402                          dwIndex,
2403                          lpName,
2404                          &dwLength,
2405                          NULL,
2406                          NULL,
2407                          NULL,
2408                          NULL);
2409 }
2410 
2411 
2412 /************************************************************************
2413  *  RegEnumKeyExA
2414  *
2415  * @implemented
2416  */
2417 LONG
2418 WINAPI
RegEnumKeyExA(_In_ HKEY hKey,_In_ DWORD dwIndex,_Out_ LPSTR lpName,_Inout_ LPDWORD lpcbName,_Reserved_ LPDWORD lpReserved,_Out_opt_ LPSTR lpClass,_Inout_opt_ LPDWORD lpcbClass,_Out_opt_ PFILETIME lpftLastWriteTime)2419 RegEnumKeyExA(
2420     _In_ HKEY hKey,
2421     _In_ DWORD dwIndex,
2422     _Out_ LPSTR lpName,
2423     _Inout_ LPDWORD lpcbName,
2424     _Reserved_ LPDWORD lpReserved,
2425     _Out_opt_ LPSTR lpClass,
2426     _Inout_opt_ LPDWORD lpcbClass,
2427     _Out_opt_ PFILETIME lpftLastWriteTime)
2428 {
2429     WCHAR* NameBuffer = NULL;
2430     WCHAR* ClassBuffer = NULL;
2431     DWORD NameLength, ClassLength;
2432     LONG ErrorCode;
2433 
2434     /* Allocate our buffers */
2435     if (*lpcbName > 0)
2436     {
2437         NameLength = *lpcbName;
2438         NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR));
2439         if (NameBuffer == NULL)
2440         {
2441             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2442             goto Exit;
2443         }
2444     }
2445 
2446     if (lpClass)
2447     {
2448         if (*lpcbClass > 0)
2449         {
2450             ClassLength = *lpcbClass;
2451             ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR));
2452             if (ClassBuffer == NULL)
2453             {
2454                 ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2455                 goto Exit;
2456             }
2457         }
2458     }
2459 
2460     /* Do the actual call */
2461     ErrorCode = RegEnumKeyExW(
2462         hKey,
2463         dwIndex,
2464         NameBuffer,
2465         lpcbName,
2466         lpReserved,
2467         ClassBuffer,
2468         lpcbClass,
2469         lpftLastWriteTime);
2470 
2471     if (ErrorCode != ERROR_SUCCESS)
2472         goto Exit;
2473 
2474     /* Convert the strings */
2475     RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR));
2476     /* NULL terminate if we can */
2477     if (NameLength > *lpcbName)
2478         lpName[*lpcbName] = '\0';
2479 
2480     if (lpClass)
2481     {
2482         RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR));
2483         if (ClassLength > *lpcbClass)
2484             lpClass[*lpcbClass] = '\0';
2485     }
2486 
2487 Exit:
2488     if (NameBuffer)
2489         RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2490     if (ClassBuffer)
2491         RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
2492 
2493     return ErrorCode;
2494 }
2495 
2496 
2497 /************************************************************************
2498  *  RegEnumKeyExW
2499  *
2500  * @implemented
2501  */
2502 LONG
2503 WINAPI
RegEnumKeyExW(_In_ HKEY hKey,_In_ DWORD dwIndex,_Out_ LPWSTR lpName,_Inout_ LPDWORD lpcbName,_Reserved_ LPDWORD lpReserved,_Out_opt_ LPWSTR lpClass,_Inout_opt_ LPDWORD lpcbClass,_Out_opt_ PFILETIME lpftLastWriteTime)2504 RegEnumKeyExW(
2505     _In_ HKEY hKey,
2506     _In_ DWORD dwIndex,
2507     _Out_ LPWSTR lpName,
2508     _Inout_ LPDWORD lpcbName,
2509     _Reserved_ LPDWORD lpReserved,
2510     _Out_opt_ LPWSTR lpClass,
2511     _Inout_opt_ LPDWORD lpcbClass,
2512     _Out_opt_ PFILETIME lpftLastWriteTime)
2513 {
2514     union
2515     {
2516         KEY_NODE_INFORMATION Node;
2517         KEY_BASIC_INFORMATION Basic;
2518     } *KeyInfo;
2519 
2520     ULONG BufferSize;
2521     ULONG ResultSize;
2522     ULONG NameLength;
2523     ULONG ClassLength = 0;
2524     HANDLE KeyHandle;
2525     LONG ErrorCode = ERROR_SUCCESS;
2526     NTSTATUS Status;
2527 
2528     Status = MapDefaultKey(&KeyHandle,
2529                            hKey);
2530     if (!NT_SUCCESS(Status))
2531     {
2532         return RtlNtStatusToDosError(Status);
2533     }
2534 
2535     if (IsHKCRKey(KeyHandle))
2536     {
2537         ErrorCode = EnumHKCRKey(
2538             KeyHandle,
2539             dwIndex,
2540             lpName,
2541             lpcbName,
2542             lpReserved,
2543             lpClass,
2544             lpcbClass,
2545             lpftLastWriteTime);
2546         ClosePredefKey(KeyHandle);
2547         return ErrorCode;
2548     }
2549 
2550     if (*lpcbName > 0)
2551     {
2552         NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2553     }
2554     else
2555     {
2556         NameLength = 0;
2557     }
2558 
2559     if (lpClass)
2560     {
2561         if (*lpcbClass > 0)
2562         {
2563             ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2564         }
2565         else
2566         {
2567             ClassLength = 0;
2568         }
2569 
2570         BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2571     }
2572     else
2573     {
2574         BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2575     }
2576 
2577     KeyInfo = RtlAllocateHeap(ProcessHeap,
2578                               0,
2579                               BufferSize);
2580     if (KeyInfo == NULL)
2581     {
2582         ErrorCode = ERROR_OUTOFMEMORY;
2583         goto Cleanup;
2584     }
2585 
2586     Status = NtEnumerateKey(KeyHandle,
2587                             (ULONG)dwIndex,
2588                             lpClass ? KeyNodeInformation : KeyBasicInformation,
2589                             KeyInfo,
2590                             BufferSize,
2591                             &ResultSize);
2592     TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2593     if (!NT_SUCCESS(Status))
2594     {
2595         ErrorCode = RtlNtStatusToDosError (Status);
2596     }
2597     else
2598     {
2599         if (lpClass == NULL)
2600         {
2601             if (KeyInfo->Basic.NameLength > NameLength)
2602             {
2603                 ErrorCode = ERROR_MORE_DATA;
2604             }
2605             else
2606             {
2607                 RtlCopyMemory(lpName,
2608                               KeyInfo->Basic.Name,
2609                               KeyInfo->Basic.NameLength);
2610                 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2611                 lpName[*lpcbName] = 0;
2612             }
2613         }
2614         else
2615         {
2616             if (KeyInfo->Node.NameLength > NameLength ||
2617                 KeyInfo->Node.ClassLength > ClassLength)
2618             {
2619                 ErrorCode = ERROR_MORE_DATA;
2620             }
2621             else
2622             {
2623                 RtlCopyMemory(lpName,
2624                               KeyInfo->Node.Name,
2625                               KeyInfo->Node.NameLength);
2626                 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2627                 lpName[*lpcbName] = 0;
2628                 RtlCopyMemory(lpClass,
2629                               (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2630                               KeyInfo->Node.ClassLength);
2631                 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2632                 lpClass[*lpcbClass] = 0;
2633             }
2634         }
2635 
2636         if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2637         {
2638             if (lpClass == NULL)
2639             {
2640                 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2641                 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2642             }
2643             else
2644             {
2645                 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2646                 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2647             }
2648         }
2649     }
2650 
2651     RtlFreeHeap(ProcessHeap,
2652                 0,
2653                 KeyInfo);
2654 
2655 Cleanup:
2656     ClosePredefKey(KeyHandle);
2657 
2658     return ErrorCode;
2659 }
2660 
2661 
2662 /************************************************************************
2663  *  RegEnumValueA
2664  *
2665  * @implemented
2666  */
2667 LONG WINAPI
RegEnumValueA(_In_ HKEY hKey,_In_ DWORD dwIndex,_Out_ LPSTR lpName,_Inout_ LPDWORD lpcbName,_Reserved_ LPDWORD lpdwReserved,_Out_opt_ LPDWORD lpdwType,_Out_opt_ LPBYTE lpData,_Inout_opt_ LPDWORD lpcbData)2668 RegEnumValueA(
2669     _In_ HKEY hKey,
2670     _In_ DWORD dwIndex,
2671     _Out_ LPSTR lpName,
2672     _Inout_ LPDWORD lpcbName,
2673     _Reserved_ LPDWORD lpdwReserved,
2674     _Out_opt_ LPDWORD lpdwType,
2675     _Out_opt_ LPBYTE lpData,
2676     _Inout_opt_ LPDWORD lpcbData)
2677 {
2678     WCHAR* NameBuffer;
2679     DWORD NameBufferSize, NameLength;
2680     LONG ErrorCode;
2681     DWORD LocalType = REG_NONE;
2682     BOOL NameOverflow = FALSE;
2683 
2684     /* Do parameter checks now, once and for all. */
2685     if (!lpName || !lpcbName)
2686         return ERROR_INVALID_PARAMETER;
2687 
2688     if ((lpData && !lpcbData) || lpdwReserved)
2689         return ERROR_INVALID_PARAMETER;
2690 
2691     /* Get the size of the buffer we must use for the first call to RegEnumValueW */
2692     ErrorCode = RegQueryInfoKeyW(
2693         hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
2694     if (ErrorCode != ERROR_SUCCESS)
2695         return ErrorCode;
2696 
2697     /* Add space for the null terminator */
2698     NameBufferSize++;
2699 
2700     /* Allocate the buffer for the unicode name */
2701     NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR));
2702     if (NameBuffer == NULL)
2703     {
2704         return ERROR_NOT_ENOUGH_MEMORY;
2705     }
2706 
2707     /*
2708      * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
2709      * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
2710      * is an overflow on the data or on the name during the the second call. So the first time, we make the
2711      * call with the supplied value. This is merdique, but this is how it is.
2712      */
2713     NameLength = *lpcbName;
2714     ErrorCode = RegEnumValueW(
2715         hKey,
2716         dwIndex,
2717         NameBuffer,
2718         &NameLength,
2719         NULL,
2720         &LocalType,
2721         NULL,
2722         NULL);
2723     if (ErrorCode != ERROR_SUCCESS)
2724     {
2725         if (ErrorCode == ERROR_MORE_DATA)
2726             NameOverflow = TRUE;
2727         else
2728             goto Exit;
2729     }
2730 
2731     if (is_string(LocalType) && lpcbData)
2732     {
2733         /* We must allocate a buffer to get the unicode data */
2734         DWORD DataBufferSize = *lpcbData * sizeof(WCHAR);
2735         WCHAR* DataBuffer = NULL;
2736         DWORD DataLength = *lpcbData;
2737         LPSTR DataStr = (LPSTR)lpData;
2738 
2739         if (lpData)
2740             DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR));
2741 
2742         /* Do the real call */
2743         ErrorCode = RegEnumValueW(
2744             hKey,
2745             dwIndex,
2746             NameBuffer,
2747             &NameBufferSize,
2748             lpdwReserved,
2749             lpdwType,
2750             (LPBYTE)DataBuffer,
2751             &DataBufferSize);
2752 
2753         *lpcbData = DataBufferSize / sizeof(WCHAR);
2754 
2755         if (ErrorCode != ERROR_SUCCESS)
2756         {
2757             RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2758             goto Exit;
2759         }
2760 
2761         /* Copy the data whatever the error code is */
2762         if (lpData)
2763         {
2764             /* Do the data conversion */
2765             RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize);
2766             /* NULL-terminate if there is enough room */
2767             if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0'))
2768                 DataStr[*lpcbData] = '\0';
2769         }
2770 
2771         RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
2772     }
2773     else
2774     {
2775         /* No data conversion needed. Do the call with provided buffers */
2776         ErrorCode = RegEnumValueW(
2777             hKey,
2778             dwIndex,
2779             NameBuffer,
2780             &NameBufferSize,
2781             lpdwReserved,
2782             lpdwType,
2783             lpData,
2784             lpcbData);
2785 
2786         if (ErrorCode != ERROR_SUCCESS)
2787         {
2788             goto Exit;
2789         }
2790     }
2791 
2792     if (NameOverflow)
2793     {
2794         ErrorCode = ERROR_MORE_DATA;
2795         goto Exit;
2796     }
2797 
2798     /* Convert the name string */
2799     RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR));
2800     lpName[*lpcbName] = ANSI_NULL;
2801 
2802 Exit:
2803     if (NameBuffer)
2804         RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2805 
2806     return ErrorCode;
2807 }
2808 
2809 
2810 /******************************************************************************
2811  * RegEnumValueW   [ADVAPI32.@]
2812  * @implemented
2813  *
2814  * PARAMS
2815  *  hkey       [I] Handle to key to query
2816  *  index      [I] Index of value to query
2817  *  value      [O] Value string
2818  *  val_count  [I/O] Size of value buffer (in wchars)
2819  *  reserved   [I] Reserved
2820  *  type       [O] Type code
2821  *  data       [O] Value data
2822  *  count      [I/O] Size of data buffer (in bytes)
2823  *
2824  * RETURNS
2825  *  Success: ERROR_SUCCESS
2826  *  Failure: nonzero error code from Winerror.h
2827  */
2828 LONG
2829 WINAPI
RegEnumValueW(_In_ HKEY hKey,_In_ DWORD index,_Out_ LPWSTR value,_Inout_ PDWORD val_count,_Reserved_ PDWORD reserved,_Out_opt_ PDWORD type,_Out_opt_ LPBYTE data,_Inout_opt_ PDWORD count)2830 RegEnumValueW(
2831     _In_ HKEY hKey,
2832     _In_ DWORD index,
2833     _Out_ LPWSTR value,
2834     _Inout_ PDWORD val_count,
2835     _Reserved_ PDWORD reserved,
2836     _Out_opt_ PDWORD type,
2837     _Out_opt_ LPBYTE data,
2838     _Inout_opt_ PDWORD count)
2839 {
2840     HANDLE KeyHandle;
2841     NTSTATUS status;
2842     ULONG total_size;
2843     char buffer[256], *buf_ptr = buffer;
2844     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2845     static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2846 
2847     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2848           hKey, index, value, val_count, reserved, type, data, count );
2849 
2850     if (!value || !val_count)
2851         return ERROR_INVALID_PARAMETER;
2852 
2853     if ((data && !count) || reserved)
2854         return ERROR_INVALID_PARAMETER;
2855 
2856     status = MapDefaultKey(&KeyHandle, hKey);
2857     if (!NT_SUCCESS(status))
2858     {
2859         return RtlNtStatusToDosError(status);
2860     }
2861 
2862     if (IsHKCRKey(KeyHandle))
2863     {
2864         LONG ErrorCode = EnumHKCRValue(
2865             KeyHandle,
2866             index,
2867             value,
2868             val_count,
2869             reserved,
2870             type,
2871             data,
2872             count);
2873         ClosePredefKey(KeyHandle);
2874         return ErrorCode;
2875     }
2876 
2877     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2878     if (data) total_size += *count;
2879     total_size = min( sizeof(buffer), total_size );
2880 
2881     status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2882                                   buffer, total_size, &total_size );
2883     if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
2884 
2885     if (value || data)
2886     {
2887         /* retry with a dynamically allocated buffer */
2888         while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
2889         {
2890             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2891             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2892             {
2893                 status = ERROR_NOT_ENOUGH_MEMORY;
2894                 goto done;
2895             }
2896             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2897             status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2898                                           buf_ptr, total_size, &total_size );
2899         }
2900 
2901         if (status) goto done;
2902 
2903         if (value)
2904         {
2905             if (info->NameLength/sizeof(WCHAR) >= *val_count)
2906             {
2907                 status = STATUS_BUFFER_OVERFLOW;
2908                 goto overflow;
2909             }
2910             memcpy( value, info->Name, info->NameLength );
2911             *val_count = info->NameLength / sizeof(WCHAR);
2912             value[*val_count] = 0;
2913         }
2914 
2915         if (data)
2916         {
2917             if (info->DataLength > *count)
2918             {
2919                 status = STATUS_BUFFER_OVERFLOW;
2920                 goto overflow;
2921             }
2922             memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
2923             if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
2924             {
2925                 /* if the type is REG_SZ and data is not 0-terminated
2926                  * and there is enough space in the buffer NT appends a \0 */
2927                 WCHAR *ptr = (WCHAR *)(data + info->DataLength);
2928                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2929             }
2930         }
2931     }
2932     else status = STATUS_SUCCESS;
2933 
2934  overflow:
2935     if (type) *type = info->Type;
2936     if (count) *count = info->DataLength;
2937 
2938  done:
2939     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2940     ClosePredefKey(KeyHandle);
2941     return RtlNtStatusToDosError(status);
2942 }
2943 
2944 
2945 /************************************************************************
2946  *  RegFlushKey
2947  *
2948  * @implemented
2949  */
2950 LONG WINAPI
RegFlushKey(HKEY hKey)2951 RegFlushKey(HKEY hKey)
2952 {
2953     HANDLE KeyHandle;
2954     NTSTATUS Status;
2955 
2956     if (hKey == HKEY_PERFORMANCE_DATA)
2957     {
2958         return ERROR_SUCCESS;
2959     }
2960 
2961     Status = MapDefaultKey(&KeyHandle,
2962                            hKey);
2963     if (!NT_SUCCESS(Status))
2964     {
2965         return RtlNtStatusToDosError(Status);
2966     }
2967 
2968     Status = NtFlushKey(KeyHandle);
2969 
2970     ClosePredefKey(KeyHandle);
2971 
2972     if (!NT_SUCCESS(Status))
2973     {
2974         return RtlNtStatusToDosError(Status);
2975     }
2976 
2977     return ERROR_SUCCESS;
2978 }
2979 
2980 
2981 /************************************************************************
2982  *  RegGetKeySecurity
2983  *
2984  * @implemented
2985  */
2986 LONG WINAPI
RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor)2987 RegGetKeySecurity(HKEY hKey,
2988                   SECURITY_INFORMATION SecurityInformation,
2989                   PSECURITY_DESCRIPTOR pSecurityDescriptor,
2990                   LPDWORD lpcbSecurityDescriptor)
2991 {
2992     HANDLE KeyHandle;
2993     NTSTATUS Status;
2994 
2995     if (hKey == HKEY_PERFORMANCE_DATA)
2996     {
2997         return ERROR_INVALID_HANDLE;
2998     }
2999 
3000     Status = MapDefaultKey(&KeyHandle,
3001                            hKey);
3002     if (!NT_SUCCESS(Status))
3003     {
3004         TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3005         return RtlNtStatusToDosError(Status);
3006     }
3007 
3008     Status = NtQuerySecurityObject(KeyHandle,
3009                                    SecurityInformation,
3010                                    pSecurityDescriptor,
3011                                    *lpcbSecurityDescriptor,
3012                                    lpcbSecurityDescriptor);
3013 
3014     ClosePredefKey(KeyHandle);
3015 
3016     if (!NT_SUCCESS(Status))
3017     {
3018          WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3019          return RtlNtStatusToDosError(Status);
3020     }
3021 
3022     return ERROR_SUCCESS;
3023 }
3024 
3025 
3026 /************************************************************************
3027  *  RegLoadKeyA
3028  *
3029  * @implemented
3030  */
3031 LONG WINAPI
RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile)3032 RegLoadKeyA(HKEY hKey,
3033             LPCSTR lpSubKey,
3034             LPCSTR lpFile)
3035 {
3036     UNICODE_STRING FileName;
3037     UNICODE_STRING KeyName;
3038     LONG ErrorCode;
3039 
3040     RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
3041     RtlInitEmptyUnicodeString(&FileName, NULL, 0);
3042 
3043     if (lpSubKey)
3044     {
3045         if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
3046         {
3047             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3048             goto Exit;
3049         }
3050     }
3051 
3052     if (lpFile)
3053     {
3054         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
3055         {
3056             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3057             goto Exit;
3058         }
3059     }
3060 
3061     ErrorCode = RegLoadKeyW(hKey,
3062                             KeyName.Buffer,
3063                             FileName.Buffer);
3064 
3065 Exit:
3066     RtlFreeUnicodeString(&FileName);
3067     RtlFreeUnicodeString(&KeyName);
3068 
3069     return ErrorCode;
3070 }
3071 
3072 
3073 /************************************************************************
3074  *  RegLoadKeyW
3075  *
3076  * @implemented
3077  */
3078 LONG WINAPI
RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile)3079 RegLoadKeyW(HKEY hKey,
3080             LPCWSTR lpSubKey,
3081             LPCWSTR lpFile)
3082 {
3083     OBJECT_ATTRIBUTES FileObjectAttributes;
3084     OBJECT_ATTRIBUTES KeyObjectAttributes;
3085     UNICODE_STRING FileName;
3086     UNICODE_STRING KeyName;
3087     HANDLE KeyHandle;
3088     NTSTATUS Status;
3089     LONG ErrorCode = ERROR_SUCCESS;
3090 
3091     if (hKey == HKEY_PERFORMANCE_DATA)
3092     {
3093         return ERROR_INVALID_HANDLE;
3094     }
3095 
3096     Status = MapDefaultKey(&KeyHandle,
3097                            hKey);
3098     if (!NT_SUCCESS(Status))
3099     {
3100         return RtlNtStatusToDosError(Status);
3101     }
3102 
3103     if (!RtlDosPathNameToNtPathName_U(lpFile,
3104                                       &FileName,
3105                                       NULL,
3106                                       NULL))
3107     {
3108       ErrorCode = ERROR_BAD_PATHNAME;
3109       goto Cleanup;
3110     }
3111 
3112     InitializeObjectAttributes(&FileObjectAttributes,
3113                                &FileName,
3114                                OBJ_CASE_INSENSITIVE,
3115                                NULL,
3116                                NULL);
3117 
3118     RtlInitUnicodeString(&KeyName, lpSubKey);
3119 
3120     InitializeObjectAttributes(&KeyObjectAttributes,
3121                                &KeyName,
3122                                OBJ_CASE_INSENSITIVE,
3123                                KeyHandle,
3124                                NULL);
3125 
3126     Status = NtLoadKey(&KeyObjectAttributes,
3127                        &FileObjectAttributes);
3128 
3129     RtlFreeHeap(RtlGetProcessHeap(),
3130                 0,
3131                 FileName.Buffer);
3132 
3133     if (!NT_SUCCESS(Status))
3134     {
3135         ErrorCode = RtlNtStatusToDosError(Status);
3136         goto Cleanup;
3137     }
3138 
3139 Cleanup:
3140     ClosePredefKey(KeyHandle);
3141 
3142     return ErrorCode;
3143 }
3144 
3145 
3146 /************************************************************************
3147  *  RegNotifyChangeKeyValue
3148  *
3149  * @unimplemented
3150  */
3151 LONG WINAPI
RegNotifyChangeKeyValue(HKEY hKey,BOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,BOOL fAsynchronous)3152 RegNotifyChangeKeyValue(HKEY hKey,
3153                         BOOL bWatchSubtree,
3154                         DWORD dwNotifyFilter,
3155                         HANDLE hEvent,
3156                         BOOL fAsynchronous)
3157 {
3158     IO_STATUS_BLOCK IoStatusBlock;
3159     HANDLE KeyHandle;
3160     NTSTATUS Status;
3161     LONG ErrorCode = ERROR_SUCCESS;
3162 
3163     if (hKey == HKEY_PERFORMANCE_DATA)
3164     {
3165         return ERROR_INVALID_HANDLE;
3166     }
3167 
3168     if ((fAsynchronous != FALSE) && (hEvent == NULL))
3169     {
3170         return ERROR_INVALID_PARAMETER;
3171     }
3172 
3173     Status = MapDefaultKey(&KeyHandle,
3174                            hKey);
3175     if (!NT_SUCCESS(Status))
3176     {
3177         return RtlNtStatusToDosError(Status);
3178     }
3179 
3180     /* FIXME: Remote key handles must fail */
3181 
3182     Status = NtNotifyChangeKey(KeyHandle,
3183                                hEvent,
3184                                0,
3185                                0,
3186                                &IoStatusBlock,
3187                                dwNotifyFilter,
3188                                bWatchSubtree,
3189                                0,
3190                                0,
3191                                fAsynchronous);
3192     if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3193     {
3194         ErrorCode = RtlNtStatusToDosError(Status);
3195     }
3196 
3197     ClosePredefKey(KeyHandle);
3198 
3199     return ErrorCode;
3200 }
3201 
3202 
3203 /************************************************************************
3204  *  RegOpenCurrentUser
3205  *
3206  * @implemented
3207  */
3208 LONG WINAPI
RegOpenCurrentUser(IN REGSAM samDesired,OUT PHKEY phkResult)3209 RegOpenCurrentUser(IN REGSAM samDesired,
3210                    OUT PHKEY phkResult)
3211 {
3212     NTSTATUS Status;
3213 
3214     Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3215                                 (PHANDLE)phkResult);
3216     if (!NT_SUCCESS(Status))
3217     {
3218         /* NOTE - don't set the last error code! just return the error! */
3219         return RtlNtStatusToDosError(Status);
3220     }
3221 
3222     return ERROR_SUCCESS;
3223 }
3224 
3225 
3226 /************************************************************************
3227  *  RegOpenKeyA
3228  *
3229  *  20050503 Fireball - imported from WINE
3230  *
3231  * @implemented
3232  */
3233 LONG WINAPI
RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult)3234 RegOpenKeyA(HKEY hKey,
3235             LPCSTR lpSubKey,
3236             PHKEY phkResult)
3237 {
3238     TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3239           hKey, lpSubKey, phkResult);
3240 
3241     if (!phkResult)
3242         return ERROR_INVALID_PARAMETER;
3243 
3244     if (!hKey && !lpSubKey)
3245     {
3246         *phkResult = hKey;
3247         return ERROR_SUCCESS;
3248     }
3249 
3250     return RegOpenKeyExA(hKey,
3251                          lpSubKey,
3252                          0,
3253                          MAXIMUM_ALLOWED,
3254                          phkResult);
3255 }
3256 
3257 
3258 /************************************************************************
3259  *  RegOpenKeyW
3260  *
3261  *  19981101 Ariadne
3262  *  19990525 EA
3263  *  20050503 Fireball - imported from WINE
3264  *
3265  * @implemented
3266  */
3267 LONG WINAPI
RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult)3268 RegOpenKeyW(HKEY hKey,
3269             LPCWSTR lpSubKey,
3270             PHKEY phkResult)
3271 {
3272     TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3273           hKey, lpSubKey, phkResult);
3274 
3275     if (!phkResult)
3276         return ERROR_INVALID_PARAMETER;
3277 
3278     if (!hKey && !lpSubKey)
3279     {
3280         *phkResult = hKey;
3281         return ERROR_SUCCESS;
3282     }
3283 
3284     return RegOpenKeyExW(hKey,
3285                          lpSubKey,
3286                          0,
3287                          MAXIMUM_ALLOWED,
3288                          phkResult);
3289 }
3290 
3291 
3292 /************************************************************************
3293  *  RegOpenKeyExA
3294  *
3295  * @implemented
3296  */
3297 LONG WINAPI
RegOpenKeyExA(_In_ HKEY hKey,_In_ LPCSTR lpSubKey,_In_ DWORD ulOptions,_In_ REGSAM samDesired,_Out_ PHKEY phkResult)3298 RegOpenKeyExA(
3299     _In_ HKEY hKey,
3300     _In_ LPCSTR lpSubKey,
3301     _In_ DWORD ulOptions,
3302     _In_ REGSAM samDesired,
3303     _Out_ PHKEY phkResult)
3304 {
3305     UNICODE_STRING SubKeyString;
3306     LONG ErrorCode;
3307 
3308     TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3309           hKey, lpSubKey, ulOptions, samDesired, phkResult);
3310 
3311     if (lpSubKey)
3312     {
3313         if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
3314             return ERROR_NOT_ENOUGH_MEMORY;
3315     }
3316     else
3317         RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
3318 
3319     ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
3320 
3321     RtlFreeUnicodeString(&SubKeyString);
3322 
3323     return ErrorCode;
3324 }
3325 
3326 
3327 /************************************************************************
3328  *  RegOpenKeyExW
3329  *
3330  * @implemented
3331  */
3332 LONG WINAPI
RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)3333 RegOpenKeyExW(HKEY hKey,
3334               LPCWSTR lpSubKey,
3335               DWORD ulOptions,
3336               REGSAM samDesired,
3337               PHKEY phkResult)
3338 {
3339     OBJECT_ATTRIBUTES ObjectAttributes;
3340     UNICODE_STRING SubKeyString;
3341     HANDLE KeyHandle;
3342     NTSTATUS Status;
3343     ULONG Attributes = OBJ_CASE_INSENSITIVE;
3344     LONG ErrorCode = ERROR_SUCCESS;
3345     BOOLEAN SubKeyStringAllocated = FALSE;
3346 
3347     TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3348           hKey, lpSubKey, ulOptions, samDesired, phkResult);
3349     if (!phkResult)
3350     {
3351         return ERROR_INVALID_PARAMETER;
3352     }
3353 
3354     if (!hKey && lpSubKey && phkResult)
3355     {
3356         return ERROR_INVALID_HANDLE;
3357     }
3358 
3359     if (IsPredefKey(hKey) && (!lpSubKey || !*lpSubKey))
3360     {
3361         *phkResult = hKey;
3362         return ERROR_SUCCESS;
3363     }
3364 
3365     Status = MapDefaultKey(&KeyHandle, hKey);
3366     if (!NT_SUCCESS(Status))
3367     {
3368         return RtlNtStatusToDosError(Status);
3369     }
3370 
3371     if (IsHKCRKey(KeyHandle))
3372     {
3373         ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
3374         ClosePredefKey(KeyHandle);
3375         return ErrorCode;
3376     }
3377 
3378     if (ulOptions & REG_OPTION_OPEN_LINK)
3379         Attributes |= OBJ_OPENLINK;
3380 
3381     if (lpSubKey == NULL || wcscmp(lpSubKey, L"\\") == 0)
3382     {
3383         RtlInitUnicodeString(&SubKeyString, L"");
3384     }
3385     else
3386     {
3387         RtlInitUnicodeString(&SubKeyString, lpSubKey);
3388 
3389         /* Handle unaligned lpSubKey */
3390         if ((ULONG_PTR)lpSubKey & 1)
3391         {
3392             UNICODE_STRING AlignedString;
3393 
3394             Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
3395                                                &SubKeyString,
3396                                                &AlignedString);
3397             if (!NT_SUCCESS(Status))
3398             {
3399                 goto Exit;
3400             }
3401 
3402             SubKeyString = AlignedString;
3403             SubKeyStringAllocated = TRUE;
3404         }
3405     }
3406 
3407     InitializeObjectAttributes(&ObjectAttributes,
3408                                &SubKeyString,
3409                                Attributes,
3410                                KeyHandle,
3411                                NULL);
3412 
3413     Status = NtOpenKey((PHANDLE)phkResult,
3414                        samDesired,
3415                        &ObjectAttributes);
3416 
3417 Exit:
3418 
3419     if (SubKeyStringAllocated)
3420     {
3421         RtlFreeUnicodeString(&SubKeyString);
3422     }
3423 
3424     if (!NT_SUCCESS(Status))
3425     {
3426         ErrorCode = RtlNtStatusToDosError(Status);
3427     }
3428 
3429     ClosePredefKey(KeyHandle);
3430 
3431     return ErrorCode;
3432 }
3433 
3434 
3435 /************************************************************************
3436  *  RegOpenUserClassesRoot
3437  *
3438  * @implemented
3439  */
3440 LONG WINAPI
RegOpenUserClassesRoot(IN HANDLE hToken,IN DWORD dwOptions,IN REGSAM samDesired,OUT PHKEY phkResult)3441 RegOpenUserClassesRoot(IN HANDLE hToken,
3442                        IN DWORD dwOptions,
3443                        IN REGSAM samDesired,
3444                        OUT PHKEY phkResult)
3445 {
3446     const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3447     const WCHAR UserClassesKeySuffix[] = L"_Classes";
3448     PTOKEN_USER TokenUserData;
3449     ULONG RequiredLength;
3450     UNICODE_STRING UserSidString, UserClassesKeyRoot;
3451     OBJECT_ATTRIBUTES ObjectAttributes;
3452     NTSTATUS Status;
3453 
3454     /* check parameters */
3455     if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3456     {
3457         return ERROR_INVALID_PARAMETER;
3458     }
3459 
3460     /*
3461      * Get the user sid from the token
3462      */
3463 
3464 ReadTokenSid:
3465     /* determine how much memory we need */
3466     Status = NtQueryInformationToken(hToken,
3467                                      TokenUser,
3468                                      NULL,
3469                                      0,
3470                                      &RequiredLength);
3471     if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
3472     {
3473         /* NOTE - as opposed to all other registry functions windows does indeed
3474                   change the last error code in case the caller supplied a invalid
3475                   handle for example! */
3476         return RtlNtStatusToDosError(Status);
3477     }
3478     RegInitialize(); /* HACK until delay-loading is implemented */
3479     TokenUserData = RtlAllocateHeap(ProcessHeap,
3480                                     0,
3481                                     RequiredLength);
3482     if (TokenUserData == NULL)
3483     {
3484         return ERROR_NOT_ENOUGH_MEMORY;
3485     }
3486 
3487     /* attempt to read the information */
3488     Status = NtQueryInformationToken(hToken,
3489                                      TokenUser,
3490                                      TokenUserData,
3491                                      RequiredLength,
3492                                      &RequiredLength);
3493     if (!NT_SUCCESS(Status))
3494     {
3495         RtlFreeHeap(ProcessHeap,
3496                     0,
3497                     TokenUserData);
3498         if (Status == STATUS_BUFFER_TOO_SMALL)
3499         {
3500             /* the information appears to have changed?! try again */
3501             goto ReadTokenSid;
3502         }
3503 
3504         /* NOTE - as opposed to all other registry functions windows does indeed
3505                   change the last error code in case the caller supplied a invalid
3506                   handle for example! */
3507         return RtlNtStatusToDosError(Status);
3508     }
3509 
3510     /*
3511      * Build the absolute path for the user's registry in the form
3512      * "\Registry\User\<SID>_Classes"
3513      */
3514     Status = RtlConvertSidToUnicodeString(&UserSidString,
3515                                           TokenUserData->User.Sid,
3516                                           TRUE);
3517 
3518     /* we don't need the user data anymore, free it */
3519     RtlFreeHeap(ProcessHeap,
3520                 0,
3521                 TokenUserData);
3522 
3523     if (!NT_SUCCESS(Status))
3524     {
3525         return RtlNtStatusToDosError(Status);
3526     }
3527 
3528     /* allocate enough memory for the entire key string */
3529     UserClassesKeyRoot.Length = 0;
3530     UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3531                                        sizeof(UserClassesKeyPrefix) +
3532                                        sizeof(UserClassesKeySuffix);
3533     UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3534                                                 0,
3535                                                 UserClassesKeyRoot.MaximumLength);
3536     if (UserClassesKeyRoot.Buffer == NULL)
3537     {
3538         RtlFreeUnicodeString(&UserSidString);
3539         return RtlNtStatusToDosError(Status);
3540     }
3541 
3542     /* build the string */
3543     RtlAppendUnicodeToString(&UserClassesKeyRoot,
3544                              UserClassesKeyPrefix);
3545     RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3546                                    &UserSidString);
3547     RtlAppendUnicodeToString(&UserClassesKeyRoot,
3548                              UserClassesKeySuffix);
3549 
3550     TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3551 
3552     /*
3553      * Open the key
3554      */
3555     InitializeObjectAttributes(&ObjectAttributes,
3556                                &UserClassesKeyRoot,
3557                                OBJ_CASE_INSENSITIVE,
3558                                NULL,
3559                                NULL);
3560 
3561     Status = NtOpenKey((PHANDLE)phkResult,
3562                        samDesired,
3563                        &ObjectAttributes);
3564 
3565     RtlFreeUnicodeString(&UserSidString);
3566     RtlFreeUnicodeString(&UserClassesKeyRoot);
3567 
3568     if (!NT_SUCCESS(Status))
3569     {
3570         return RtlNtStatusToDosError(Status);
3571     }
3572 
3573     return ERROR_SUCCESS;
3574 }
3575 
3576 
3577 /************************************************************************
3578  *  RegQueryInfoKeyA
3579  *
3580  * @implemented
3581  */
3582 LONG WINAPI
RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcMaxSubKeyLen,LPDWORD lpcMaxClassLen,LPDWORD lpcValues,LPDWORD lpcMaxValueNameLen,LPDWORD lpcMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime)3583 RegQueryInfoKeyA(HKEY hKey,
3584                  LPSTR lpClass,
3585                  LPDWORD lpcClass,
3586                  LPDWORD lpReserved,
3587                  LPDWORD lpcSubKeys,
3588                  LPDWORD lpcMaxSubKeyLen,
3589                  LPDWORD lpcMaxClassLen,
3590                  LPDWORD lpcValues,
3591                  LPDWORD lpcMaxValueNameLen,
3592                  LPDWORD lpcMaxValueLen,
3593                  LPDWORD lpcbSecurityDescriptor,
3594                  PFILETIME lpftLastWriteTime)
3595 {
3596     WCHAR ClassName[MAX_PATH];
3597     UNICODE_STRING UnicodeString;
3598     ANSI_STRING AnsiString;
3599     LONG ErrorCode;
3600     NTSTATUS Status;
3601     DWORD cClass = 0;
3602 
3603     if ((lpClass) && (!lpcClass))
3604     {
3605         return ERROR_INVALID_PARAMETER;
3606     }
3607 
3608     RtlInitUnicodeString(&UnicodeString,
3609                          NULL);
3610     if (lpClass != NULL)
3611     {
3612         RtlInitEmptyUnicodeString(&UnicodeString,
3613                                   ClassName,
3614                                   sizeof(ClassName));
3615         cClass = sizeof(ClassName) / sizeof(WCHAR);
3616     }
3617 
3618     ErrorCode = RegQueryInfoKeyW(hKey,
3619                                  UnicodeString.Buffer,
3620                                  &cClass,
3621                                  lpReserved,
3622                                  lpcSubKeys,
3623                                  lpcMaxSubKeyLen,
3624                                  lpcMaxClassLen,
3625                                  lpcValues,
3626                                  lpcMaxValueNameLen,
3627                                  lpcMaxValueLen,
3628                                  lpcbSecurityDescriptor,
3629                                  lpftLastWriteTime);
3630     if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3631     {
3632         if (*lpcClass == 0)
3633         {
3634             return ErrorCode;
3635         }
3636 
3637         RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
3638         UnicodeString.Length = cClass * sizeof(WCHAR);
3639         Status = RtlUnicodeStringToAnsiString(&AnsiString,
3640                                               &UnicodeString,
3641                                               FALSE);
3642         ErrorCode = RtlNtStatusToDosError(Status);
3643         cClass = AnsiString.Length;
3644         lpClass[cClass] = ANSI_NULL;
3645     }
3646 
3647     if (lpcClass != NULL)
3648     {
3649         *lpcClass = cClass;
3650     }
3651 
3652     return ErrorCode;
3653 }
3654 
3655 
3656 /************************************************************************
3657  *  RegQueryInfoKeyW
3658  *
3659  * @implemented
3660  */
3661 LONG WINAPI
RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcMaxSubKeyLen,LPDWORD lpcMaxClassLen,LPDWORD lpcValues,LPDWORD lpcMaxValueNameLen,LPDWORD lpcMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime)3662 RegQueryInfoKeyW(HKEY hKey,
3663                  LPWSTR lpClass,
3664                  LPDWORD lpcClass,
3665                  LPDWORD lpReserved,
3666                  LPDWORD lpcSubKeys,
3667                  LPDWORD lpcMaxSubKeyLen,
3668                  LPDWORD lpcMaxClassLen,
3669                  LPDWORD lpcValues,
3670                  LPDWORD lpcMaxValueNameLen,
3671                  LPDWORD lpcMaxValueLen,
3672                  LPDWORD lpcbSecurityDescriptor,
3673                  PFILETIME lpftLastWriteTime)
3674 {
3675     KEY_FULL_INFORMATION FullInfoBuffer;
3676     PKEY_FULL_INFORMATION FullInfo;
3677     ULONG FullInfoSize;
3678     ULONG ClassLength = 0;
3679     HANDLE KeyHandle;
3680     NTSTATUS Status;
3681     ULONG Length;
3682     LONG ErrorCode = ERROR_SUCCESS;
3683 
3684     if ((lpClass) && (!lpcClass))
3685     {
3686         return ERROR_INVALID_PARAMETER;
3687     }
3688 
3689     Status = MapDefaultKey(&KeyHandle,
3690                            hKey);
3691     if (!NT_SUCCESS(Status))
3692     {
3693         return RtlNtStatusToDosError(Status);
3694     }
3695 
3696     if (IsHKCRKey(KeyHandle))
3697     {
3698         ErrorCode = QueryInfoHKCRKey(KeyHandle, lpClass, lpcClass, lpReserved,
3699                                      lpcSubKeys, lpcMaxSubKeyLen, lpcMaxClassLen,
3700                                      lpcValues, lpcMaxValueNameLen, lpcMaxValueLen,
3701                                      lpcbSecurityDescriptor, lpftLastWriteTime);
3702         ClosePredefKey(KeyHandle);
3703         return ErrorCode;
3704     }
3705 
3706     if (lpClass != NULL)
3707     {
3708         if (*lpcClass > 0)
3709         {
3710             ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3711         }
3712         else
3713         {
3714             ClassLength = 0;
3715         }
3716 
3717         FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3718         FullInfo = RtlAllocateHeap(ProcessHeap,
3719                                    0,
3720                                    FullInfoSize);
3721         if (FullInfo == NULL)
3722         {
3723             ErrorCode = ERROR_OUTOFMEMORY;
3724             goto Cleanup;
3725         }
3726     }
3727     else
3728     {
3729         FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3730         FullInfo = &FullInfoBuffer;
3731     }
3732 
3733     if (lpcbSecurityDescriptor != NULL)
3734         *lpcbSecurityDescriptor = 0;
3735 
3736     Status = NtQueryKey(KeyHandle,
3737                         KeyFullInformation,
3738                         FullInfo,
3739                         FullInfoSize,
3740                         &Length);
3741     TRACE("NtQueryKey() returned status 0x%X\n", Status);
3742     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
3743     {
3744         ErrorCode = RtlNtStatusToDosError(Status);
3745         goto Cleanup;
3746     }
3747 
3748     TRACE("SubKeys %d\n", FullInfo->SubKeys);
3749     if (lpcSubKeys != NULL)
3750     {
3751         *lpcSubKeys = FullInfo->SubKeys;
3752     }
3753 
3754     TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3755     if (lpcMaxSubKeyLen != NULL)
3756     {
3757         *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3758     }
3759 
3760     TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3761     if (lpcMaxClassLen != NULL)
3762     {
3763         *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3764     }
3765 
3766     TRACE("Values %lu\n", FullInfo->Values);
3767     if (lpcValues != NULL)
3768     {
3769         *lpcValues = FullInfo->Values;
3770     }
3771 
3772     TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3773     if (lpcMaxValueNameLen != NULL)
3774     {
3775         *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3776     }
3777 
3778     TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3779     if (lpcMaxValueLen != NULL)
3780     {
3781         *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3782     }
3783 
3784     if (lpcbSecurityDescriptor != NULL)
3785     {
3786         Status = NtQuerySecurityObject(KeyHandle,
3787                                        OWNER_SECURITY_INFORMATION |
3788                                        GROUP_SECURITY_INFORMATION |
3789                                        DACL_SECURITY_INFORMATION,
3790                                        NULL,
3791                                        0,
3792                                        lpcbSecurityDescriptor);
3793         TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
3794     }
3795 
3796     if (lpftLastWriteTime != NULL)
3797     {
3798         lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3799         lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3800     }
3801 
3802     if (lpClass != NULL)
3803     {
3804         if (*lpcClass == 0)
3805         {
3806             goto Cleanup;
3807         }
3808 
3809         if (FullInfo->ClassLength > ClassLength)
3810         {
3811             ErrorCode = ERROR_INSUFFICIENT_BUFFER;
3812         }
3813         else
3814         {
3815             RtlCopyMemory(lpClass,
3816                           FullInfo->Class,
3817                           FullInfo->ClassLength);
3818             lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3819         }
3820     }
3821 
3822     if (lpcClass != NULL)
3823     {
3824         *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3825     }
3826 
3827 Cleanup:
3828     if (lpClass != NULL)
3829     {
3830         RtlFreeHeap(ProcessHeap,
3831                     0,
3832                     FullInfo);
3833     }
3834 
3835     ClosePredefKey(KeyHandle);
3836 
3837     return ErrorCode;
3838 }
3839 
3840 
3841 /************************************************************************
3842  *  RegQueryMultipleValuesA
3843  *
3844  * @implemented
3845  */
3846 LONG WINAPI
RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize)3847 RegQueryMultipleValuesA(HKEY hKey,
3848                         PVALENTA val_list,
3849                         DWORD num_vals,
3850                         LPSTR lpValueBuf,
3851                         LPDWORD ldwTotsize)
3852 {
3853     ULONG i;
3854     DWORD maxBytes = *ldwTotsize;
3855     LPSTR bufptr = lpValueBuf;
3856     LONG ErrorCode;
3857 
3858     if (maxBytes >= (1024*1024))
3859         return ERROR_MORE_DATA;
3860 
3861     *ldwTotsize = 0;
3862 
3863     TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3864           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3865 
3866     for (i = 0; i < num_vals; i++)
3867     {
3868         val_list[i].ve_valuelen = 0;
3869         ErrorCode = RegQueryValueExA(hKey,
3870                                      val_list[i].ve_valuename,
3871                                      NULL,
3872                                      NULL,
3873                                      NULL,
3874                                      &val_list[i].ve_valuelen);
3875         if (ErrorCode != ERROR_SUCCESS)
3876         {
3877             return ErrorCode;
3878         }
3879 
3880         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3881         {
3882             ErrorCode = RegQueryValueExA(hKey,
3883                                          val_list[i].ve_valuename,
3884                                          NULL,
3885                                          &val_list[i].ve_type,
3886                                          (LPBYTE)bufptr,
3887                                          &val_list[i].ve_valuelen);
3888             if (ErrorCode != ERROR_SUCCESS)
3889             {
3890                 return ErrorCode;
3891             }
3892 
3893             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3894 
3895             bufptr += val_list[i].ve_valuelen;
3896         }
3897 
3898         *ldwTotsize += val_list[i].ve_valuelen;
3899     }
3900 
3901     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3902 }
3903 
3904 
3905 /************************************************************************
3906  *  RegQueryMultipleValuesW
3907  *
3908  * @implemented
3909  */
3910 LONG WINAPI
RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize)3911 RegQueryMultipleValuesW(HKEY hKey,
3912                         PVALENTW val_list,
3913                         DWORD num_vals,
3914                         LPWSTR lpValueBuf,
3915                         LPDWORD ldwTotsize)
3916 {
3917     ULONG i;
3918     DWORD maxBytes = *ldwTotsize;
3919     LPSTR bufptr = (LPSTR)lpValueBuf;
3920     LONG ErrorCode;
3921 
3922     if (maxBytes >= (1024*1024))
3923         return ERROR_MORE_DATA;
3924 
3925     *ldwTotsize = 0;
3926 
3927     TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3928           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3929 
3930     for (i = 0; i < num_vals; i++)
3931     {
3932         val_list[i].ve_valuelen = 0;
3933         ErrorCode = RegQueryValueExW(hKey,
3934                                      val_list[i].ve_valuename,
3935                                      NULL,
3936                                      NULL,
3937                                      NULL,
3938                                      &val_list[i].ve_valuelen);
3939         if (ErrorCode != ERROR_SUCCESS)
3940         {
3941             return ErrorCode;
3942          }
3943 
3944         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3945         {
3946             ErrorCode = RegQueryValueExW(hKey,
3947                                          val_list[i].ve_valuename,
3948                                          NULL,
3949                                          &val_list[i].ve_type,
3950                                          (LPBYTE)bufptr,
3951                                          &val_list[i].ve_valuelen);
3952             if (ErrorCode != ERROR_SUCCESS)
3953             {
3954                 return ErrorCode;
3955             }
3956 
3957             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3958 
3959             bufptr += val_list[i].ve_valuelen;
3960         }
3961 
3962         *ldwTotsize += val_list[i].ve_valuelen;
3963     }
3964 
3965     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3966 }
3967 
3968 
3969 /************************************************************************
3970  *  RegQueryReflectionKey
3971  *
3972  * @unimplemented
3973  */
3974 LONG WINAPI
RegQueryReflectionKey(IN HKEY hBase,OUT BOOL * bIsReflectionDisabled)3975 RegQueryReflectionKey(IN HKEY hBase,
3976                       OUT BOOL* bIsReflectionDisabled)
3977 {
3978     FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3979           hBase, bIsReflectionDisabled);
3980     return ERROR_CALL_NOT_IMPLEMENTED;
3981 }
3982 
3983 
3984 /******************************************************************************
3985  * RegQueryValueExA   [ADVAPI32.@]
3986  *
3987  * Get the type and contents of a specified value under with a key.
3988  *
3989  * PARAMS
3990  *  hkey      [I]   Handle of the key to query
3991  *  name      [I]   Name of value under hkey to query
3992  *  reserved  [I]   Reserved - must be NULL
3993  *  type      [O]   Destination for the value type, or NULL if not required
3994  *  data      [O]   Destination for the values contents, or NULL if not required
3995  *  count     [I/O] Size of data, updated with the number of bytes returned
3996  *
3997  * RETURNS
3998  *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
3999  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4000  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4001  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4002  *
4003  * NOTES
4004  *   MSDN states that if data is too small it is partially filled. In reality
4005  *   it remains untouched.
4006  */
4007 LONG
4008 WINAPI
RegQueryValueExA(_In_ HKEY hkeyorg,_In_ LPCSTR name,_In_ LPDWORD reserved,_Out_opt_ LPDWORD type,_Out_opt_ LPBYTE data,_Inout_opt_ LPDWORD count)4009 RegQueryValueExA(
4010     _In_ HKEY hkeyorg,
4011     _In_ LPCSTR name,
4012     _In_ LPDWORD reserved,
4013     _Out_opt_ LPDWORD type,
4014     _Out_opt_ LPBYTE data,
4015     _Inout_opt_ LPDWORD count)
4016 {
4017     UNICODE_STRING nameW;
4018     DWORD DataLength;
4019     DWORD ErrorCode;
4020     DWORD BufferSize = 0;
4021     WCHAR* Buffer;
4022     CHAR* DataStr = (CHAR*)data;
4023     DWORD LocalType;
4024 
4025     /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4026     if ((data && !count) || reserved)
4027         return ERROR_INVALID_PARAMETER;
4028 
4029     if (name)
4030     {
4031         if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
4032             return ERROR_NOT_ENOUGH_MEMORY;
4033     }
4034     else
4035         RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4036 
4037     ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4038     if (ErrorCode != ERROR_SUCCESS)
4039     {
4040         if ((!data) && count)
4041             *count = 0;
4042         RtlFreeUnicodeString(&nameW);
4043         return ErrorCode;
4044     }
4045 
4046     /* See if we can directly handle the call without caring for conversion */
4047     if (!is_string(LocalType) || !count)
4048     {
4049         ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4050         RtlFreeUnicodeString(&nameW);
4051         return ErrorCode;
4052     }
4053 
4054     /* Allocate a unicode string to get the data */
4055     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4056     if (!Buffer)
4057     {
4058         RtlFreeUnicodeString(&nameW);
4059         return ERROR_NOT_ENOUGH_MEMORY;
4060     }
4061 
4062     ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize);
4063     if (ErrorCode != ERROR_SUCCESS)
4064     {
4065         RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4066         RtlFreeUnicodeString(&nameW);
4067         return ErrorCode;
4068     }
4069 
4070     /* We don't need this anymore */
4071     RtlFreeUnicodeString(&nameW);
4072 
4073     /* Get the length for the multi-byte string (without the terminating NULL!) */
4074     DataLength = *count;
4075     RtlUnicodeToMultiByteSize(count, Buffer, BufferSize);
4076 
4077     if ((!data) || (DataLength < *count))
4078     {
4079         RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4080         return  data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4081     }
4082 
4083     /* We can finally do the conversion */
4084     RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize);
4085 
4086     /* NULL-terminate if there is enough room */
4087     if (DataLength > *count)
4088         DataStr[*count] = '\0';
4089 
4090     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4091 
4092     return ERROR_SUCCESS;
4093 }
4094 
4095 
4096 /************************************************************************
4097  *  RegQueryValueExW
4098  *
4099  * @implemented
4100  */
4101 LONG
4102 WINAPI
RegQueryValueExW(_In_ HKEY hkeyorg,_In_ LPCWSTR name,_In_ LPDWORD reserved,_In_ LPDWORD type,_In_ LPBYTE data,_In_ LPDWORD count)4103 RegQueryValueExW(
4104     _In_ HKEY hkeyorg,
4105     _In_ LPCWSTR name,
4106     _In_ LPDWORD reserved,
4107     _In_ LPDWORD type,
4108     _In_ LPBYTE data,
4109     _In_ LPDWORD count)
4110 {
4111     HANDLE hkey;
4112     NTSTATUS status;
4113     UNICODE_STRING name_str;
4114     DWORD total_size;
4115     char buffer[256], *buf_ptr = buffer;
4116     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4117     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4118 
4119     TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4120           hkeyorg, debugstr_w(name), reserved, type, data, count,
4121           (count && data) ? *count : 0 );
4122 
4123     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4124 
4125     status = MapDefaultKey(&hkey, hkeyorg);
4126     if (!NT_SUCCESS(status))
4127     {
4128         return RtlNtStatusToDosError(status);
4129     }
4130 
4131     if (IsHKCRKey(hkey))
4132     {
4133         LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count);
4134         ClosePredefKey(hkey);
4135         return ErrorCode;
4136     }
4137 
4138     RtlInitUnicodeString( &name_str, name );
4139 
4140     if (data)
4141         total_size = min( sizeof(buffer), *count + info_size );
4142     else
4143         total_size = info_size;
4144 
4145 
4146     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4147                               buffer, total_size, &total_size );
4148 
4149     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW)
4150     {
4151         // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4152         // On windows these conditions are likely to be side effects of the implementation...
4153         if (status == STATUS_INVALID_HANDLE && hkey)
4154         {
4155             if (type) *type = REG_NONE;
4156             if (count) *count = 0;
4157         }
4158         else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
4159         {
4160             if (type) *type = REG_NONE;
4161             if (data == NULL && count) *count = 0;
4162         }
4163         goto done;
4164     }
4165 
4166     if (data)
4167     {
4168         /* retry with a dynamically allocated buffer */
4169         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4170         {
4171             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4172             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4173             {
4174                 ClosePredefKey(hkey);
4175                 return ERROR_NOT_ENOUGH_MEMORY;
4176             }
4177             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4178             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4179                                       buf_ptr, total_size, &total_size );
4180         }
4181 
4182         if (NT_SUCCESS(status))
4183         {
4184             memcpy( data, buf_ptr + info_size, total_size - info_size );
4185             /* if the type is REG_SZ and data is not 0-terminated
4186              * and there is enough space in the buffer NT appends a \0 */
4187             if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4188             {
4189                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4190                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4191             }
4192         }
4193         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4194     }
4195     else status = STATUS_SUCCESS;
4196 
4197     if (type) *type = info->Type;
4198     if (count) *count = total_size - info_size;
4199 
4200  done:
4201     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4202     ClosePredefKey(hkey);
4203     return RtlNtStatusToDosError(status);
4204 }
4205 
4206 
4207 /************************************************************************
4208  *  RegQueryValueA
4209  *
4210  * @implemented
4211  */
RegQueryValueA(HKEY hkey,LPCSTR name,LPSTR data,LPLONG count)4212 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
4213 {
4214     DWORD ret;
4215     HKEY subkey = hkey;
4216 
4217     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4218 
4219     if (name && name[0])
4220     {
4221     if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4222     }
4223     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4224     if (subkey != hkey) RegCloseKey( subkey );
4225     if (ret == ERROR_FILE_NOT_FOUND)
4226     {
4227     /* return empty string if default value not found */
4228     if (data) *data = 0;
4229     if (count) *count = 1;
4230     ret = ERROR_SUCCESS;
4231     }
4232     return ret;
4233 }
4234 
4235 
4236 /************************************************************************
4237  *  RegQueryValueW
4238  *
4239  * @implemented
4240  */
RegQueryValueW(HKEY hkey,LPCWSTR name,LPWSTR data,LPLONG count)4241 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
4242 {
4243     DWORD ret;
4244     HKEY subkey = hkey;
4245 
4246     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4247     if (hkey == NULL)
4248     {
4249        return ERROR_INVALID_HANDLE;
4250     }
4251     if (name && name[0])
4252     {
4253         ret = RegOpenKeyW( hkey, name, &subkey);
4254         if (ret != ERROR_SUCCESS)
4255         {
4256             return ret;
4257         }
4258     }
4259 
4260     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4261 
4262     if (subkey != hkey)
4263     {
4264         RegCloseKey( subkey );
4265     }
4266 
4267     if (ret == ERROR_FILE_NOT_FOUND)
4268     {
4269         /* return empty string if default value not found */
4270         if (data)
4271             *data = 0;
4272         if (count)
4273             *count = sizeof(WCHAR);
4274         ret = ERROR_SUCCESS;
4275     }
4276     return ret;
4277 }
4278 
4279 
4280 /************************************************************************
4281  *  RegReplaceKeyA
4282  *
4283  * @implemented
4284  */
4285 LONG WINAPI
RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile)4286 RegReplaceKeyA(HKEY hKey,
4287                LPCSTR lpSubKey,
4288                LPCSTR lpNewFile,
4289                LPCSTR lpOldFile)
4290 {
4291     UNICODE_STRING SubKey;
4292     UNICODE_STRING NewFile;
4293     UNICODE_STRING OldFile;
4294     LONG ErrorCode;
4295 
4296     RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4297     RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4298     RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4299 
4300     if (lpSubKey)
4301     {
4302         if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4303         {
4304             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4305             goto Exit;
4306         }
4307     }
4308 
4309     if (lpOldFile)
4310     {
4311         if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4312         {
4313             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4314             goto Exit;
4315         }
4316     }
4317 
4318     if (lpNewFile)
4319     {
4320         if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4321         {
4322             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4323             goto Exit;
4324         }
4325     }
4326 
4327     ErrorCode = RegReplaceKeyW(hKey,
4328                                SubKey.Buffer,
4329                                NewFile.Buffer,
4330                                OldFile.Buffer);
4331 
4332 Exit:
4333     RtlFreeUnicodeString(&OldFile);
4334     RtlFreeUnicodeString(&NewFile);
4335     RtlFreeUnicodeString(&SubKey);
4336 
4337     return ErrorCode;
4338 }
4339 
4340 
4341 /************************************************************************
4342  *  RegReplaceKeyW
4343  *
4344  * @unimplemented
4345  */
4346 LONG WINAPI
RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile)4347 RegReplaceKeyW(HKEY hKey,
4348                LPCWSTR lpSubKey,
4349                LPCWSTR lpNewFile,
4350                LPCWSTR lpOldFile)
4351 {
4352     OBJECT_ATTRIBUTES KeyObjectAttributes;
4353     OBJECT_ATTRIBUTES NewObjectAttributes;
4354     OBJECT_ATTRIBUTES OldObjectAttributes;
4355     UNICODE_STRING SubKeyName;
4356     UNICODE_STRING NewFileName;
4357     UNICODE_STRING OldFileName;
4358     BOOLEAN CloseRealKey;
4359     HANDLE RealKeyHandle;
4360     HANDLE KeyHandle;
4361     NTSTATUS Status;
4362     LONG ErrorCode = ERROR_SUCCESS;
4363 
4364     if (hKey == HKEY_PERFORMANCE_DATA)
4365     {
4366         return ERROR_INVALID_HANDLE;
4367     }
4368 
4369     Status = MapDefaultKey(&KeyHandle,
4370                            hKey);
4371     if (!NT_SUCCESS(Status))
4372     {
4373         return RtlNtStatusToDosError(Status);
4374     }
4375 
4376     /* Open the real key */
4377     if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4378     {
4379         RtlInitUnicodeString(&SubKeyName, lpSubKey);
4380         InitializeObjectAttributes(&KeyObjectAttributes,
4381                                    &SubKeyName,
4382                                    OBJ_CASE_INSENSITIVE,
4383                                    KeyHandle,
4384                                    NULL);
4385         Status = NtOpenKey(&RealKeyHandle,
4386                            MAXIMUM_ALLOWED,
4387                            &KeyObjectAttributes);
4388         if (!NT_SUCCESS(Status))
4389         {
4390             ErrorCode = RtlNtStatusToDosError(Status);
4391             goto Cleanup;
4392         }
4393 
4394         CloseRealKey = TRUE;
4395     }
4396     else
4397     {
4398         RealKeyHandle = KeyHandle;
4399         CloseRealKey = FALSE;
4400     }
4401 
4402     /* Convert new file name */
4403     if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4404                                       &NewFileName,
4405                                       NULL,
4406                                       NULL))
4407     {
4408         if (CloseRealKey)
4409         {
4410             NtClose(RealKeyHandle);
4411         }
4412 
4413         ErrorCode = ERROR_INVALID_PARAMETER;
4414         goto Cleanup;
4415     }
4416 
4417     InitializeObjectAttributes(&NewObjectAttributes,
4418                                &NewFileName,
4419                                OBJ_CASE_INSENSITIVE,
4420                                NULL,
4421                                NULL);
4422 
4423     /* Convert old file name */
4424     if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4425                                       &OldFileName,
4426                                       NULL,
4427                                       NULL))
4428     {
4429         RtlFreeHeap(RtlGetProcessHeap (),
4430                     0,
4431                     NewFileName.Buffer);
4432         if (CloseRealKey)
4433         {
4434             NtClose(RealKeyHandle);
4435         }
4436 
4437         ErrorCode = ERROR_INVALID_PARAMETER;
4438         goto Cleanup;
4439     }
4440 
4441     InitializeObjectAttributes(&OldObjectAttributes,
4442                                &OldFileName,
4443                                OBJ_CASE_INSENSITIVE,
4444                                NULL,
4445                                NULL);
4446 
4447     Status = NtReplaceKey(&NewObjectAttributes,
4448                           RealKeyHandle,
4449                           &OldObjectAttributes);
4450 
4451     RtlFreeHeap(RtlGetProcessHeap(),
4452                 0,
4453                 OldFileName.Buffer);
4454     RtlFreeHeap(RtlGetProcessHeap(),
4455                 0,
4456                 NewFileName.Buffer);
4457 
4458     if (CloseRealKey)
4459     {
4460         NtClose(RealKeyHandle);
4461     }
4462 
4463     if (!NT_SUCCESS(Status))
4464     {
4465         return RtlNtStatusToDosError(Status);
4466     }
4467 
4468 Cleanup:
4469     ClosePredefKey(KeyHandle);
4470 
4471     return ErrorCode;
4472 }
4473 
4474 
4475 /************************************************************************
4476  *  RegRestoreKeyA
4477  *
4478  * @implemented
4479  */
4480 LONG WINAPI
RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags)4481 RegRestoreKeyA(HKEY hKey,
4482                LPCSTR lpFile,
4483                DWORD dwFlags)
4484 {
4485     UNICODE_STRING FileName;
4486     LONG ErrorCode;
4487 
4488     if (lpFile)
4489     {
4490         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4491             return ERROR_NOT_ENOUGH_MEMORY;
4492     }
4493     else
4494         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4495 
4496     ErrorCode = RegRestoreKeyW(hKey,
4497                                FileName.Buffer,
4498                                dwFlags);
4499 
4500     RtlFreeUnicodeString(&FileName);
4501 
4502     return ErrorCode;
4503 }
4504 
4505 
4506 /************************************************************************
4507  *  RegRestoreKeyW
4508  *
4509  * @implemented
4510  */
4511 LONG WINAPI
RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags)4512 RegRestoreKeyW(HKEY hKey,
4513                LPCWSTR lpFile,
4514                DWORD dwFlags)
4515 {
4516     OBJECT_ATTRIBUTES ObjectAttributes;
4517     IO_STATUS_BLOCK IoStatusBlock;
4518     UNICODE_STRING FileName;
4519     HANDLE FileHandle;
4520     HANDLE KeyHandle;
4521     NTSTATUS Status;
4522 
4523     if (hKey == HKEY_PERFORMANCE_DATA)
4524     {
4525         return ERROR_INVALID_HANDLE;
4526     }
4527 
4528     Status = MapDefaultKey(&KeyHandle,
4529                            hKey);
4530     if (!NT_SUCCESS(Status))
4531     {
4532         return RtlNtStatusToDosError(Status);
4533     }
4534 
4535     if (!RtlDosPathNameToNtPathName_U(lpFile,
4536                                       &FileName,
4537                                       NULL,
4538                                       NULL))
4539     {
4540         Status = STATUS_INVALID_PARAMETER;
4541         goto Cleanup;
4542     }
4543 
4544     InitializeObjectAttributes(&ObjectAttributes,
4545                                &FileName,
4546                                OBJ_CASE_INSENSITIVE,
4547                                NULL,
4548                                NULL);
4549 
4550     Status = NtOpenFile(&FileHandle,
4551                         FILE_GENERIC_READ,
4552                         &ObjectAttributes,
4553                         &IoStatusBlock,
4554                         FILE_SHARE_READ,
4555                         FILE_SYNCHRONOUS_IO_NONALERT);
4556     RtlFreeHeap(RtlGetProcessHeap(),
4557                 0,
4558                 FileName.Buffer);
4559     if (!NT_SUCCESS(Status))
4560     {
4561         goto Cleanup;
4562     }
4563 
4564     Status = NtRestoreKey(KeyHandle,
4565                           FileHandle,
4566                           (ULONG)dwFlags);
4567     NtClose (FileHandle);
4568 
4569 Cleanup:
4570     ClosePredefKey(KeyHandle);
4571 
4572     if (!NT_SUCCESS(Status))
4573     {
4574         return RtlNtStatusToDosError(Status);
4575     }
4576 
4577     return ERROR_SUCCESS;
4578 }
4579 
4580 
4581 /************************************************************************
4582  *  RegSaveKeyA
4583  *
4584  * @implemented
4585  */
4586 LONG WINAPI
RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes)4587 RegSaveKeyA(HKEY hKey,
4588             LPCSTR lpFile,
4589             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4590 {
4591     UNICODE_STRING FileName;
4592     LONG ErrorCode;
4593 
4594     if (lpFile)
4595     {
4596         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4597             return ERROR_NOT_ENOUGH_MEMORY;
4598     }
4599     else
4600         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4601 
4602     ErrorCode = RegSaveKeyW(hKey,
4603                             FileName.Buffer,
4604                             lpSecurityAttributes);
4605     RtlFreeUnicodeString(&FileName);
4606 
4607     return ErrorCode;
4608 }
4609 
4610 
4611 /************************************************************************
4612  *  RegSaveKeyW
4613  *
4614  * @implemented
4615  */
4616 LONG WINAPI
RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes)4617 RegSaveKeyW(HKEY hKey,
4618             LPCWSTR lpFile,
4619             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4620 {
4621     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4622     OBJECT_ATTRIBUTES ObjectAttributes;
4623     UNICODE_STRING FileName;
4624     IO_STATUS_BLOCK IoStatusBlock;
4625     HANDLE FileHandle;
4626     HANDLE KeyHandle;
4627     NTSTATUS Status;
4628 
4629     Status = MapDefaultKey(&KeyHandle,
4630                            hKey);
4631     if (!NT_SUCCESS(Status))
4632     {
4633         return RtlNtStatusToDosError(Status);
4634     }
4635 
4636     if (!RtlDosPathNameToNtPathName_U(lpFile,
4637                                       &FileName,
4638                                       NULL,
4639                                       NULL))
4640     {
4641         Status = STATUS_INVALID_PARAMETER;
4642         goto Cleanup;
4643     }
4644 
4645     if (lpSecurityAttributes != NULL)
4646     {
4647         SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4648     }
4649 
4650     InitializeObjectAttributes(&ObjectAttributes,
4651                                &FileName,
4652                                OBJ_CASE_INSENSITIVE,
4653                                NULL,
4654                                SecurityDescriptor);
4655     Status = NtCreateFile(&FileHandle,
4656                           GENERIC_WRITE | SYNCHRONIZE,
4657                           &ObjectAttributes,
4658                           &IoStatusBlock,
4659                           NULL,
4660                           FILE_ATTRIBUTE_NORMAL,
4661                           FILE_SHARE_READ,
4662                           FILE_CREATE,
4663                           FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4664                           NULL,
4665                           0);
4666     RtlFreeHeap(RtlGetProcessHeap(),
4667                 0,
4668                 FileName.Buffer);
4669     if (!NT_SUCCESS(Status))
4670     {
4671         goto Cleanup;
4672     }
4673 
4674     Status = NtSaveKey(KeyHandle,
4675                        FileHandle);
4676     NtClose (FileHandle);
4677 
4678 Cleanup:
4679     ClosePredefKey(KeyHandle);
4680 
4681     if (!NT_SUCCESS(Status))
4682     {
4683         return RtlNtStatusToDosError(Status);
4684     }
4685 
4686     return ERROR_SUCCESS;
4687 }
4688 
4689 
4690 /************************************************************************
4691  *  RegSaveKeyExA
4692  *
4693  * @implemented
4694  */
4695 LONG
4696 WINAPI
RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags)4697 RegSaveKeyExA(HKEY hKey,
4698               LPCSTR lpFile,
4699               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4700               DWORD Flags)
4701 {
4702     UNICODE_STRING FileName;
4703     LONG ErrorCode;
4704 
4705     if (lpFile)
4706     {
4707         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4708             return ERROR_NOT_ENOUGH_MEMORY;
4709     }
4710     else
4711         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4712 
4713     ErrorCode = RegSaveKeyExW(hKey,
4714                               FileName.Buffer,
4715                               lpSecurityAttributes,
4716                               Flags);
4717     RtlFreeUnicodeString(&FileName);
4718 
4719     return ErrorCode;
4720 }
4721 
4722 
4723 /************************************************************************
4724  *  RegSaveKeyExW
4725  *
4726  * @unimplemented
4727  */
4728 LONG
4729 WINAPI
RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags)4730 RegSaveKeyExW(HKEY hKey,
4731               LPCWSTR lpFile,
4732               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4733               DWORD Flags)
4734 {
4735     switch (Flags)
4736     {
4737         case REG_STANDARD_FORMAT:
4738         case REG_LATEST_FORMAT:
4739         case REG_NO_COMPRESSION:
4740             break;
4741         default:
4742             return ERROR_INVALID_PARAMETER;
4743     }
4744 
4745     FIXME("RegSaveKeyExW(): Flags ignored!\n");
4746 
4747     return RegSaveKeyW(hKey,
4748                        lpFile,
4749                        lpSecurityAttributes);
4750 }
4751 
4752 
4753 /************************************************************************
4754  *  RegSetKeySecurity
4755  *
4756  * @implemented
4757  */
4758 LONG WINAPI
RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor)4759 RegSetKeySecurity(HKEY hKey,
4760                   SECURITY_INFORMATION SecurityInformation,
4761                   PSECURITY_DESCRIPTOR pSecurityDescriptor)
4762 {
4763     HANDLE KeyHandle;
4764     NTSTATUS Status;
4765 
4766     if (hKey == HKEY_PERFORMANCE_DATA)
4767     {
4768         return ERROR_INVALID_HANDLE;
4769     }
4770 
4771     Status = MapDefaultKey(&KeyHandle,
4772                            hKey);
4773     if (!NT_SUCCESS(Status))
4774     {
4775         return RtlNtStatusToDosError(Status);
4776     }
4777 
4778     Status = NtSetSecurityObject(KeyHandle,
4779                                  SecurityInformation,
4780                                  pSecurityDescriptor);
4781 
4782     ClosePredefKey(KeyHandle);
4783 
4784     if (!NT_SUCCESS(Status))
4785     {
4786         return RtlNtStatusToDosError(Status);
4787     }
4788 
4789     return ERROR_SUCCESS;
4790 }
4791 
4792 
4793 /************************************************************************
4794  *  RegSetValueExA
4795  *
4796  * @implemented
4797  */
4798 LONG WINAPI
RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE * lpData,DWORD cbData)4799 RegSetValueExA(HKEY hKey,
4800                LPCSTR lpValueName,
4801                DWORD Reserved,
4802                DWORD dwType,
4803                CONST BYTE* lpData,
4804                DWORD cbData)
4805 {
4806     UNICODE_STRING ValueName;
4807     LPWSTR pValueName;
4808     ANSI_STRING AnsiString;
4809     UNICODE_STRING Data;
4810     LONG ErrorCode;
4811     LPBYTE pData;
4812     DWORD DataSize;
4813     NTSTATUS Status;
4814 
4815     /* Convert SubKey name to Unicode */
4816     if (lpValueName != NULL && lpValueName[0] != '\0')
4817     {
4818         if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
4819             return ERROR_NOT_ENOUGH_MEMORY;
4820     }
4821     else
4822     {
4823         ValueName.Buffer = NULL;
4824     }
4825 
4826     pValueName = (LPWSTR)ValueName.Buffer;
4827 
4828 
4829     if (is_string(dwType) && (cbData != 0))
4830     {
4831         /* Convert ANSI string Data to Unicode */
4832         /* If last character NOT zero then increment length */
4833         LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4834         AnsiString.Buffer = (PSTR)lpData;
4835         AnsiString.Length = cbData + bNoNulledStr;
4836         AnsiString.MaximumLength = cbData + bNoNulledStr;
4837         Status = RtlAnsiStringToUnicodeString(&Data,
4838                                      &AnsiString,
4839                                      TRUE);
4840 
4841         if (!NT_SUCCESS(Status))
4842         {
4843             if (pValueName != NULL)
4844                 RtlFreeUnicodeString(&ValueName);
4845 
4846             return RtlNtStatusToDosError(Status);
4847         }
4848         pData = (LPBYTE)Data.Buffer;
4849         DataSize = cbData * sizeof(WCHAR);
4850     }
4851     else
4852     {
4853         Data.Buffer = NULL;
4854         pData = (LPBYTE)lpData;
4855         DataSize = cbData;
4856     }
4857 
4858     ErrorCode = RegSetValueExW(hKey,
4859                                pValueName,
4860                                Reserved,
4861                                dwType,
4862                                pData,
4863                                DataSize);
4864 
4865     if (pValueName != NULL)
4866         RtlFreeUnicodeString(&ValueName);
4867 
4868     if (Data.Buffer != NULL)
4869         RtlFreeUnicodeString(&Data);
4870 
4871     return ErrorCode;
4872 }
4873 
4874 
4875 /************************************************************************
4876  *  RegSetValueExW
4877  *
4878  * @implemented
4879  */
4880 LONG
4881 WINAPI
RegSetValueExW(_In_ HKEY hKey,_In_ LPCWSTR lpValueName,_In_ DWORD Reserved,_In_ DWORD dwType,_In_ CONST BYTE * lpData,_In_ DWORD cbData)4882 RegSetValueExW(
4883     _In_ HKEY hKey,
4884     _In_ LPCWSTR lpValueName,
4885     _In_ DWORD Reserved,
4886     _In_ DWORD dwType,
4887     _In_ CONST BYTE* lpData,
4888     _In_ DWORD cbData)
4889 {
4890     UNICODE_STRING ValueName;
4891     HANDLE KeyHandle;
4892     NTSTATUS Status;
4893 
4894     Status = MapDefaultKey(&KeyHandle,
4895                            hKey);
4896     if (!NT_SUCCESS(Status))
4897     {
4898         return RtlNtStatusToDosError(Status);
4899     }
4900 
4901     if (IsHKCRKey(KeyHandle))
4902     {
4903         LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4904         ClosePredefKey(KeyHandle);
4905         return ErrorCode;
4906     }
4907 
4908     if (is_string(dwType) && (cbData != 0))
4909     {
4910         PWSTR pwsData = (PWSTR)lpData;
4911 
4912         _SEH2_TRY
4913         {
4914             if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4915                 (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4916             {
4917                 /* Increment length if last character is not zero and next is zero */
4918                 cbData += sizeof(WCHAR);
4919             }
4920         }
4921         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4922         {
4923             /* Do not fail if we fault where we were told not to go */
4924         }
4925         _SEH2_END;
4926     }
4927 
4928     RtlInitUnicodeString(&ValueName, lpValueName);
4929 
4930     Status = NtSetValueKey(KeyHandle,
4931                            &ValueName,
4932                            0,
4933                            dwType,
4934                            (PVOID)lpData,
4935                            (ULONG)cbData);
4936 
4937     ClosePredefKey(KeyHandle);
4938 
4939     if (!NT_SUCCESS(Status))
4940     {
4941         return RtlNtStatusToDosError(Status);
4942     }
4943 
4944     return ERROR_SUCCESS;
4945 }
4946 
4947 
4948 /************************************************************************
4949  *  RegSetValueA
4950  *
4951  * @implemented
4952  */
4953 LONG WINAPI
RegSetValueA(HKEY hKeyOriginal,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData)4954 RegSetValueA(HKEY hKeyOriginal,
4955              LPCSTR lpSubKey,
4956              DWORD dwType,
4957              LPCSTR lpData,
4958              DWORD cbData)
4959 {
4960     HKEY subkey;
4961     HANDLE hKey;
4962     DWORD ret;
4963     NTSTATUS Status;
4964 
4965     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4966 
4967     if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4968 
4969     Status = MapDefaultKey(&hKey, hKeyOriginal);
4970     if (!NT_SUCCESS(Status))
4971     {
4972         return RtlNtStatusToDosError (Status);
4973     }
4974     subkey = hKey;
4975 
4976     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
4977     {
4978         ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4979         if (ret != ERROR_SUCCESS)
4980             goto Cleanup;
4981     }
4982 
4983     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
4984     if (subkey != hKey)
4985         RegCloseKey(subkey);
4986 
4987 Cleanup:
4988     ClosePredefKey(hKey);
4989 
4990     return ret;
4991 }
4992 
4993 
4994 /************************************************************************
4995  *  RegSetValueW
4996  *
4997  * @implemented
4998  */
4999 LONG WINAPI
RegSetValueW(HKEY hKeyOriginal,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData)5000 RegSetValueW(HKEY hKeyOriginal,
5001              LPCWSTR lpSubKey,
5002              DWORD dwType,
5003              LPCWSTR lpData,
5004              DWORD cbData)
5005 {
5006     HKEY subkey;
5007     HANDLE hKey;
5008     DWORD ret;
5009     NTSTATUS Status;
5010 
5011     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5012 
5013     if (dwType != REG_SZ || !lpData)
5014         return ERROR_INVALID_PARAMETER;
5015 
5016     Status = MapDefaultKey(&hKey,
5017                            hKeyOriginal);
5018     if (!NT_SUCCESS(Status))
5019     {
5020         return RtlNtStatusToDosError(Status);
5021     }
5022     subkey = hKey;
5023 
5024     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
5025     {
5026         ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5027         if (ret != ERROR_SUCCESS)
5028             goto Cleanup;
5029     }
5030 
5031     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5032                           (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5033     if (subkey != hKey)
5034         RegCloseKey(subkey);
5035 
5036 Cleanup:
5037     ClosePredefKey(hKey);
5038 
5039     return ret;
5040 }
5041 
5042 
5043 /************************************************************************
5044  *  RegUnLoadKeyA
5045  *
5046  * @implemented
5047  */
5048 LONG WINAPI
RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey)5049 RegUnLoadKeyA(HKEY hKey,
5050               LPCSTR lpSubKey)
5051 {
5052     UNICODE_STRING KeyName;
5053     DWORD ErrorCode;
5054 
5055     if (lpSubKey)
5056     {
5057         if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5058             return ERROR_NOT_ENOUGH_MEMORY;
5059     }
5060     else
5061         RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5062 
5063     ErrorCode = RegUnLoadKeyW(hKey,
5064                               KeyName.Buffer);
5065 
5066     RtlFreeUnicodeString (&KeyName);
5067 
5068     return ErrorCode;
5069 }
5070 
5071 
5072 /************************************************************************
5073  *  RegUnLoadKeyW
5074  *
5075  * @implemented
5076  */
5077 LONG WINAPI
RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey)5078 RegUnLoadKeyW(HKEY hKey,
5079               LPCWSTR lpSubKey)
5080 {
5081     OBJECT_ATTRIBUTES ObjectAttributes;
5082     UNICODE_STRING KeyName;
5083     HANDLE KeyHandle;
5084     NTSTATUS Status;
5085 
5086     if (hKey == HKEY_PERFORMANCE_DATA)
5087     {
5088       return ERROR_INVALID_HANDLE;
5089     }
5090 
5091     Status = MapDefaultKey(&KeyHandle, hKey);
5092     if (!NT_SUCCESS(Status))
5093     {
5094         return RtlNtStatusToDosError(Status);
5095     }
5096 
5097     RtlInitUnicodeString(&KeyName, lpSubKey);
5098 
5099     InitializeObjectAttributes(&ObjectAttributes,
5100                                &KeyName,
5101                                OBJ_CASE_INSENSITIVE,
5102                                KeyHandle,
5103                                NULL);
5104 
5105     Status = NtUnloadKey(&ObjectAttributes);
5106 
5107     ClosePredefKey(KeyHandle);
5108 
5109     if (!NT_SUCCESS(Status))
5110     {
5111         return RtlNtStatusToDosError(Status);
5112     }
5113 
5114     return ERROR_SUCCESS;
5115 }
5116 
5117 #endif // _ADVAPI32_VISTA_
5118 
5119 /******************************************************************************
5120  * load_string [Internal]
5121  *
5122  * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5123  * avoid importing user32, which is higher level than advapi32. Helper for
5124  * RegLoadMUIString.
5125  */
load_string(HINSTANCE hModule,UINT resId,LPWSTR pwszBuffer,INT cMaxChars)5126 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
5127 {
5128     HGLOBAL hMemory;
5129     HRSRC hResource;
5130     WCHAR* pString;
5131     int idxString;
5132 
5133     /* Negative values have to be inverted. */
5134     if (HIWORD(resId) == 0xffff)
5135         resId = (UINT)(-((INT)resId));
5136 
5137     /* Load the resource into memory and get a pointer to it. */
5138     hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
5139     if (!hResource) return 0;
5140     hMemory = LoadResource(hModule, hResource);
5141     if (!hMemory) return 0;
5142     pString = LockResource(hMemory);
5143 
5144     /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5145     idxString = resId & 0xf;
5146     while (idxString--) pString += *pString + 1;
5147 
5148     /* If no buffer is given, return length of the string. */
5149     if (!pwszBuffer) return *pString;
5150 
5151     /* Else copy over the string, respecting the buffer size. */
5152     cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
5153     if (cMaxChars >= 0)
5154     {
5155         memcpy(pwszBuffer, pString + 1, cMaxChars * sizeof(WCHAR));
5156         pwszBuffer[cMaxChars] = L'\0';
5157     }
5158 
5159     return cMaxChars;
5160 }
5161 
5162 /************************************************************************
5163  *  RegLoadMUIStringW
5164  *
5165  * @implemented
5166  */
5167 LONG WINAPI
RegLoadMUIStringW(IN HKEY hKey,IN LPCWSTR pszValue OPTIONAL,OUT LPWSTR pszOutBuf,IN DWORD cbOutBuf,OUT LPDWORD pcbData OPTIONAL,IN DWORD Flags,IN LPCWSTR pszDirectory OPTIONAL)5168 RegLoadMUIStringW(
5169     IN HKEY hKey,
5170     IN LPCWSTR pszValue  OPTIONAL,
5171     OUT LPWSTR pszOutBuf,
5172     IN DWORD cbOutBuf,
5173     OUT LPDWORD pcbData OPTIONAL,
5174     IN DWORD Flags,
5175     IN LPCWSTR pszDirectory  OPTIONAL)
5176 {
5177     DWORD dwValueType, cbData;
5178     LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
5179     LONG result;
5180 
5181     /* Parameter sanity checks. */
5182     if (!hKey || !pszOutBuf)
5183         return ERROR_INVALID_PARAMETER;
5184 
5185     if (pszDirectory && *pszDirectory)
5186     {
5187         FIXME("BaseDir parameter not yet supported!\n");
5188         return ERROR_INVALID_PARAMETER;
5189     }
5190 
5191     /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5192     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
5193     if (result != ERROR_SUCCESS) goto cleanup;
5194     if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
5195     {
5196         result = ERROR_FILE_NOT_FOUND;
5197         goto cleanup;
5198     }
5199     pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5200     if (!pwszTempBuffer)
5201     {
5202         result = ERROR_NOT_ENOUGH_MEMORY;
5203         goto cleanup;
5204     }
5205     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
5206     if (result != ERROR_SUCCESS) goto cleanup;
5207 
5208     /* Expand environment variables, if appropriate, or copy the original string over. */
5209     if (dwValueType == REG_EXPAND_SZ)
5210     {
5211         cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
5212         if (!cbData) goto cleanup;
5213         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5214         if (!pwszExpandedBuffer)
5215         {
5216             result = ERROR_NOT_ENOUGH_MEMORY;
5217             goto cleanup;
5218         }
5219         ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
5220     }
5221     else
5222     {
5223         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5224         memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
5225     }
5226 
5227     /* If the value references a resource based string, parse the value and load the string.
5228      * Else just copy over the original value. */
5229     result = ERROR_SUCCESS;
5230     if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
5231     {
5232         lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
5233     }
5234     else
5235     {
5236         WCHAR* pComma = wcsrchr(pwszExpandedBuffer, L',');
5237         UINT uiStringId;
5238         HMODULE hModule;
5239 
5240         /* Format of the expanded value is 'path_to_dll,-resId' */
5241         if (!pComma || pComma[1] != L'-')
5242         {
5243             result = ERROR_BADKEY;
5244             goto cleanup;
5245         }
5246 
5247         uiStringId = _wtoi(pComma + 2);
5248         *pComma = L'\0';
5249 
5250         hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
5251         if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
5252             result = ERROR_BADKEY;
5253         FreeLibrary(hModule);
5254     }
5255 
5256 cleanup:
5257     HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
5258     HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
5259     return result;
5260 }
5261 
5262 /************************************************************************
5263  *  RegLoadMUIStringA
5264  *
5265  * @implemented
5266  */
5267 LONG WINAPI
RegLoadMUIStringA(IN HKEY hKey,IN LPCSTR pszValue OPTIONAL,OUT LPSTR pszOutBuf,IN DWORD cbOutBuf,OUT LPDWORD pcbData OPTIONAL,IN DWORD Flags,IN LPCSTR pszDirectory OPTIONAL)5268 RegLoadMUIStringA(
5269     IN HKEY hKey,
5270     IN LPCSTR pszValue  OPTIONAL,
5271     OUT LPSTR pszOutBuf,
5272     IN DWORD cbOutBuf,
5273     OUT LPDWORD pcbData OPTIONAL,
5274     IN DWORD Flags,
5275     IN LPCSTR pszDirectory  OPTIONAL)
5276 {
5277     UNICODE_STRING valueW, baseDirW;
5278     WCHAR* pwszBuffer;
5279     DWORD cbData = cbOutBuf * sizeof(WCHAR);
5280     LONG result;
5281 
5282     valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
5283     if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
5284         !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
5285         !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
5286     {
5287         result = ERROR_NOT_ENOUGH_MEMORY;
5288         goto cleanup;
5289     }
5290 
5291     result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
5292         baseDirW.Buffer);
5293 
5294     if (result == ERROR_SUCCESS)
5295     {
5296         cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
5297         if (pcbData)
5298             *pcbData = cbData;
5299     }
5300 
5301 cleanup:
5302     HeapFree(GetProcessHeap(), 0, pwszBuffer);
5303     RtlFreeUnicodeString(&baseDirW);
5304     RtlFreeUnicodeString(&valueW);
5305 
5306     return result;
5307 }
5308 
5309 /* EOF */
5310