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