xref: /reactos/dll/win32/advapi32/reg/reg.c (revision 6a6b5ec2)
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 (IsHKCRKey(KeyHandle))
3722     {
3723         ErrorCode = QueryInfoHKCRKey(KeyHandle, lpClass, lpcClass, lpReserved,
3724                                      lpcSubKeys, lpcMaxSubKeyLen, lpcMaxClassLen,
3725                                      lpcValues, lpcMaxValueNameLen, lpcMaxValueLen,
3726                                      lpcbSecurityDescriptor, lpftLastWriteTime);
3727         ClosePredefKey(KeyHandle);
3728         return ErrorCode;
3729     }
3730 
3731     if (lpClass != NULL)
3732     {
3733         if (*lpcClass > 0)
3734         {
3735             ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3736         }
3737         else
3738         {
3739             ClassLength = 0;
3740         }
3741 
3742         FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3743         FullInfo = RtlAllocateHeap(ProcessHeap,
3744                                    0,
3745                                    FullInfoSize);
3746         if (FullInfo == NULL)
3747         {
3748             ErrorCode = ERROR_OUTOFMEMORY;
3749             goto Cleanup;
3750         }
3751     }
3752     else
3753     {
3754         FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3755         FullInfo = &FullInfoBuffer;
3756     }
3757 
3758     if (lpcbSecurityDescriptor != NULL)
3759         *lpcbSecurityDescriptor = 0;
3760 
3761     Status = NtQueryKey(KeyHandle,
3762                         KeyFullInformation,
3763                         FullInfo,
3764                         FullInfoSize,
3765                         &Length);
3766     TRACE("NtQueryKey() returned status 0x%X\n", Status);
3767     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
3768     {
3769         ErrorCode = RtlNtStatusToDosError(Status);
3770         goto Cleanup;
3771     }
3772 
3773     TRACE("SubKeys %d\n", FullInfo->SubKeys);
3774     if (lpcSubKeys != NULL)
3775     {
3776         *lpcSubKeys = FullInfo->SubKeys;
3777     }
3778 
3779     TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3780     if (lpcMaxSubKeyLen != NULL)
3781     {
3782         *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3783     }
3784 
3785     TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3786     if (lpcMaxClassLen != NULL)
3787     {
3788         *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3789     }
3790 
3791     TRACE("Values %lu\n", FullInfo->Values);
3792     if (lpcValues != NULL)
3793     {
3794         *lpcValues = FullInfo->Values;
3795     }
3796 
3797     TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3798     if (lpcMaxValueNameLen != NULL)
3799     {
3800         *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3801     }
3802 
3803     TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3804     if (lpcMaxValueLen != NULL)
3805     {
3806         *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3807     }
3808 
3809     if (lpcbSecurityDescriptor != NULL)
3810     {
3811         Status = NtQuerySecurityObject(KeyHandle,
3812                                        OWNER_SECURITY_INFORMATION |
3813                                        GROUP_SECURITY_INFORMATION |
3814                                        DACL_SECURITY_INFORMATION,
3815                                        NULL,
3816                                        0,
3817                                        lpcbSecurityDescriptor);
3818         TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
3819     }
3820 
3821     if (lpftLastWriteTime != NULL)
3822     {
3823         lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3824         lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3825     }
3826 
3827     if (lpClass != NULL)
3828     {
3829         if (*lpcClass == 0)
3830         {
3831             goto Cleanup;
3832         }
3833 
3834         if (FullInfo->ClassLength > ClassLength)
3835         {
3836             ErrorCode = ERROR_INSUFFICIENT_BUFFER;
3837         }
3838         else
3839         {
3840             RtlCopyMemory(lpClass,
3841                           FullInfo->Class,
3842                           FullInfo->ClassLength);
3843             lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3844         }
3845     }
3846 
3847     if (lpcClass != NULL)
3848     {
3849         *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3850     }
3851 
3852 Cleanup:
3853     if (lpClass != NULL)
3854     {
3855         RtlFreeHeap(ProcessHeap,
3856                     0,
3857                     FullInfo);
3858     }
3859 
3860     ClosePredefKey(KeyHandle);
3861 
3862     return ErrorCode;
3863 }
3864 
3865 
3866 /************************************************************************
3867  *  RegQueryMultipleValuesA
3868  *
3869  * @implemented
3870  */
3871 LONG WINAPI
3872 RegQueryMultipleValuesA(HKEY hKey,
3873                         PVALENTA val_list,
3874                         DWORD num_vals,
3875                         LPSTR lpValueBuf,
3876                         LPDWORD ldwTotsize)
3877 {
3878     ULONG i;
3879     DWORD maxBytes = *ldwTotsize;
3880     LPSTR bufptr = lpValueBuf;
3881     LONG ErrorCode;
3882 
3883     if (maxBytes >= (1024*1024))
3884         return ERROR_MORE_DATA;
3885 
3886     *ldwTotsize = 0;
3887 
3888     TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3889           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3890 
3891     for (i = 0; i < num_vals; i++)
3892     {
3893         val_list[i].ve_valuelen = 0;
3894         ErrorCode = RegQueryValueExA(hKey,
3895                                      val_list[i].ve_valuename,
3896                                      NULL,
3897                                      NULL,
3898                                      NULL,
3899                                      &val_list[i].ve_valuelen);
3900         if (ErrorCode != ERROR_SUCCESS)
3901         {
3902             return ErrorCode;
3903         }
3904 
3905         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3906         {
3907             ErrorCode = RegQueryValueExA(hKey,
3908                                          val_list[i].ve_valuename,
3909                                          NULL,
3910                                          &val_list[i].ve_type,
3911                                          (LPBYTE)bufptr,
3912                                          &val_list[i].ve_valuelen);
3913             if (ErrorCode != ERROR_SUCCESS)
3914             {
3915                 return ErrorCode;
3916             }
3917 
3918             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3919 
3920             bufptr += val_list[i].ve_valuelen;
3921         }
3922 
3923         *ldwTotsize += val_list[i].ve_valuelen;
3924     }
3925 
3926     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3927 }
3928 
3929 
3930 /************************************************************************
3931  *  RegQueryMultipleValuesW
3932  *
3933  * @implemented
3934  */
3935 LONG WINAPI
3936 RegQueryMultipleValuesW(HKEY hKey,
3937                         PVALENTW val_list,
3938                         DWORD num_vals,
3939                         LPWSTR lpValueBuf,
3940                         LPDWORD ldwTotsize)
3941 {
3942     ULONG i;
3943     DWORD maxBytes = *ldwTotsize;
3944     LPSTR bufptr = (LPSTR)lpValueBuf;
3945     LONG ErrorCode;
3946 
3947     if (maxBytes >= (1024*1024))
3948         return ERROR_MORE_DATA;
3949 
3950     *ldwTotsize = 0;
3951 
3952     TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3953           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3954 
3955     for (i = 0; i < num_vals; i++)
3956     {
3957         val_list[i].ve_valuelen = 0;
3958         ErrorCode = RegQueryValueExW(hKey,
3959                                      val_list[i].ve_valuename,
3960                                      NULL,
3961                                      NULL,
3962                                      NULL,
3963                                      &val_list[i].ve_valuelen);
3964         if (ErrorCode != ERROR_SUCCESS)
3965         {
3966             return ErrorCode;
3967          }
3968 
3969         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3970         {
3971             ErrorCode = RegQueryValueExW(hKey,
3972                                          val_list[i].ve_valuename,
3973                                          NULL,
3974                                          &val_list[i].ve_type,
3975                                          (LPBYTE)bufptr,
3976                                          &val_list[i].ve_valuelen);
3977             if (ErrorCode != ERROR_SUCCESS)
3978             {
3979                 return ErrorCode;
3980             }
3981 
3982             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3983 
3984             bufptr += val_list[i].ve_valuelen;
3985         }
3986 
3987         *ldwTotsize += val_list[i].ve_valuelen;
3988     }
3989 
3990     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3991 }
3992 
3993 
3994 /************************************************************************
3995  *  RegQueryReflectionKey
3996  *
3997  * @unimplemented
3998  */
3999 LONG WINAPI
4000 RegQueryReflectionKey(IN HKEY hBase,
4001                       OUT BOOL* bIsReflectionDisabled)
4002 {
4003     FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4004           hBase, bIsReflectionDisabled);
4005     return ERROR_CALL_NOT_IMPLEMENTED;
4006 }
4007 
4008 
4009 /******************************************************************************
4010  * RegQueryValueExA   [ADVAPI32.@]
4011  *
4012  * Get the type and contents of a specified value under with a key.
4013  *
4014  * PARAMS
4015  *  hkey      [I]   Handle of the key to query
4016  *  name      [I]   Name of value under hkey to query
4017  *  reserved  [I]   Reserved - must be NULL
4018  *  type      [O]   Destination for the value type, or NULL if not required
4019  *  data      [O]   Destination for the values contents, or NULL if not required
4020  *  count     [I/O] Size of data, updated with the number of bytes returned
4021  *
4022  * RETURNS
4023  *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4024  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4025  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4026  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4027  *
4028  * NOTES
4029  *   MSDN states that if data is too small it is partially filled. In reality
4030  *   it remains untouched.
4031  */
4032 LONG
4033 WINAPI
4034 RegQueryValueExA(
4035     _In_ HKEY hkeyorg,
4036     _In_ LPCSTR name,
4037     _In_ LPDWORD reserved,
4038     _Out_opt_ LPDWORD type,
4039     _Out_opt_ LPBYTE data,
4040     _Inout_opt_ LPDWORD count)
4041 {
4042     UNICODE_STRING nameW;
4043     DWORD DataLength;
4044     DWORD ErrorCode;
4045     DWORD BufferSize = 0;
4046     WCHAR* Buffer;
4047     CHAR* DataStr = (CHAR*)data;
4048     DWORD LocalType;
4049 
4050     /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4051     if ((data && !count) || reserved)
4052         return ERROR_INVALID_PARAMETER;
4053 
4054     if (name)
4055     {
4056         if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
4057             return ERROR_NOT_ENOUGH_MEMORY;
4058     }
4059     else
4060         RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4061 
4062     ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4063     if (ErrorCode != ERROR_SUCCESS)
4064     {
4065         if ((!data) && count)
4066             *count = 0;
4067         RtlFreeUnicodeString(&nameW);
4068         return ErrorCode;
4069     }
4070 
4071     /* See if we can directly handle the call without caring for conversion */
4072     if (!is_string(LocalType) || !count)
4073     {
4074         ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4075         RtlFreeUnicodeString(&nameW);
4076         return ErrorCode;
4077     }
4078 
4079     /* Allocate a unicode string to get the data */
4080     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4081     if (!Buffer)
4082     {
4083         RtlFreeUnicodeString(&nameW);
4084         return ERROR_NOT_ENOUGH_MEMORY;
4085     }
4086 
4087     ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize);
4088     if (ErrorCode != ERROR_SUCCESS)
4089     {
4090         RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4091         RtlFreeUnicodeString(&nameW);
4092         return ErrorCode;
4093     }
4094 
4095     /* We don't need this anymore */
4096     RtlFreeUnicodeString(&nameW);
4097 
4098     /* Get the length for the multi-byte string (without the terminating NULL!) */
4099     DataLength = *count;
4100     RtlUnicodeToMultiByteSize(count, Buffer, BufferSize);
4101 
4102     if ((!data) || (DataLength < *count))
4103     {
4104         RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4105         return  data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4106     }
4107 
4108     /* We can finally do the conversion */
4109     RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize);
4110 
4111     /* NULL-terminate if there is enough room */
4112     if (DataLength > *count)
4113         DataStr[*count] = '\0';
4114 
4115     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4116 
4117     return ERROR_SUCCESS;
4118 }
4119 
4120 
4121 /************************************************************************
4122  *  RegQueryValueExW
4123  *
4124  * @implemented
4125  */
4126 LONG
4127 WINAPI
4128 RegQueryValueExW(
4129     _In_ HKEY hkeyorg,
4130     _In_ LPCWSTR name,
4131     _In_ LPDWORD reserved,
4132     _In_ LPDWORD type,
4133     _In_ LPBYTE data,
4134     _In_ LPDWORD count)
4135 {
4136     HANDLE hkey;
4137     NTSTATUS status;
4138     UNICODE_STRING name_str;
4139     DWORD total_size;
4140     char buffer[256], *buf_ptr = buffer;
4141     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4142     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4143 
4144     TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4145           hkeyorg, debugstr_w(name), reserved, type, data, count,
4146           (count && data) ? *count : 0 );
4147 
4148     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4149 
4150     status = MapDefaultKey(&hkey, hkeyorg);
4151     if (!NT_SUCCESS(status))
4152     {
4153         return RtlNtStatusToDosError(status);
4154     }
4155 
4156     if (IsHKCRKey(hkey))
4157     {
4158         LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count);
4159         ClosePredefKey(hkey);
4160         return ErrorCode;
4161     }
4162 
4163     RtlInitUnicodeString( &name_str, name );
4164 
4165     if (data)
4166         total_size = min( sizeof(buffer), *count + info_size );
4167     else
4168         total_size = info_size;
4169 
4170 
4171     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4172                               buffer, total_size, &total_size );
4173 
4174     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW)
4175     {
4176         // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4177         // On windows these conditions are likely to be side effects of the implementation...
4178         if (status == STATUS_INVALID_HANDLE && hkey)
4179         {
4180             if (type) *type = REG_NONE;
4181             if (count) *count = 0;
4182         }
4183         else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
4184         {
4185             if (type) *type = REG_NONE;
4186             if (data == NULL && count) *count = 0;
4187         }
4188         goto done;
4189     }
4190 
4191     if (data)
4192     {
4193         /* retry with a dynamically allocated buffer */
4194         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4195         {
4196             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4197             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4198             {
4199                 ClosePredefKey(hkey);
4200                 return ERROR_NOT_ENOUGH_MEMORY;
4201             }
4202             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4203             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4204                                       buf_ptr, total_size, &total_size );
4205         }
4206 
4207         if (NT_SUCCESS(status))
4208         {
4209             memcpy( data, buf_ptr + info_size, total_size - info_size );
4210             /* if the type is REG_SZ and data is not 0-terminated
4211              * and there is enough space in the buffer NT appends a \0 */
4212             if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4213             {
4214                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4215                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4216             }
4217         }
4218         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4219     }
4220     else status = STATUS_SUCCESS;
4221 
4222     if (type) *type = info->Type;
4223     if (count) *count = total_size - info_size;
4224 
4225  done:
4226     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4227     ClosePredefKey(hkey);
4228     return RtlNtStatusToDosError(status);
4229 }
4230 
4231 
4232 /************************************************************************
4233  *  RegQueryValueA
4234  *
4235  * @implemented
4236  */
4237 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
4238 {
4239     DWORD ret;
4240     HKEY subkey = hkey;
4241 
4242     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4243 
4244     if (name && name[0])
4245     {
4246     if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4247     }
4248     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4249     if (subkey != hkey) RegCloseKey( subkey );
4250     if (ret == ERROR_FILE_NOT_FOUND)
4251     {
4252     /* return empty string if default value not found */
4253     if (data) *data = 0;
4254     if (count) *count = 1;
4255     ret = ERROR_SUCCESS;
4256     }
4257     return ret;
4258 }
4259 
4260 
4261 /************************************************************************
4262  *  RegQueryValueW
4263  *
4264  * @implemented
4265  */
4266 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
4267 {
4268     DWORD ret;
4269     HKEY subkey = hkey;
4270 
4271     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4272     if (hkey == NULL)
4273     {
4274        return ERROR_INVALID_HANDLE;
4275     }
4276     if (name && name[0])
4277     {
4278         ret = RegOpenKeyW( hkey, name, &subkey);
4279         if (ret != ERROR_SUCCESS)
4280         {
4281             return ret;
4282         }
4283     }
4284 
4285     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4286 
4287     if (subkey != hkey)
4288     {
4289         RegCloseKey( subkey );
4290     }
4291 
4292     if (ret == ERROR_FILE_NOT_FOUND)
4293     {
4294         /* return empty string if default value not found */
4295         if (data)
4296             *data = 0;
4297         if (count)
4298             *count = sizeof(WCHAR);
4299         ret = ERROR_SUCCESS;
4300     }
4301     return ret;
4302 }
4303 
4304 
4305 /************************************************************************
4306  *  RegReplaceKeyA
4307  *
4308  * @implemented
4309  */
4310 LONG WINAPI
4311 RegReplaceKeyA(HKEY hKey,
4312                LPCSTR lpSubKey,
4313                LPCSTR lpNewFile,
4314                LPCSTR lpOldFile)
4315 {
4316     UNICODE_STRING SubKey;
4317     UNICODE_STRING NewFile;
4318     UNICODE_STRING OldFile;
4319     LONG ErrorCode;
4320 
4321     RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4322     RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4323     RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4324 
4325     if (lpSubKey)
4326     {
4327         if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4328         {
4329             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4330             goto Exit;
4331         }
4332     }
4333 
4334     if (lpOldFile)
4335     {
4336         if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4337         {
4338             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4339             goto Exit;
4340         }
4341     }
4342 
4343     if (lpNewFile)
4344     {
4345         if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4346         {
4347             ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4348             goto Exit;
4349         }
4350     }
4351 
4352     ErrorCode = RegReplaceKeyW(hKey,
4353                                SubKey.Buffer,
4354                                NewFile.Buffer,
4355                                OldFile.Buffer);
4356 
4357 Exit:
4358     RtlFreeUnicodeString(&OldFile);
4359     RtlFreeUnicodeString(&NewFile);
4360     RtlFreeUnicodeString(&SubKey);
4361 
4362     return ErrorCode;
4363 }
4364 
4365 
4366 /************************************************************************
4367  *  RegReplaceKeyW
4368  *
4369  * @unimplemented
4370  */
4371 LONG WINAPI
4372 RegReplaceKeyW(HKEY hKey,
4373                LPCWSTR lpSubKey,
4374                LPCWSTR lpNewFile,
4375                LPCWSTR lpOldFile)
4376 {
4377     OBJECT_ATTRIBUTES KeyObjectAttributes;
4378     OBJECT_ATTRIBUTES NewObjectAttributes;
4379     OBJECT_ATTRIBUTES OldObjectAttributes;
4380     UNICODE_STRING SubKeyName;
4381     UNICODE_STRING NewFileName;
4382     UNICODE_STRING OldFileName;
4383     BOOLEAN CloseRealKey;
4384     HANDLE RealKeyHandle;
4385     HANDLE KeyHandle;
4386     NTSTATUS Status;
4387     LONG ErrorCode = ERROR_SUCCESS;
4388 
4389     if (hKey == HKEY_PERFORMANCE_DATA)
4390     {
4391         return ERROR_INVALID_HANDLE;
4392     }
4393 
4394     Status = MapDefaultKey(&KeyHandle,
4395                            hKey);
4396     if (!NT_SUCCESS(Status))
4397     {
4398         return RtlNtStatusToDosError(Status);
4399     }
4400 
4401     /* Open the real key */
4402     if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4403     {
4404         RtlInitUnicodeString(&SubKeyName, lpSubKey);
4405         InitializeObjectAttributes(&KeyObjectAttributes,
4406                                    &SubKeyName,
4407                                    OBJ_CASE_INSENSITIVE,
4408                                    KeyHandle,
4409                                    NULL);
4410         Status = NtOpenKey(&RealKeyHandle,
4411                            MAXIMUM_ALLOWED,
4412                            &KeyObjectAttributes);
4413         if (!NT_SUCCESS(Status))
4414         {
4415             ErrorCode = RtlNtStatusToDosError(Status);
4416             goto Cleanup;
4417         }
4418 
4419         CloseRealKey = TRUE;
4420     }
4421     else
4422     {
4423         RealKeyHandle = KeyHandle;
4424         CloseRealKey = FALSE;
4425     }
4426 
4427     /* Convert new file name */
4428     if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4429                                       &NewFileName,
4430                                       NULL,
4431                                       NULL))
4432     {
4433         if (CloseRealKey)
4434         {
4435             NtClose(RealKeyHandle);
4436         }
4437 
4438         ErrorCode = ERROR_INVALID_PARAMETER;
4439         goto Cleanup;
4440     }
4441 
4442     InitializeObjectAttributes(&NewObjectAttributes,
4443                                &NewFileName,
4444                                OBJ_CASE_INSENSITIVE,
4445                                NULL,
4446                                NULL);
4447 
4448     /* Convert old file name */
4449     if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4450                                       &OldFileName,
4451                                       NULL,
4452                                       NULL))
4453     {
4454         RtlFreeHeap(RtlGetProcessHeap (),
4455                     0,
4456                     NewFileName.Buffer);
4457         if (CloseRealKey)
4458         {
4459             NtClose(RealKeyHandle);
4460         }
4461 
4462         ErrorCode = ERROR_INVALID_PARAMETER;
4463         goto Cleanup;
4464     }
4465 
4466     InitializeObjectAttributes(&OldObjectAttributes,
4467                                &OldFileName,
4468                                OBJ_CASE_INSENSITIVE,
4469                                NULL,
4470                                NULL);
4471 
4472     Status = NtReplaceKey(&NewObjectAttributes,
4473                           RealKeyHandle,
4474                           &OldObjectAttributes);
4475 
4476     RtlFreeHeap(RtlGetProcessHeap(),
4477                 0,
4478                 OldFileName.Buffer);
4479     RtlFreeHeap(RtlGetProcessHeap(),
4480                 0,
4481                 NewFileName.Buffer);
4482 
4483     if (CloseRealKey)
4484     {
4485         NtClose(RealKeyHandle);
4486     }
4487 
4488     if (!NT_SUCCESS(Status))
4489     {
4490         return RtlNtStatusToDosError(Status);
4491     }
4492 
4493 Cleanup:
4494     ClosePredefKey(KeyHandle);
4495 
4496     return ErrorCode;
4497 }
4498 
4499 
4500 /************************************************************************
4501  *  RegRestoreKeyA
4502  *
4503  * @implemented
4504  */
4505 LONG WINAPI
4506 RegRestoreKeyA(HKEY hKey,
4507                LPCSTR lpFile,
4508                DWORD dwFlags)
4509 {
4510     UNICODE_STRING FileName;
4511     LONG ErrorCode;
4512 
4513     if (lpFile)
4514     {
4515         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4516             return ERROR_NOT_ENOUGH_MEMORY;
4517     }
4518     else
4519         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4520 
4521     ErrorCode = RegRestoreKeyW(hKey,
4522                                FileName.Buffer,
4523                                dwFlags);
4524 
4525     RtlFreeUnicodeString(&FileName);
4526 
4527     return ErrorCode;
4528 }
4529 
4530 
4531 /************************************************************************
4532  *  RegRestoreKeyW
4533  *
4534  * @implemented
4535  */
4536 LONG WINAPI
4537 RegRestoreKeyW(HKEY hKey,
4538                LPCWSTR lpFile,
4539                DWORD dwFlags)
4540 {
4541     OBJECT_ATTRIBUTES ObjectAttributes;
4542     IO_STATUS_BLOCK IoStatusBlock;
4543     UNICODE_STRING FileName;
4544     HANDLE FileHandle;
4545     HANDLE KeyHandle;
4546     NTSTATUS Status;
4547 
4548     if (hKey == HKEY_PERFORMANCE_DATA)
4549     {
4550         return ERROR_INVALID_HANDLE;
4551     }
4552 
4553     Status = MapDefaultKey(&KeyHandle,
4554                            hKey);
4555     if (!NT_SUCCESS(Status))
4556     {
4557         return RtlNtStatusToDosError(Status);
4558     }
4559 
4560     if (!RtlDosPathNameToNtPathName_U(lpFile,
4561                                       &FileName,
4562                                       NULL,
4563                                       NULL))
4564     {
4565         Status = STATUS_INVALID_PARAMETER;
4566         goto Cleanup;
4567     }
4568 
4569     InitializeObjectAttributes(&ObjectAttributes,
4570                                &FileName,
4571                                OBJ_CASE_INSENSITIVE,
4572                                NULL,
4573                                NULL);
4574 
4575     Status = NtOpenFile(&FileHandle,
4576                         FILE_GENERIC_READ,
4577                         &ObjectAttributes,
4578                         &IoStatusBlock,
4579                         FILE_SHARE_READ,
4580                         FILE_SYNCHRONOUS_IO_NONALERT);
4581     RtlFreeHeap(RtlGetProcessHeap(),
4582                 0,
4583                 FileName.Buffer);
4584     if (!NT_SUCCESS(Status))
4585     {
4586         goto Cleanup;
4587     }
4588 
4589     Status = NtRestoreKey(KeyHandle,
4590                           FileHandle,
4591                           (ULONG)dwFlags);
4592     NtClose (FileHandle);
4593 
4594 Cleanup:
4595     ClosePredefKey(KeyHandle);
4596 
4597     if (!NT_SUCCESS(Status))
4598     {
4599         return RtlNtStatusToDosError(Status);
4600     }
4601 
4602     return ERROR_SUCCESS;
4603 }
4604 
4605 
4606 /************************************************************************
4607  *  RegSaveKeyA
4608  *
4609  * @implemented
4610  */
4611 LONG WINAPI
4612 RegSaveKeyA(HKEY hKey,
4613             LPCSTR lpFile,
4614             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4615 {
4616     UNICODE_STRING FileName;
4617     LONG ErrorCode;
4618 
4619     if (lpFile)
4620     {
4621         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4622             return ERROR_NOT_ENOUGH_MEMORY;
4623     }
4624     else
4625         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4626 
4627     ErrorCode = RegSaveKeyW(hKey,
4628                             FileName.Buffer,
4629                             lpSecurityAttributes);
4630     RtlFreeUnicodeString(&FileName);
4631 
4632     return ErrorCode;
4633 }
4634 
4635 
4636 /************************************************************************
4637  *  RegSaveKeyW
4638  *
4639  * @implemented
4640  */
4641 LONG WINAPI
4642 RegSaveKeyW(HKEY hKey,
4643             LPCWSTR lpFile,
4644             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4645 {
4646     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4647     OBJECT_ATTRIBUTES ObjectAttributes;
4648     UNICODE_STRING FileName;
4649     IO_STATUS_BLOCK IoStatusBlock;
4650     HANDLE FileHandle;
4651     HANDLE KeyHandle;
4652     NTSTATUS Status;
4653 
4654     Status = MapDefaultKey(&KeyHandle,
4655                            hKey);
4656     if (!NT_SUCCESS(Status))
4657     {
4658         return RtlNtStatusToDosError(Status);
4659     }
4660 
4661     if (!RtlDosPathNameToNtPathName_U(lpFile,
4662                                       &FileName,
4663                                       NULL,
4664                                       NULL))
4665     {
4666         Status = STATUS_INVALID_PARAMETER;
4667         goto Cleanup;
4668     }
4669 
4670     if (lpSecurityAttributes != NULL)
4671     {
4672         SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4673     }
4674 
4675     InitializeObjectAttributes(&ObjectAttributes,
4676                                &FileName,
4677                                OBJ_CASE_INSENSITIVE,
4678                                NULL,
4679                                SecurityDescriptor);
4680     Status = NtCreateFile(&FileHandle,
4681                           GENERIC_WRITE | SYNCHRONIZE,
4682                           &ObjectAttributes,
4683                           &IoStatusBlock,
4684                           NULL,
4685                           FILE_ATTRIBUTE_NORMAL,
4686                           FILE_SHARE_READ,
4687                           FILE_CREATE,
4688                           FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4689                           NULL,
4690                           0);
4691     RtlFreeHeap(RtlGetProcessHeap(),
4692                 0,
4693                 FileName.Buffer);
4694     if (!NT_SUCCESS(Status))
4695     {
4696         goto Cleanup;
4697     }
4698 
4699     Status = NtSaveKey(KeyHandle,
4700                        FileHandle);
4701     NtClose (FileHandle);
4702 
4703 Cleanup:
4704     ClosePredefKey(KeyHandle);
4705 
4706     if (!NT_SUCCESS(Status))
4707     {
4708         return RtlNtStatusToDosError(Status);
4709     }
4710 
4711     return ERROR_SUCCESS;
4712 }
4713 
4714 
4715 /************************************************************************
4716  *  RegSaveKeyExA
4717  *
4718  * @implemented
4719  */
4720 LONG
4721 WINAPI
4722 RegSaveKeyExA(HKEY hKey,
4723               LPCSTR lpFile,
4724               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4725               DWORD Flags)
4726 {
4727     UNICODE_STRING FileName;
4728     LONG ErrorCode;
4729 
4730     if (lpFile)
4731     {
4732         if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4733             return ERROR_NOT_ENOUGH_MEMORY;
4734     }
4735     else
4736         RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4737 
4738     ErrorCode = RegSaveKeyExW(hKey,
4739                               FileName.Buffer,
4740                               lpSecurityAttributes,
4741                               Flags);
4742     RtlFreeUnicodeString(&FileName);
4743 
4744     return ErrorCode;
4745 }
4746 
4747 
4748 /************************************************************************
4749  *  RegSaveKeyExW
4750  *
4751  * @unimplemented
4752  */
4753 LONG
4754 WINAPI
4755 RegSaveKeyExW(HKEY hKey,
4756               LPCWSTR lpFile,
4757               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4758               DWORD Flags)
4759 {
4760     switch (Flags)
4761     {
4762         case REG_STANDARD_FORMAT:
4763         case REG_LATEST_FORMAT:
4764         case REG_NO_COMPRESSION:
4765             break;
4766         default:
4767             return ERROR_INVALID_PARAMETER;
4768     }
4769 
4770     FIXME("RegSaveKeyExW(): Flags ignored!\n");
4771 
4772     return RegSaveKeyW(hKey,
4773                        lpFile,
4774                        lpSecurityAttributes);
4775 }
4776 
4777 
4778 /************************************************************************
4779  *  RegSetKeySecurity
4780  *
4781  * @implemented
4782  */
4783 LONG WINAPI
4784 RegSetKeySecurity(HKEY hKey,
4785                   SECURITY_INFORMATION SecurityInformation,
4786                   PSECURITY_DESCRIPTOR pSecurityDescriptor)
4787 {
4788     HANDLE KeyHandle;
4789     NTSTATUS Status;
4790 
4791     if (hKey == HKEY_PERFORMANCE_DATA)
4792     {
4793         return ERROR_INVALID_HANDLE;
4794     }
4795 
4796     Status = MapDefaultKey(&KeyHandle,
4797                            hKey);
4798     if (!NT_SUCCESS(Status))
4799     {
4800         return RtlNtStatusToDosError(Status);
4801     }
4802 
4803     Status = NtSetSecurityObject(KeyHandle,
4804                                  SecurityInformation,
4805                                  pSecurityDescriptor);
4806 
4807     ClosePredefKey(KeyHandle);
4808 
4809     if (!NT_SUCCESS(Status))
4810     {
4811         return RtlNtStatusToDosError(Status);
4812     }
4813 
4814     return ERROR_SUCCESS;
4815 }
4816 
4817 
4818 /************************************************************************
4819  *  RegSetValueExA
4820  *
4821  * @implemented
4822  */
4823 LONG WINAPI
4824 RegSetValueExA(HKEY hKey,
4825                LPCSTR lpValueName,
4826                DWORD Reserved,
4827                DWORD dwType,
4828                CONST BYTE* lpData,
4829                DWORD cbData)
4830 {
4831     UNICODE_STRING ValueName;
4832     LPWSTR pValueName;
4833     ANSI_STRING AnsiString;
4834     UNICODE_STRING Data;
4835     LONG ErrorCode;
4836     LPBYTE pData;
4837     DWORD DataSize;
4838     NTSTATUS Status;
4839 
4840     /* Convert SubKey name to Unicode */
4841     if (lpValueName != NULL && lpValueName[0] != '\0')
4842     {
4843         if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName))
4844             return ERROR_NOT_ENOUGH_MEMORY;
4845     }
4846     else
4847     {
4848         ValueName.Buffer = NULL;
4849     }
4850 
4851     pValueName = (LPWSTR)ValueName.Buffer;
4852 
4853 
4854     if (is_string(dwType) && (cbData != 0))
4855     {
4856         /* Convert ANSI string Data to Unicode */
4857         /* If last character NOT zero then increment length */
4858         LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4859         AnsiString.Buffer = (PSTR)lpData;
4860         AnsiString.Length = cbData + bNoNulledStr;
4861         AnsiString.MaximumLength = cbData + bNoNulledStr;
4862         Status = RtlAnsiStringToUnicodeString(&Data,
4863                                      &AnsiString,
4864                                      TRUE);
4865 
4866         if (!NT_SUCCESS(Status))
4867         {
4868             if (pValueName != NULL)
4869                 RtlFreeUnicodeString(&ValueName);
4870 
4871             return RtlNtStatusToDosError(Status);
4872         }
4873         pData = (LPBYTE)Data.Buffer;
4874         DataSize = cbData * sizeof(WCHAR);
4875     }
4876     else
4877     {
4878         Data.Buffer = NULL;
4879         pData = (LPBYTE)lpData;
4880         DataSize = cbData;
4881     }
4882 
4883     ErrorCode = RegSetValueExW(hKey,
4884                                pValueName,
4885                                Reserved,
4886                                dwType,
4887                                pData,
4888                                DataSize);
4889 
4890     if (pValueName != NULL)
4891         RtlFreeUnicodeString(&ValueName);
4892 
4893     if (Data.Buffer != NULL)
4894         RtlFreeUnicodeString(&Data);
4895 
4896     return ErrorCode;
4897 }
4898 
4899 
4900 /************************************************************************
4901  *  RegSetValueExW
4902  *
4903  * @implemented
4904  */
4905 LONG
4906 WINAPI
4907 RegSetValueExW(
4908     _In_ HKEY hKey,
4909     _In_ LPCWSTR lpValueName,
4910     _In_ DWORD Reserved,
4911     _In_ DWORD dwType,
4912     _In_ CONST BYTE* lpData,
4913     _In_ DWORD cbData)
4914 {
4915     UNICODE_STRING ValueName;
4916     HANDLE KeyHandle;
4917     NTSTATUS Status;
4918 
4919     Status = MapDefaultKey(&KeyHandle,
4920                            hKey);
4921     if (!NT_SUCCESS(Status))
4922     {
4923         return RtlNtStatusToDosError(Status);
4924     }
4925 
4926     if (IsHKCRKey(KeyHandle))
4927     {
4928         LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4929         ClosePredefKey(KeyHandle);
4930         return ErrorCode;
4931     }
4932 
4933     if (is_string(dwType) && (cbData != 0))
4934     {
4935         PWSTR pwsData = (PWSTR)lpData;
4936 
4937         _SEH2_TRY
4938         {
4939             if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4940                 (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4941             {
4942                 /* Increment length if last character is not zero and next is zero */
4943                 cbData += sizeof(WCHAR);
4944             }
4945         }
4946         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4947         {
4948             /* Do not fail if we fault where we were told not to go */
4949         }
4950         _SEH2_END;
4951     }
4952 
4953     RtlInitUnicodeString(&ValueName, lpValueName);
4954 
4955     Status = NtSetValueKey(KeyHandle,
4956                            &ValueName,
4957                            0,
4958                            dwType,
4959                            (PVOID)lpData,
4960                            (ULONG)cbData);
4961 
4962     ClosePredefKey(KeyHandle);
4963 
4964     if (!NT_SUCCESS(Status))
4965     {
4966         return RtlNtStatusToDosError(Status);
4967     }
4968 
4969     return ERROR_SUCCESS;
4970 }
4971 
4972 
4973 /************************************************************************
4974  *  RegSetValueA
4975  *
4976  * @implemented
4977  */
4978 LONG WINAPI
4979 RegSetValueA(HKEY hKeyOriginal,
4980              LPCSTR lpSubKey,
4981              DWORD dwType,
4982              LPCSTR lpData,
4983              DWORD cbData)
4984 {
4985     HKEY subkey;
4986     HANDLE hKey;
4987     DWORD ret;
4988     NTSTATUS Status;
4989 
4990     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4991 
4992     if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4993 
4994     Status = MapDefaultKey(&hKey, hKeyOriginal);
4995     if (!NT_SUCCESS(Status))
4996     {
4997         return RtlNtStatusToDosError (Status);
4998     }
4999     subkey = hKey;
5000 
5001     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
5002     {
5003         ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
5004         if (ret != ERROR_SUCCESS)
5005             goto Cleanup;
5006     }
5007 
5008     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
5009     if (subkey != hKey)
5010         RegCloseKey(subkey);
5011 
5012 Cleanup:
5013     ClosePredefKey(hKey);
5014 
5015     return ret;
5016 }
5017 
5018 
5019 /************************************************************************
5020  *  RegSetValueW
5021  *
5022  * @implemented
5023  */
5024 LONG WINAPI
5025 RegSetValueW(HKEY hKeyOriginal,
5026              LPCWSTR lpSubKey,
5027              DWORD dwType,
5028              LPCWSTR lpData,
5029              DWORD cbData)
5030 {
5031     HKEY subkey;
5032     HANDLE hKey;
5033     DWORD ret;
5034     NTSTATUS Status;
5035 
5036     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5037 
5038     if (dwType != REG_SZ || !lpData)
5039         return ERROR_INVALID_PARAMETER;
5040 
5041     Status = MapDefaultKey(&hKey,
5042                            hKeyOriginal);
5043     if (!NT_SUCCESS(Status))
5044     {
5045         return RtlNtStatusToDosError(Status);
5046     }
5047     subkey = hKey;
5048 
5049     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
5050     {
5051         ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5052         if (ret != ERROR_SUCCESS)
5053             goto Cleanup;
5054     }
5055 
5056     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5057                           (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5058     if (subkey != hKey)
5059         RegCloseKey(subkey);
5060 
5061 Cleanup:
5062     ClosePredefKey(hKey);
5063 
5064     return ret;
5065 }
5066 
5067 
5068 /************************************************************************
5069  *  RegUnLoadKeyA
5070  *
5071  * @implemented
5072  */
5073 LONG WINAPI
5074 RegUnLoadKeyA(HKEY hKey,
5075               LPCSTR lpSubKey)
5076 {
5077     UNICODE_STRING KeyName;
5078     DWORD ErrorCode;
5079 
5080     if (lpSubKey)
5081     {
5082         if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5083             return ERROR_NOT_ENOUGH_MEMORY;
5084     }
5085     else
5086         RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5087 
5088     ErrorCode = RegUnLoadKeyW(hKey,
5089                               KeyName.Buffer);
5090 
5091     RtlFreeUnicodeString (&KeyName);
5092 
5093     return ErrorCode;
5094 }
5095 
5096 
5097 /************************************************************************
5098  *  RegUnLoadKeyW
5099  *
5100  * @implemented
5101  */
5102 LONG WINAPI
5103 RegUnLoadKeyW(HKEY hKey,
5104               LPCWSTR lpSubKey)
5105 {
5106     OBJECT_ATTRIBUTES ObjectAttributes;
5107     UNICODE_STRING KeyName;
5108     HANDLE KeyHandle;
5109     NTSTATUS Status;
5110 
5111     if (hKey == HKEY_PERFORMANCE_DATA)
5112     {
5113       return ERROR_INVALID_HANDLE;
5114     }
5115 
5116     Status = MapDefaultKey(&KeyHandle, hKey);
5117     if (!NT_SUCCESS(Status))
5118     {
5119         return RtlNtStatusToDosError(Status);
5120     }
5121 
5122     RtlInitUnicodeString(&KeyName, lpSubKey);
5123 
5124     InitializeObjectAttributes(&ObjectAttributes,
5125                                &KeyName,
5126                                OBJ_CASE_INSENSITIVE,
5127                                KeyHandle,
5128                                NULL);
5129 
5130     Status = NtUnloadKey(&ObjectAttributes);
5131 
5132     ClosePredefKey(KeyHandle);
5133 
5134     if (!NT_SUCCESS(Status))
5135     {
5136         return RtlNtStatusToDosError(Status);
5137     }
5138 
5139     return ERROR_SUCCESS;
5140 }
5141 
5142 /* EOF */
5143