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