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