update for HEAD-2003091401
[reactos.git] / lib / advapi32 / reg / reg.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/advapi32/reg/reg.c
6  * PURPOSE:         Registry functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  *                  19990309 EA Stubs
11  */
12
13 /* INCLUDES *****************************************************************/
14
15 #define NTOS_MODE_USER
16 #include <ntos.h>
17 #include <ddk/ntddk.h>
18 #include <ntdll/rtl.h>
19 #include <windows.h>
20 #include <wchar.h>
21
22 #define NDEBUG
23 #include <debug.h>
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 CRITICAL_SECTION HandleTableCS;
34 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
35 static HANDLE ProcessHeap;
36
37 /* PROTOTYPES ***************************************************************/
38
39 static NTSTATUS MapDefaultKey (PHKEY ParentKey, HKEY Key);
40 static VOID CloseDefaultKeys(VOID);
41
42 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
43 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
44 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
45 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
46
47
48 /* FUNCTIONS ****************************************************************/
49
50 /************************************************************************
51  *  RegInitDefaultHandles
52  */
53 BOOL
54 RegInitialize (VOID)
55 {
56   DPRINT("RegInitialize()\n");
57
58   ProcessHeap = RtlGetProcessHeap();
59   RtlZeroMemory (DefaultHandleTable,
60                  MAX_DEFAULT_HANDLES * sizeof(HANDLE));
61   RtlInitializeCriticalSection (&HandleTableCS);
62
63   return TRUE;
64 }
65
66
67 /************************************************************************
68  *  RegInit
69  */
70 BOOL
71 RegCleanup (VOID)
72 {
73   DPRINT("RegCleanup()\n");
74
75   CloseDefaultKeys ();
76   RtlDeleteCriticalSection (&HandleTableCS);
77
78   return TRUE;
79 }
80
81
82 static NTSTATUS
83 MapDefaultKey (PHKEY RealKey,
84                HKEY Key)
85 {
86   PHANDLE Handle;
87   ULONG Index;
88   NTSTATUS Status = STATUS_SUCCESS;
89
90   DPRINT("MapDefaultKey (Key %x)\n", Key);
91
92   if (((ULONG)Key & 0xF0000000) != 0x80000000)
93     {
94       *RealKey = Key;
95       return STATUS_SUCCESS;
96     }
97
98   /* Handle special cases here */
99   Index = (ULONG)Key & 0x0FFFFFFF;
100   if (Index >= MAX_DEFAULT_HANDLES)
101     {
102       return STATUS_INVALID_PARAMETER;
103     }
104
105   RtlEnterCriticalSection (&HandleTableCS);
106   Handle = &DefaultHandleTable[Index];
107   if (*Handle == NULL)
108     {
109       /* create/open the default handle */
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           case 5: /* HKEY_CURRENT_CONFIG */
134             Status = OpenCurrentConfigKey (Handle);
135             break;
136
137           case 6: /* HKEY_DYN_DATA */
138             Status = STATUS_NOT_IMPLEMENTED;
139             break;
140
141           default:
142             DPRINT("MapDefaultHandle() no handle creator\n");
143             Status = STATUS_INVALID_PARAMETER;
144         }
145     }
146   RtlLeaveCriticalSection (&HandleTableCS);
147
148   if (NT_SUCCESS(Status))
149     {
150       *RealKey = (HKEY)*Handle;
151     }
152
153    return Status;
154 }
155
156
157 static VOID
158 CloseDefaultKeys (VOID)
159 {
160   ULONG i;
161
162   RtlEnterCriticalSection (&HandleTableCS);
163   for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
164     {
165       if (DefaultHandleTable[i] != NULL)
166         {
167           NtClose (DefaultHandleTable[i]);
168           DefaultHandleTable[i] = NULL;
169         }
170     }
171   RtlLeaveCriticalSection (&HandleTableCS);
172 }
173
174
175 static NTSTATUS
176 OpenClassesRootKey (PHANDLE KeyHandle)
177 {
178   OBJECT_ATTRIBUTES Attributes;
179   UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\Software\\CLASSES");
180
181   DPRINT("OpenClassesRootKey()\n");
182
183   InitializeObjectAttributes (&Attributes,
184                               &KeyName,
185                               OBJ_CASE_INSENSITIVE,
186                               NULL,
187                               NULL);
188   return NtOpenKey (KeyHandle,
189                     MAXIMUM_ALLOWED,
190                     &Attributes);
191 }
192
193
194 static NTSTATUS
195 OpenLocalMachineKey (PHANDLE KeyHandle)
196 {
197   OBJECT_ATTRIBUTES Attributes;
198   UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine");
199
200   DPRINT("OpenLocalMachineKey()\n");
201
202   InitializeObjectAttributes (&Attributes,
203                               &KeyName,
204                               OBJ_CASE_INSENSITIVE,
205                               NULL,
206                               NULL);
207   return NtOpenKey (KeyHandle,
208                     MAXIMUM_ALLOWED,
209                     &Attributes);
210 }
211
212
213 static NTSTATUS
214 OpenUsersKey (PHANDLE KeyHandle)
215 {
216   OBJECT_ATTRIBUTES Attributes;
217   UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\User");
218
219   DPRINT("OpenUsersKey()\n");
220
221   InitializeObjectAttributes (&Attributes,
222                               &KeyName,
223                               OBJ_CASE_INSENSITIVE,
224                               NULL,
225                               NULL);
226   return NtOpenKey (KeyHandle,
227                     KEY_ALL_ACCESS,
228                     &Attributes);
229 }
230
231
232 static NTSTATUS
233 OpenCurrentConfigKey (PHANDLE KeyHandle)
234 {
235   OBJECT_ATTRIBUTES Attributes;
236   UNICODE_STRING KeyName =
237   UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
238
239   DPRINT("OpenCurrentConfigKey()\n");
240
241   InitializeObjectAttributes (&Attributes,
242                               &KeyName,
243                               OBJ_CASE_INSENSITIVE,
244                               NULL,
245                               NULL);
246   return NtOpenKey (KeyHandle,
247                     MAXIMUM_ALLOWED,
248                     &Attributes);
249 }
250
251
252 /************************************************************************
253  *  RegCloseKey
254  *
255  * @implemented
256  */
257 LONG STDCALL
258 RegCloseKey (HKEY hKey)
259 {
260   LONG ErrorCode;
261   NTSTATUS Status;
262
263   /* don't close null handle or a pseudo handle */
264   if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
265     {
266       return ERROR_INVALID_HANDLE;
267     }
268
269   Status = NtClose (hKey);
270   if (!NT_SUCCESS(Status))
271     {
272       ErrorCode = RtlNtStatusToDosError (Status);
273       SetLastError (ErrorCode);
274       return ErrorCode;
275     }
276
277   return ERROR_SUCCESS;
278 }
279
280
281 /************************************************************************
282  *  RegConnectRegistryA
283  *
284  * @unimplemented
285  */
286 LONG STDCALL
287 RegConnectRegistryA (LPCSTR lpMachineName,
288                      HKEY hKey,
289                      PHKEY phkResult)
290 {
291   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
292   return ERROR_CALL_NOT_IMPLEMENTED;
293 }
294
295
296 /************************************************************************
297  *  RegConnectRegistryW
298  *
299  * @unimplemented
300  */
301 LONG STDCALL
302 RegConnectRegistryW (LPCWSTR lpMachineName,
303                      HKEY hKey,
304                      PHKEY phkResult)
305 {
306   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
307   return ERROR_CALL_NOT_IMPLEMENTED;
308 }
309
310
311 /************************************************************************
312  *  RegCreateKeyExA
313  *
314  * @implemented
315  */
316 LONG STDCALL
317 RegCreateKeyExA (HKEY hKey,
318                  LPCSTR lpSubKey,
319                  DWORD Reserved,
320                  LPSTR lpClass,
321                  DWORD dwOptions,
322                  REGSAM samDesired,
323                  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
324                  PHKEY phkResult,
325                  LPDWORD lpdwDisposition)
326 {
327   UNICODE_STRING SubKeyString;
328   UNICODE_STRING ClassString;
329   OBJECT_ATTRIBUTES Attributes;
330   HKEY ParentKey;
331   LONG ErrorCode;
332   NTSTATUS Status;
333
334   DPRINT("RegCreateKeyExA() called\n");
335
336   /* get the real parent key */
337   Status = MapDefaultKey (&ParentKey,
338                           hKey);
339   if (!NT_SUCCESS(Status))
340     {
341       ErrorCode = RtlNtStatusToDosError (Status);
342       SetLastError (ErrorCode);
343       return ErrorCode;
344     }
345   DPRINT("ParentKey %x\n", (ULONG)ParentKey);
346
347   if (lpClass != NULL)
348     {
349       RtlCreateUnicodeStringFromAsciiz (&ClassString,
350                                         lpClass);
351     }
352   RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
353                                     (LPSTR)lpSubKey);
354   InitializeObjectAttributes (&Attributes,
355                               &SubKeyString,
356                               OBJ_CASE_INSENSITIVE,
357                               (HANDLE)ParentKey,
358                               (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
359   Status = NtCreateKey (phkResult,
360                         samDesired,
361                         &Attributes,
362                         0,
363                         (lpClass == NULL)? NULL : &ClassString,
364                         dwOptions,
365                         (PULONG)lpdwDisposition);
366   RtlFreeUnicodeString (&SubKeyString);
367   if (lpClass != NULL)
368     {
369       RtlFreeUnicodeString (&ClassString);
370     }
371   DPRINT("Status %x\n", Status);
372   if (!NT_SUCCESS(Status))
373     {
374       ErrorCode = RtlNtStatusToDosError (Status);
375       SetLastError (ErrorCode);
376       return ErrorCode;
377     }
378
379   return ERROR_SUCCESS;
380 }
381
382
383 /************************************************************************
384  *  RegCreateKeyExW
385  *
386  * @implemented
387  */
388 LONG STDCALL
389 RegCreateKeyExW(HKEY hKey,
390     LPCWSTR   lpSubKey,
391     DWORD     Reserved,
392     LPWSTR    lpClass,
393     DWORD     dwOptions,
394     REGSAM    samDesired,
395     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
396     PHKEY     phkResult,
397     LPDWORD   lpdwDisposition)
398 {
399   UNICODE_STRING SubKeyString;
400   UNICODE_STRING ClassString;
401   OBJECT_ATTRIBUTES Attributes;
402   HKEY ParentKey;
403   LONG ErrorCode;
404   NTSTATUS Status;
405
406   DPRINT("RegCreateKeyExW() called\n");
407
408   /* get the real parent key */
409   Status = MapDefaultKey (&ParentKey,
410                           hKey);
411   if (!NT_SUCCESS(Status))
412     {
413       ErrorCode = RtlNtStatusToDosError(Status);
414       SetLastError (ErrorCode);
415       return ErrorCode;
416     }
417   DPRINT("ParentKey %x\n", (ULONG)ParentKey);
418
419   RtlInitUnicodeString (&ClassString,
420                         lpClass);
421   RtlInitUnicodeString (&SubKeyString,
422                         lpSubKey);
423   InitializeObjectAttributes (&Attributes,
424                               &SubKeyString,
425                               OBJ_CASE_INSENSITIVE,
426                               (HANDLE)ParentKey,
427                               (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
428   Status = NtCreateKey (phkResult,
429                         samDesired,
430                         &Attributes,
431                         0,
432                         (lpClass == NULL)? NULL : &ClassString,
433                         dwOptions,
434                         (PULONG)lpdwDisposition);
435   DPRINT("Status %x\n", Status);
436   if (!NT_SUCCESS(Status))
437     {
438       ErrorCode = RtlNtStatusToDosError (Status);
439       SetLastError (ErrorCode);
440       return ErrorCode;
441     }
442
443   return ERROR_SUCCESS;
444 }
445
446
447 /************************************************************************
448  *  RegCreateKeyA
449  *
450  * @implemented
451  */
452 LONG STDCALL
453 RegCreateKeyA (HKEY hKey,
454                LPCSTR lpSubKey,
455                PHKEY phkResult)
456 {
457   return RegCreateKeyExA (hKey,
458                           lpSubKey,
459                           0,
460                           NULL,
461                           0,
462                           KEY_ALL_ACCESS,
463                           NULL,
464                           phkResult,
465                           NULL);
466 }
467
468
469 /************************************************************************
470  *  RegCreateKeyW
471  *
472  * @implemented
473  */
474 LONG STDCALL
475 RegCreateKeyW (HKEY hKey,
476                LPCWSTR lpSubKey,
477                PHKEY phkResult)
478 {
479   return RegCreateKeyExW (hKey,
480                           lpSubKey,
481                           0,
482                           NULL,
483                           0,
484                           KEY_ALL_ACCESS,
485                           NULL,
486                           phkResult,
487                           NULL);
488 }
489
490
491 /************************************************************************
492  *  RegDeleteKeyA
493  *
494  * @implemented
495  */
496 LONG STDCALL
497 RegDeleteKeyA (HKEY hKey,
498                LPCSTR lpSubKey)
499 {
500   OBJECT_ATTRIBUTES ObjectAttributes;
501   UNICODE_STRING SubKeyName;
502   HKEY ParentKey;
503   HANDLE TargetKey;
504   NTSTATUS Status;
505   LONG ErrorCode;
506
507   Status = MapDefaultKey (&ParentKey,
508                           hKey);
509   if (!NT_SUCCESS(Status))
510     {
511       ErrorCode = RtlNtStatusToDosError (Status);
512       SetLastError (ErrorCode);
513       return ErrorCode;
514     }
515
516   RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
517                                     (LPSTR)lpSubKey);
518   InitializeObjectAttributes(&ObjectAttributes,
519                              &SubKeyName,
520                              OBJ_CASE_INSENSITIVE,
521                              (HANDLE)ParentKey,
522                              NULL);
523
524   Status = NtOpenKey (&TargetKey,
525                       DELETE,
526                       &ObjectAttributes);
527   RtlFreeUnicodeString (&SubKeyName);
528   if (!NT_SUCCESS(Status))
529     {
530       ErrorCode = RtlNtStatusToDosError (Status);
531       SetLastError (ErrorCode);
532       return ErrorCode;
533     }
534
535   Status = NtDeleteKey (TargetKey);
536   NtClose (TargetKey);
537   if (!NT_SUCCESS(Status))
538     {
539       ErrorCode = RtlNtStatusToDosError(Status);
540       SetLastError (ErrorCode);
541       return ErrorCode;
542     }
543
544   return ERROR_SUCCESS;
545 }
546
547
548 /************************************************************************
549  *  RegDeleteKeyW
550  *
551  * @implemented
552  */
553 LONG STDCALL
554 RegDeleteKeyW (HKEY hKey,
555                LPCWSTR lpSubKey)
556 {
557   OBJECT_ATTRIBUTES ObjectAttributes;
558   UNICODE_STRING SubKeyName;
559   HKEY ParentKey;
560   HANDLE TargetKey;
561   NTSTATUS Status;
562   LONG ErrorCode;
563
564   Status = MapDefaultKey (&ParentKey,
565                           hKey);
566   if (!NT_SUCCESS(Status))
567     {
568       ErrorCode = RtlNtStatusToDosError (Status);
569       SetLastError (ErrorCode);
570       return ErrorCode;
571     }
572
573   RtlInitUnicodeString (&SubKeyName,
574                         (LPWSTR)lpSubKey);
575   InitializeObjectAttributes (&ObjectAttributes,
576                               &SubKeyName,
577                               OBJ_CASE_INSENSITIVE,
578                               (HANDLE)ParentKey,
579                               NULL);
580   Status = NtOpenKey (&TargetKey,
581                       DELETE,
582                       &ObjectAttributes);
583   if (!NT_SUCCESS(Status))
584     {
585       ErrorCode = RtlNtStatusToDosError (Status);
586       SetLastError (ErrorCode);
587       return ErrorCode;
588     }
589
590   Status = NtDeleteKey (TargetKey);
591   NtClose (TargetKey);
592   if (!NT_SUCCESS(Status))
593     {
594       ErrorCode = RtlNtStatusToDosError (Status);
595       SetLastError (ErrorCode);
596       return ErrorCode;
597     }
598
599   return ERROR_SUCCESS;
600 }
601
602
603 /************************************************************************
604  *  RegDeleteValueA
605  *
606  * @implemented
607  */
608 LONG STDCALL
609 RegDeleteValueA (HKEY hKey,
610                  LPCSTR lpValueName)
611 {
612   UNICODE_STRING ValueName;
613   HKEY KeyHandle;
614   LONG ErrorCode;
615   NTSTATUS Status;
616
617   Status = MapDefaultKey (&KeyHandle,
618                           hKey);
619   if (!NT_SUCCESS(Status))
620     {
621       ErrorCode = RtlNtStatusToDosError (Status);
622       SetLastError (ErrorCode);
623       return ErrorCode;
624     }
625
626   RtlCreateUnicodeStringFromAsciiz (&ValueName,
627                                     (LPSTR)lpValueName);
628   Status = NtDeleteValueKey (KeyHandle,
629                              &ValueName);
630   RtlFreeUnicodeString (&ValueName);
631   if (!NT_SUCCESS(Status))
632     {
633       ErrorCode = RtlNtStatusToDosError (Status);
634       SetLastError (ErrorCode);
635       return ErrorCode;
636     }
637
638   return ERROR_SUCCESS;
639 }
640
641
642 /************************************************************************
643  *  RegDeleteValueW
644  *
645  * @implemented
646  */
647 LONG STDCALL
648 RegDeleteValueW (HKEY hKey,
649                  LPCWSTR lpValueName)
650 {
651   UNICODE_STRING ValueName;
652   NTSTATUS Status;
653   LONG ErrorCode;
654   HKEY KeyHandle;
655
656   Status = MapDefaultKey (&KeyHandle,
657                           hKey);
658   if (!NT_SUCCESS(Status))
659     {
660       ErrorCode = RtlNtStatusToDosError (Status);
661       SetLastError (ErrorCode);
662       return ErrorCode;
663     }
664
665   RtlInitUnicodeString (&ValueName,
666                         (LPWSTR)lpValueName);
667
668   Status = NtDeleteValueKey (KeyHandle,
669                              &ValueName);
670   if (!NT_SUCCESS(Status))
671     {
672       ErrorCode = RtlNtStatusToDosError (Status);
673       SetLastError (ErrorCode);
674       return ErrorCode;
675     }
676
677   return ERROR_SUCCESS;
678 }
679
680
681 /************************************************************************
682  *  RegEnumKeyA
683  *
684  * @implemented
685  */
686 LONG STDCALL
687 RegEnumKeyA (HKEY hKey,
688              DWORD dwIndex,
689              LPSTR lpName,
690              DWORD cbName)
691 {
692   DWORD dwLength;
693
694   dwLength = cbName;
695   return RegEnumKeyExA (hKey,
696                         dwIndex,
697                         lpName,
698                         &dwLength,
699                         NULL,
700                         NULL,
701                         NULL,
702                         NULL);
703 }
704
705
706 /************************************************************************
707  *  RegEnumKeyW
708  *
709  * @implemented
710  */
711 LONG STDCALL
712 RegEnumKeyW (HKEY hKey,
713              DWORD dwIndex,
714              LPWSTR lpName,
715              DWORD cbName)
716 {
717   DWORD dwLength;
718
719   dwLength = cbName;
720   return RegEnumKeyExW (hKey,
721                         dwIndex,
722                         lpName,
723                         &dwLength,
724                         NULL,
725                         NULL,
726                         NULL,
727                         NULL);
728 }
729
730
731 /************************************************************************
732  *  RegEnumKeyExA
733  *
734  * @implemented
735  */
736 LONG STDCALL
737 RegEnumKeyExA (HKEY hKey,
738                DWORD dwIndex,
739                LPSTR lpName,
740                LPDWORD lpcbName,
741                LPDWORD lpReserved,
742                LPSTR lpClass,
743                LPDWORD lpcbClass,
744                PFILETIME lpftLastWriteTime)
745 {
746   union
747   {
748     KEY_NODE_INFORMATION Node;
749     KEY_BASIC_INFORMATION Basic;
750   } *KeyInfo;
751
752   UNICODE_STRING StringU;
753   ANSI_STRING StringA;
754   LONG ErrorCode = ERROR_SUCCESS;
755   DWORD NameLength;
756   DWORD ClassLength;
757   DWORD BufferSize;
758   DWORD ResultSize;
759   HKEY KeyHandle;
760   NTSTATUS Status;
761
762   DPRINT("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
763          hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
764
765   if ((lpClass) && (!lpcbClass))
766     {
767       SetLastError (ERROR_INVALID_PARAMETER);
768       return ERROR_INVALID_PARAMETER;
769     }
770   Status = MapDefaultKey(&KeyHandle,
771                          hKey);
772   if (!NT_SUCCESS(Status))
773     {
774       ErrorCode = RtlNtStatusToDosError (Status);
775       SetLastError (ErrorCode);
776       return ErrorCode;
777     }
778
779   if (*lpcbName > 0)
780     {
781       NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
782     }
783   else
784     {
785       NameLength = 0;
786     }
787   if (lpClass)
788     {
789       if (*lpcbClass > 0)
790         {
791           ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
792         }
793       else
794         {
795           ClassLength = 0;
796         }
797       /* The class name should start at a dword boundary */
798       BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
799     }
800   else
801     {
802       BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
803     }
804   
805   KeyInfo = RtlAllocateHeap (ProcessHeap,
806                              0,
807                              BufferSize);
808   
809   if (KeyInfo == NULL)
810     {
811       SetLastError (ERROR_OUTOFMEMORY);
812       return ERROR_OUTOFMEMORY;
813     }
814
815   Status = NtEnumerateKey (KeyHandle,
816                            (ULONG)dwIndex,
817                            lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
818                            KeyInfo,
819                            BufferSize,
820                            &ResultSize);
821   DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
822   if (!NT_SUCCESS(Status))
823     {
824       ErrorCode = RtlNtStatusToDosError (Status);
825     }
826   else
827     {
828       if (lpClass == NULL)
829         {
830           if (KeyInfo->Basic.NameLength > NameLength)
831             {
832               ErrorCode = ERROR_BUFFER_OVERFLOW;
833             }
834           else
835             {
836               StringU.Buffer = KeyInfo->Basic.Name;
837               StringU.Length = KeyInfo->Basic.NameLength;
838               StringU.MaximumLength = KeyInfo->Basic.NameLength;
839             }
840         }
841       else
842         {
843           if (KeyInfo->Node.NameLength > NameLength ||
844               KeyInfo->Node.ClassLength > ClassLength)
845             {
846               ErrorCode = ERROR_BUFFER_OVERFLOW;
847             }
848           else
849             {
850               StringA.Buffer = lpClass;
851               StringA.Length = 0;
852               StringA.MaximumLength = *lpcbClass;
853               StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
854               StringU.Length = KeyInfo->Node.ClassLength;
855               StringU.MaximumLength = KeyInfo->Node.ClassLength;
856               RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
857               lpClass[StringA.Length] = 0;
858               *lpcbClass = StringA.Length;
859               StringU.Buffer = KeyInfo->Node.Name;
860               StringU.Length = KeyInfo->Node.NameLength;
861               StringU.MaximumLength = KeyInfo->Node.NameLength;
862             }
863         }
864       if (ErrorCode == ERROR_SUCCESS)
865         {
866           StringA.Buffer = lpName;
867           StringA.Length = 0;
868           StringA.MaximumLength = *lpcbName;
869           RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
870           lpName[StringA.Length] = 0;
871           *lpcbName = StringA.Length;
872           if (lpftLastWriteTime != NULL)
873             {
874               if (lpClass == NULL)
875                 {
876                   lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
877                   lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
878                 }
879               else
880                 {
881                   lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
882                   lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
883                 }
884             }
885         }
886     }
887
888   DPRINT("Key Namea0 Length %d\n", StringU.Length);
889   DPRINT("Key Namea1 Length %d\n", NameLength);
890   DPRINT("Key Namea Length %d\n", *lpcbName);
891   DPRINT("Key Namea %s\n", lpName);
892
893   RtlFreeHeap (ProcessHeap,
894                0,
895                KeyInfo);
896
897   if (ErrorCode != ERROR_SUCCESS)
898     {
899       SetLastError(ErrorCode);
900     }
901
902   return ErrorCode;
903 }
904
905
906 /************************************************************************
907  *  RegEnumKeyExW
908  *
909  * @implemented
910  */
911 LONG STDCALL
912 RegEnumKeyExW (HKEY hKey,
913                DWORD dwIndex,
914                LPWSTR lpName,
915                LPDWORD lpcbName,
916                LPDWORD lpReserved,
917                LPWSTR lpClass,
918                LPDWORD lpcbClass,
919                PFILETIME lpftLastWriteTime)
920 {
921   union
922   {
923     KEY_NODE_INFORMATION Node;
924     KEY_BASIC_INFORMATION Basic;
925   } *KeyInfo;
926
927   ULONG BufferSize;
928   ULONG ResultSize;
929   ULONG NameLength;
930   ULONG ClassLength;
931   HKEY KeyHandle;
932   LONG ErrorCode = ERROR_SUCCESS;
933   NTSTATUS Status;
934
935   Status = MapDefaultKey(&KeyHandle,
936                          hKey);
937   if (!NT_SUCCESS(Status))
938     {
939       ErrorCode = RtlNtStatusToDosError (Status);
940       SetLastError (ErrorCode);
941       return ErrorCode;
942     }
943   if (*lpcbName > 0)
944     {
945       NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
946     }
947   else
948     {
949       NameLength = 0;
950     }
951   if (lpClass)
952     {
953       if (*lpcbClass > 0)
954         {
955           ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
956         }
957       else
958         {
959           ClassLength = 0;
960         }
961       BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
962     }
963   else
964     {
965       BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
966     }
967   KeyInfo = RtlAllocateHeap (ProcessHeap,
968                              0,
969                              BufferSize);
970   if (KeyInfo == NULL)
971     {
972       SetLastError (ERROR_OUTOFMEMORY);
973       return ERROR_OUTOFMEMORY;
974     }
975
976   Status = NtEnumerateKey (KeyHandle,
977                            (ULONG)dwIndex,
978                            lpClass ? KeyNodeInformation : KeyBasicInformation,
979                            KeyInfo,
980                            BufferSize,
981                            &ResultSize);
982   DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
983   if (!NT_SUCCESS(Status))
984     {
985       ErrorCode = RtlNtStatusToDosError (Status);
986     }
987   else
988     {
989       if (lpClass == NULL)
990         {
991           if (KeyInfo->Basic.NameLength > NameLength)
992             {
993               ErrorCode = ERROR_BUFFER_OVERFLOW;
994             }
995           else
996             {
997               RtlCopyMemory (lpName,
998                              KeyInfo->Basic.Name,
999                              KeyInfo->Basic.NameLength);
1000               *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
1001               lpName[*lpcbName] = 0;
1002             }
1003         }
1004       else
1005         {
1006           if (KeyInfo->Node.NameLength > NameLength ||
1007               KeyInfo->Node.ClassLength > ClassLength)
1008             {
1009               ErrorCode = ERROR_BUFFER_OVERFLOW;
1010             }
1011           else
1012             {
1013               RtlCopyMemory (lpName,
1014                              KeyInfo->Node.Name,
1015                              KeyInfo->Node.NameLength);
1016               *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
1017               lpName[*lpcbName] = 0;
1018               RtlCopyMemory (lpClass,
1019                              (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
1020                              KeyInfo->Node.ClassLength);
1021               *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
1022               lpClass[*lpcbClass] = 0;
1023             }
1024         }
1025       if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
1026         {
1027           if (lpClass == NULL)
1028             {
1029               lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1030               lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1031             }
1032           else
1033             {
1034               lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1035               lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1036             }
1037         }
1038     }
1039
1040   RtlFreeHeap (ProcessHeap,
1041                0,
1042                KeyInfo);
1043
1044   if (ErrorCode != ERROR_SUCCESS)
1045     {
1046       SetLastError(ErrorCode);
1047     }
1048   return ErrorCode;
1049 }
1050
1051
1052 /************************************************************************
1053  *  RegEnumValueA
1054  *
1055  * @implemented
1056  */
1057 LONG STDCALL
1058 RegEnumValueA (HKEY hKey,
1059                DWORD dwIndex,
1060                LPSTR lpValueName,
1061                LPDWORD lpcbValueName,
1062                LPDWORD lpReserved,
1063                LPDWORD lpType,
1064                LPBYTE lpData,
1065                LPDWORD lpcbData)
1066 {
1067   union
1068   {
1069     KEY_VALUE_FULL_INFORMATION Full;
1070     KEY_VALUE_BASIC_INFORMATION Basic;
1071   } *ValueInfo;
1072
1073   ULONG NameLength;
1074   ULONG BufferSize;
1075   ULONG DataLength;
1076   ULONG ResultSize;
1077   HKEY KeyHandle;
1078   LONG ErrorCode;
1079   NTSTATUS Status;
1080   UNICODE_STRING StringU;
1081   ANSI_STRING StringA;
1082   BOOL IsStringType;
1083
1084   ErrorCode = ERROR_SUCCESS;
1085
1086   Status = MapDefaultKey (&KeyHandle,
1087                           hKey);
1088   if (!NT_SUCCESS(Status))
1089     {
1090       ErrorCode = RtlNtStatusToDosError (Status);
1091       SetLastError (ErrorCode);
1092       return ErrorCode;
1093     }
1094
1095   if (*lpcbValueName > 0)
1096     {
1097       NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1098     }
1099   else
1100     {
1101       NameLength = 0;
1102     }
1103   if (lpData)
1104     {
1105       DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
1106       BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
1107     }
1108   else
1109     {
1110       BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
1111     }
1112
1113   ValueInfo = RtlAllocateHeap (ProcessHeap,
1114                                0,
1115                                BufferSize);
1116   if (ValueInfo == NULL)
1117     {
1118       SetLastError(ERROR_OUTOFMEMORY);
1119       return ERROR_OUTOFMEMORY;
1120     }
1121
1122   Status = NtEnumerateValueKey (KeyHandle,
1123                                 (ULONG)dwIndex,
1124                                 lpData ? KeyValueFullInformation : KeyValueBasicInformation,
1125                                 ValueInfo,
1126                                 BufferSize,
1127                                 &ResultSize);
1128
1129   DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
1130   if (!NT_SUCCESS(Status))
1131     {
1132       ErrorCode = RtlNtStatusToDosError (Status);
1133     }
1134   else
1135     {
1136       if (lpData)
1137         {
1138           IsStringType = (ValueInfo->Full.Type == REG_SZ) || 
1139                          (ValueInfo->Full.Type == REG_MULTI_SZ) || 
1140                          (ValueInfo->Full.Type == REG_EXPAND_SZ);
1141           if (ValueInfo->Full.NameLength > NameLength ||
1142               (!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
1143               ValueInfo->Full.DataLength > DataLength)
1144             {
1145               ErrorCode = ERROR_BUFFER_OVERFLOW;
1146             }
1147           else
1148             {
1149               if (IsStringType)
1150                 {
1151                   StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
1152                   StringU.Length = ValueInfo->Full.DataLength;
1153                   StringU.MaximumLength = DataLength;
1154                   StringA.Buffer = (PCHAR)lpData;
1155                   StringA.Length = 0;
1156                   StringA.MaximumLength = *lpcbData;
1157                   RtlUnicodeStringToAnsiString (&StringA,
1158                                                 &StringU,
1159                                                 FALSE);
1160                   *lpcbData = StringA.Length;
1161                 }
1162               else
1163                 {
1164                   RtlCopyMemory(lpData,
1165                                 (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
1166                                 ValueInfo->Full.DataLength);
1167                   *lpcbData = ValueInfo->Full.DataLength;
1168                 }
1169               StringU.Buffer = ValueInfo->Full.Name;
1170               StringU.Length = ValueInfo->Full.NameLength;
1171               StringU.MaximumLength = NameLength;
1172             }
1173         }
1174       else
1175         {
1176           if (ValueInfo->Basic.NameLength > NameLength)
1177             {
1178               ErrorCode = ERROR_BUFFER_OVERFLOW;
1179             }
1180           else
1181             {
1182               StringU.Buffer = ValueInfo->Basic.Name;
1183               StringU.Length = ValueInfo->Basic.NameLength;
1184               StringU.MaximumLength = NameLength;
1185             }
1186         }
1187       if (ErrorCode == ERROR_SUCCESS)
1188         {
1189           StringA.Buffer = (PCHAR)lpValueName;
1190           StringA.Length = 0;
1191           StringA.MaximumLength = *lpcbValueName;
1192           RtlUnicodeStringToAnsiString (&StringA,
1193                                         &StringU,
1194                                         FALSE);
1195           StringA.Buffer[StringA.Length] = 0;
1196           *lpcbValueName = StringA.Length;
1197           if (lpType)
1198             {
1199               *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
1200             }
1201         }
1202     }
1203   RtlFreeHeap (ProcessHeap,
1204                0,
1205                ValueInfo);
1206   if (ErrorCode != ERROR_SUCCESS)
1207     {
1208       SetLastError(ErrorCode);
1209     }
1210   return ErrorCode;
1211 }
1212
1213
1214 /************************************************************************
1215  *  RegEnumValueW
1216  *
1217  * @implemented
1218  */
1219 LONG STDCALL
1220 RegEnumValueW (HKEY hKey,
1221                DWORD dwIndex,
1222                LPWSTR lpValueName,
1223                LPDWORD lpcbValueName,
1224                LPDWORD lpReserved,
1225                LPDWORD lpType,
1226                LPBYTE lpData,
1227                LPDWORD lpcbData)
1228 {
1229   union
1230   {
1231     KEY_VALUE_FULL_INFORMATION Full;
1232     KEY_VALUE_BASIC_INFORMATION Basic;
1233   } *ValueInfo;
1234
1235   ULONG NameLength;
1236   ULONG BufferSize;
1237   ULONG DataLength;
1238   ULONG ResultSize;
1239   HKEY KeyHandle;
1240   LONG ErrorCode;
1241   NTSTATUS Status;
1242     
1243   ErrorCode = ERROR_SUCCESS;
1244
1245   Status = MapDefaultKey (&KeyHandle,
1246                           hKey);
1247   if (!NT_SUCCESS(Status))
1248     {
1249       ErrorCode = RtlNtStatusToDosError (Status);
1250       SetLastError (ErrorCode);
1251       return ErrorCode;
1252     }
1253   
1254   if (*lpcbValueName > 0)
1255     {
1256       NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1257     }
1258   else
1259     {
1260       NameLength = 0;
1261     }
1262   if (lpData)
1263     {
1264       DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
1265       BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
1266     }
1267   else
1268     {
1269       BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
1270     }
1271   ValueInfo = RtlAllocateHeap (ProcessHeap,
1272                                0,
1273                                BufferSize);
1274   if (ValueInfo == NULL)
1275     {
1276       SetLastError (ERROR_OUTOFMEMORY);
1277       return ERROR_OUTOFMEMORY;
1278     }
1279   Status = NtEnumerateValueKey (KeyHandle,
1280                                 (ULONG)dwIndex,
1281                                 lpData ? KeyValueFullInformation : KeyValueBasicInformation,
1282                                 ValueInfo,
1283                                 BufferSize,
1284                                 &ResultSize);
1285
1286   DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
1287   if (!NT_SUCCESS(Status))
1288     {
1289       ErrorCode = RtlNtStatusToDosError (Status);
1290     }
1291   else
1292     {
1293       if (lpData)
1294         {
1295           if (ValueInfo->Full.DataLength > DataLength ||
1296               ValueInfo->Full.NameLength > NameLength)
1297             {
1298               ErrorCode = ERROR_BUFFER_OVERFLOW;
1299             }
1300           else
1301             {
1302               RtlCopyMemory (lpValueName,
1303                              ValueInfo->Full.Name,
1304                              ValueInfo->Full.NameLength);
1305               *lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
1306               lpValueName[*lpcbValueName] = 0;
1307               RtlCopyMemory (lpData,
1308                              (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
1309                              ValueInfo->Full.DataLength);
1310               *lpcbData = (DWORD)ValueInfo->Full.DataLength;
1311             }
1312         }
1313       else
1314         {
1315           if (ValueInfo->Basic.NameLength > NameLength)
1316             {
1317               ErrorCode = ERROR_BUFFER_OVERFLOW;
1318             }
1319           else
1320             {
1321               RtlCopyMemory (lpValueName,
1322                              ValueInfo->Basic.Name,
1323                              ValueInfo->Basic.NameLength);
1324               *lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
1325               lpValueName[*lpcbValueName] = 0;
1326             }
1327         }
1328       if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
1329         {
1330           *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
1331         }
1332     }
1333   RtlFreeHeap (ProcessHeap,
1334                0,
1335                ValueInfo);
1336   if (ErrorCode != ERROR_SUCCESS)
1337     {
1338       SetLastError(ErrorCode);
1339     }
1340   return ErrorCode;
1341 }
1342
1343
1344 /************************************************************************
1345  *  RegFlushKey
1346  *
1347  * @implemented
1348  */
1349 LONG STDCALL
1350 RegFlushKey(HKEY hKey)
1351 {
1352   HKEY KeyHandle;
1353   LONG ErrorCode;
1354   NTSTATUS Status;
1355
1356   if (hKey == HKEY_PERFORMANCE_DATA)
1357     {
1358       return ERROR_SUCCESS;
1359     }
1360
1361   Status = MapDefaultKey (&KeyHandle,
1362                           hKey);
1363   if (!NT_SUCCESS(Status))
1364     {
1365       ErrorCode = RtlNtStatusToDosError (Status);
1366       SetLastError (ErrorCode);
1367       return ErrorCode;
1368     }
1369
1370   Status = NtFlushKey (KeyHandle);
1371   if (!NT_SUCCESS(Status))
1372     {
1373       ErrorCode = RtlNtStatusToDosError (Status);
1374       SetLastError (ErrorCode);
1375       return ErrorCode;
1376     }
1377
1378   return ERROR_SUCCESS;
1379 }
1380
1381
1382 /************************************************************************
1383  *  RegGetKeySecurity
1384  *
1385  * @unimplemented
1386  */
1387 LONG STDCALL
1388 RegGetKeySecurity (HKEY hKey,
1389                    SECURITY_INFORMATION SecurityInformation,
1390                    PSECURITY_DESCRIPTOR pSecurityDescriptor,
1391                    LPDWORD lpcbSecurityDescriptor)
1392 {
1393 #if 0
1394   HKEY KeyHandle;
1395   LONG ErrorCode;
1396   NTSTATUS Status;
1397
1398   if (hKey = HKEY_PERFORMANCE_DATA)
1399     {
1400       return ERROR_INVALID_HANDLE;
1401     }
1402
1403   Status = MapDefaultKey (&KeyHandle,
1404                           hKey);
1405   if (!NT_SUCCESS(Status))
1406     {
1407       ErrorCode = RtlNtStatusToDosError (Status);
1408       SetLastError (ErrorCode);
1409       return ErrorCode;
1410     }
1411
1412   Status = NtQuerySecurityObject ()
1413   if (!NT_SUCCESS(Status))
1414     {
1415       ErrorCode = RtlNtStatusToDosError (Status);
1416       SetLastError (ErrorCode);
1417       return ErrorCode;
1418     }
1419
1420   return ERROR_SUCCESS;
1421 #endif
1422
1423   UNIMPLEMENTED;
1424   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1425   return ERROR_CALL_NOT_IMPLEMENTED;
1426 }
1427
1428
1429 /************************************************************************
1430  *  RegLoadKeyA
1431  *
1432  * @implemented
1433  */
1434 LONG STDCALL
1435 RegLoadKeyA (HKEY hKey,
1436              LPCSTR lpSubKey,
1437              LPCSTR lpFile)
1438 {
1439   UNICODE_STRING FileName;
1440   UNICODE_STRING KeyName;
1441   DWORD ErrorCode;
1442
1443   RtlCreateUnicodeStringFromAsciiz (&KeyName,
1444                                     (LPSTR)lpSubKey);
1445   RtlCreateUnicodeStringFromAsciiz (&FileName,
1446                                     (LPSTR)lpFile);
1447
1448   ErrorCode = RegLoadKeyW (hKey,
1449                            KeyName.Buffer,
1450                            FileName.Buffer);
1451
1452   RtlFreeUnicodeString (&FileName);
1453   RtlFreeUnicodeString (&KeyName);
1454
1455   return ErrorCode;
1456 }
1457
1458
1459 /************************************************************************
1460  *  RegLoadKeyW
1461  *
1462  * @implemented
1463  */
1464 LONG STDCALL
1465 RegLoadKeyW (HKEY hKey,
1466              LPCWSTR lpSubKey,
1467              LPCWSTR lpFile)
1468 {
1469   OBJECT_ATTRIBUTES FileObjectAttributes;
1470   OBJECT_ATTRIBUTES KeyObjectAttributes;
1471   UNICODE_STRING FileName;
1472   UNICODE_STRING KeyName;
1473   HANDLE KeyHandle;
1474   DWORD ErrorCode;
1475   NTSTATUS Status;
1476
1477   if (hKey == HKEY_PERFORMANCE_DATA)
1478     {
1479       return ERROR_INVALID_HANDLE;
1480     }
1481
1482   Status = MapDefaultKey (&KeyHandle,
1483                           hKey);
1484   if (!NT_SUCCESS(Status))
1485     {
1486       ErrorCode = RtlNtStatusToDosError (Status);
1487       SetLastError (ErrorCode);
1488       return ErrorCode;
1489     }
1490
1491   if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
1492                                      &FileName,
1493                                      NULL,
1494                                      NULL))
1495     {
1496       SetLastError (ERROR_BAD_PATHNAME);
1497       return ERROR_BAD_PATHNAME;
1498     }
1499
1500   InitializeObjectAttributes (&FileObjectAttributes,
1501                               &FileName,
1502                               OBJ_CASE_INSENSITIVE,
1503                               NULL,
1504                               NULL);
1505
1506   RtlInitUnicodeString (&KeyName,
1507                         (LPWSTR)lpSubKey);
1508
1509   InitializeObjectAttributes (&KeyObjectAttributes,
1510                               &KeyName,
1511                               OBJ_CASE_INSENSITIVE,
1512                               KeyHandle,
1513                               NULL);
1514
1515   Status = NtLoadKey (&KeyObjectAttributes,
1516                       &FileObjectAttributes);
1517
1518   RtlFreeUnicodeString (&FileName);
1519
1520   if (!NT_SUCCESS(Status))
1521     {
1522       ErrorCode = RtlNtStatusToDosError (Status);
1523       SetLastError (ErrorCode);
1524       return ErrorCode;
1525     }
1526
1527   return ERROR_SUCCESS;
1528 }
1529
1530
1531 /************************************************************************
1532  *  RegNotifyChangeKeyValue
1533  *
1534  * @unimplemented
1535  */
1536 LONG STDCALL
1537 RegNotifyChangeKeyValue (HKEY hKey,
1538                          BOOL bWatchSubtree,
1539                          DWORD dwNotifyFilter,
1540                          HANDLE hEvent,
1541                          BOOL fAsynchronous)
1542 {
1543   IO_STATUS_BLOCK IoStatusBlock;
1544   HANDLE KeyHandle;
1545   NTSTATUS Status;
1546
1547   if (hKey == HKEY_PERFORMANCE_DATA)
1548     {
1549       return ERROR_INVALID_HANDLE;
1550     }
1551
1552   if (fAsynchronous == TRUE && hEvent == NULL)
1553     {
1554       return ERROR_INVALID_PARAMETER;
1555     }
1556
1557   Status = MapDefaultKey (&KeyHandle,
1558                           hKey);
1559   if (!NT_SUCCESS(Status))
1560     {
1561       return RtlNtStatusToDosError (Status);
1562     }
1563
1564   /* FIXME: Remote key handles must fail */
1565
1566   Status = NtNotifyChangeKey (KeyHandle,
1567                               hEvent,
1568                               0,
1569                               0,
1570                               &IoStatusBlock,
1571                               dwNotifyFilter,
1572                               bWatchSubtree,
1573                               0,
1574                               0,
1575                               fAsynchronous);
1576   if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
1577     {
1578       return RtlNtStatusToDosError (Status);
1579     }
1580
1581   return ERROR_SUCCESS;
1582 }
1583
1584
1585
1586 /************************************************************************
1587  *  RegOpenKeyA
1588  *
1589  * @implemented
1590  */
1591 LONG STDCALL
1592 RegOpenKeyA (HKEY hKey,
1593              LPCSTR lpSubKey,
1594              PHKEY phkResult)
1595 {
1596   OBJECT_ATTRIBUTES ObjectAttributes;
1597   UNICODE_STRING SubKeyString;
1598   HKEY KeyHandle;
1599   LONG ErrorCode;
1600   NTSTATUS Status;
1601
1602   Status = MapDefaultKey (&KeyHandle,
1603                           hKey);
1604   if (!NT_SUCCESS(Status))
1605     {
1606       ErrorCode = RtlNtStatusToDosError (Status);
1607       SetLastError (ErrorCode);
1608       return ErrorCode;
1609     }
1610
1611   RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
1612                                     (LPSTR)lpSubKey);
1613   InitializeObjectAttributes (&ObjectAttributes,
1614                               &SubKeyString,
1615                               OBJ_CASE_INSENSITIVE,
1616                               KeyHandle,
1617                               NULL);
1618   Status = NtOpenKey (phkResult,
1619                       MAXIMUM_ALLOWED,
1620                       &ObjectAttributes);
1621   RtlFreeUnicodeString (&SubKeyString);
1622   if (!NT_SUCCESS(Status))
1623     {
1624       ErrorCode = RtlNtStatusToDosError (Status);
1625       SetLastError (ErrorCode);
1626       return ErrorCode;
1627     }
1628
1629   return ERROR_SUCCESS;
1630 }
1631
1632
1633 /************************************************************************
1634  *  RegOpenKeyW
1635  *
1636  *  19981101 Ariadne
1637  *  19990525 EA
1638  *
1639  * @implemented
1640  */
1641 LONG STDCALL
1642 RegOpenKeyW (HKEY hKey,
1643              LPCWSTR lpSubKey,
1644              PHKEY phkResult)
1645 {
1646   OBJECT_ATTRIBUTES ObjectAttributes;
1647   UNICODE_STRING SubKeyString;
1648   HKEY KeyHandle;
1649   LONG ErrorCode;
1650   NTSTATUS Status;
1651
1652   Status = MapDefaultKey (&KeyHandle,
1653                           hKey);
1654   if (!NT_SUCCESS(Status))
1655     {
1656       ErrorCode = RtlNtStatusToDosError (Status);
1657       SetLastError (ErrorCode);
1658       return ErrorCode;
1659     }
1660
1661   RtlInitUnicodeString (&SubKeyString,
1662                         (LPWSTR)lpSubKey);
1663   InitializeObjectAttributes (&ObjectAttributes,
1664                               &SubKeyString,
1665                               OBJ_CASE_INSENSITIVE,
1666                               KeyHandle,
1667                               NULL);
1668   Status = NtOpenKey (phkResult,
1669                       MAXIMUM_ALLOWED,
1670                       &ObjectAttributes);
1671   if (!NT_SUCCESS(Status))
1672     {
1673       ErrorCode = RtlNtStatusToDosError (Status);
1674       SetLastError(ErrorCode);
1675       return ErrorCode;
1676     }
1677
1678   return ERROR_SUCCESS;
1679 }
1680
1681
1682 /************************************************************************
1683  *  RegOpenKeyExA
1684  *
1685  * @implemented
1686  */
1687 LONG STDCALL
1688 RegOpenKeyExA (HKEY hKey,
1689                LPCSTR lpSubKey,
1690                DWORD ulOptions,
1691                REGSAM samDesired,
1692                PHKEY phkResult)
1693 {
1694   OBJECT_ATTRIBUTES ObjectAttributes;
1695   UNICODE_STRING SubKeyString;
1696   HKEY KeyHandle;
1697   LONG ErrorCode;
1698   NTSTATUS Status;
1699
1700   Status = MapDefaultKey (&KeyHandle,
1701                           hKey);
1702   if (!NT_SUCCESS(Status))
1703     {
1704       ErrorCode = RtlNtStatusToDosError (Status);
1705       SetLastError (ErrorCode);
1706       return ErrorCode;
1707     }
1708
1709   RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
1710                                     (LPSTR)lpSubKey);
1711   InitializeObjectAttributes (&ObjectAttributes,
1712                               &SubKeyString,
1713                               OBJ_CASE_INSENSITIVE,
1714                               KeyHandle,
1715                               NULL);
1716   Status = NtOpenKey (phkResult,
1717                       samDesired,
1718                       &ObjectAttributes);
1719   RtlFreeUnicodeString (&SubKeyString);
1720   if (!NT_SUCCESS(Status))
1721     {
1722       ErrorCode = RtlNtStatusToDosError (Status);
1723       SetLastError (ErrorCode);
1724       return ErrorCode;
1725    }
1726
1727   return ERROR_SUCCESS;
1728 }
1729
1730
1731 /************************************************************************
1732  *  RegOpenKeyExW
1733  *
1734  * @implemented
1735  */
1736 LONG STDCALL
1737 RegOpenKeyExW (HKEY hKey,
1738                LPCWSTR lpSubKey,
1739                DWORD ulOptions,
1740                REGSAM samDesired,
1741                PHKEY phkResult)
1742 {
1743   OBJECT_ATTRIBUTES ObjectAttributes;
1744   UNICODE_STRING SubKeyString;
1745   HKEY KeyHandle;
1746   LONG ErrorCode;
1747   NTSTATUS Status;
1748
1749   Status = MapDefaultKey (&KeyHandle,
1750                           hKey);
1751   if (!NT_SUCCESS(Status))
1752     {
1753       ErrorCode = RtlNtStatusToDosError (Status);
1754       SetLastError (ErrorCode);
1755       return ErrorCode;
1756     }
1757
1758   if (lpSubKey != NULL)
1759     {
1760       RtlInitUnicodeString (&SubKeyString,
1761                             (LPWSTR)lpSubKey);
1762     }
1763   else
1764     {
1765       RtlInitUnicodeString (&SubKeyString,
1766                             (LPWSTR)L"");
1767     }
1768   InitializeObjectAttributes (&ObjectAttributes,
1769                               &SubKeyString,
1770                               OBJ_CASE_INSENSITIVE,
1771                               KeyHandle,
1772                               NULL);
1773   Status = NtOpenKey (phkResult,
1774                       samDesired,
1775                       &ObjectAttributes);
1776   if (!NT_SUCCESS(Status))
1777     {
1778       ErrorCode = RtlNtStatusToDosError (Status);
1779       SetLastError (ErrorCode);
1780       return ErrorCode;
1781     }
1782
1783   return ERROR_SUCCESS;
1784 }
1785
1786
1787 /************************************************************************
1788  *  RegQueryInfoKeyA
1789  *
1790  * @implemented
1791  */
1792 LONG STDCALL
1793 RegQueryInfoKeyA (HKEY hKey,
1794                   LPSTR lpClass,
1795                   LPDWORD lpcbClass,
1796                   LPDWORD lpReserved,
1797                   LPDWORD lpcSubKeys,
1798                   LPDWORD lpcbMaxSubKeyLen,
1799                   LPDWORD lpcbMaxClassLen,
1800                   LPDWORD lpcValues,
1801                   LPDWORD lpcbMaxValueNameLen,
1802                   LPDWORD lpcbMaxValueLen,
1803                   LPDWORD lpcbSecurityDescriptor,
1804                   PFILETIME lpftLastWriteTime)
1805 {
1806   WCHAR ClassName[MAX_PATH];
1807   UNICODE_STRING UnicodeString;
1808   ANSI_STRING AnsiString;
1809   LONG ErrorCode;
1810
1811   RtlInitUnicodeString (&UnicodeString,
1812                         NULL);
1813   if (lpClass != NULL)
1814     {
1815       UnicodeString.Buffer = &ClassName[0];
1816       UnicodeString.MaximumLength = sizeof(ClassName);
1817       AnsiString.MaximumLength = *lpcbClass;
1818     }
1819
1820   ErrorCode = RegQueryInfoKeyW (hKey,
1821                                 UnicodeString.Buffer,
1822                                 lpcbClass,
1823                                 lpReserved,
1824                                 lpcSubKeys,
1825                                 lpcbMaxSubKeyLen,
1826                                 lpcbMaxClassLen,
1827                                 lpcValues,
1828                                 lpcbMaxValueNameLen,
1829                                 lpcbMaxValueLen,
1830                                 lpcbSecurityDescriptor,
1831                                 lpftLastWriteTime);
1832   if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
1833     {
1834       AnsiString.Buffer = lpClass;
1835       AnsiString.Length = 0;
1836       UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
1837       RtlUnicodeStringToAnsiString (&AnsiString,
1838                                     &UnicodeString,
1839                                     FALSE);
1840       *lpcbClass = AnsiString.Length;
1841       lpClass[AnsiString.Length] = 0;
1842     }
1843
1844   return ErrorCode;
1845 }
1846
1847
1848 /************************************************************************
1849  *  RegQueryInfoKeyW
1850  *
1851  * @implemented
1852  */
1853 LONG STDCALL
1854 RegQueryInfoKeyW (HKEY hKey,
1855                   LPWSTR lpClass,
1856                   LPDWORD lpcbClass,
1857                   LPDWORD lpReserved,
1858                   LPDWORD lpcSubKeys,
1859                   LPDWORD lpcbMaxSubKeyLen,
1860                   LPDWORD lpcbMaxClassLen,
1861                   LPDWORD lpcValues,
1862                   LPDWORD lpcbMaxValueNameLen,
1863                   LPDWORD lpcbMaxValueLen,
1864                   LPDWORD lpcbSecurityDescriptor,
1865                   PFILETIME lpftLastWriteTime)
1866 {
1867   KEY_FULL_INFORMATION FullInfoBuffer;
1868   PKEY_FULL_INFORMATION FullInfo;
1869   ULONG FullInfoSize;
1870   ULONG ClassLength;
1871   HKEY KeyHandle;
1872   NTSTATUS Status;
1873   LONG ErrorCode = ERROR_SUCCESS;
1874   ULONG Length;
1875
1876   if ((lpClass) && (!lpcbClass))
1877     {
1878       SetLastError(ERROR_INVALID_PARAMETER);
1879       return ERROR_INVALID_PARAMETER;
1880     }
1881
1882   Status = MapDefaultKey (&KeyHandle,
1883                           hKey);
1884   if (!NT_SUCCESS(Status))
1885     {
1886       ErrorCode = RtlNtStatusToDosError (Status);
1887       SetLastError (ErrorCode);
1888       return ErrorCode;
1889     }
1890
1891   if (lpClass != NULL)
1892     {
1893       if (*lpcbClass > 0)
1894         {
1895           ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1896         }
1897       else
1898         { 
1899           ClassLength = 0;
1900         }
1901       FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
1902       FullInfo = RtlAllocateHeap (ProcessHeap,
1903                                   0,
1904                                   FullInfoSize);
1905       if (FullInfo == NULL)
1906         {
1907           SetLastError (ERROR_OUTOFMEMORY);
1908           return ERROR_OUTOFMEMORY;
1909         }
1910       FullInfo->ClassLength = ClassLength;
1911     }
1912   else
1913     {
1914       FullInfoSize = sizeof(KEY_FULL_INFORMATION);
1915       FullInfo = &FullInfoBuffer;
1916       FullInfo->ClassLength = 0;
1917     }
1918   FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
1919
1920   Status = NtQueryKey (KeyHandle,
1921                        KeyFullInformation,
1922                        FullInfo,
1923                        FullInfoSize,
1924                        &Length);
1925   DPRINT("NtQueryKey() returned status 0x%X\n", Status);
1926   if (!NT_SUCCESS(Status))
1927     {
1928       ErrorCode = RtlNtStatusToDosError (Status);
1929     }
1930   else
1931     {
1932       DPRINT("SubKeys %d\n", FullInfo->SubKeys);
1933       if (lpcSubKeys != NULL)
1934         {
1935           *lpcSubKeys = FullInfo->SubKeys;
1936         }
1937
1938       DPRINT("MaxNameLen %lu\n", FullInfo->MaxNameLen);
1939       if (lpcbMaxSubKeyLen != NULL)
1940         {
1941           *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
1942         }
1943
1944       DPRINT("MaxClassLen %lu\n", FullInfo->MaxClassLen);
1945       if (lpcbMaxClassLen != NULL)
1946         {
1947           *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
1948         }
1949
1950       DPRINT("Values %lu\n", FullInfo->Values);
1951       if (lpcValues)
1952         {
1953           *lpcValues = FullInfo->Values;
1954         }
1955
1956       DPRINT("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
1957       if (lpcbMaxValueNameLen)
1958         {
1959           *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
1960         }
1961
1962       DPRINT("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
1963       if (lpcbMaxValueLen)
1964         {
1965           *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
1966         }
1967
1968       if (lpcbSecurityDescriptor)
1969         {
1970           *lpcbSecurityDescriptor = 0;
1971           /* FIXME */
1972         }
1973
1974       if (lpftLastWriteTime != NULL)
1975         {
1976           lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
1977           lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
1978         }
1979
1980       if (lpClass != NULL)
1981         {
1982           if (FullInfo->ClassLength > ClassLength)
1983             {
1984               ErrorCode = ERROR_BUFFER_OVERFLOW;
1985             }
1986           else
1987             {
1988               RtlCopyMemory (lpClass,
1989                              FullInfo->Class,
1990                              FullInfo->ClassLength);
1991               *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
1992               lpClass[*lpcbClass] = 0;
1993             }
1994         }
1995     }
1996   if (lpClass != NULL)
1997     {
1998       RtlFreeHeap (ProcessHeap,
1999                    0,
2000                    FullInfo);
2001     }
2002   if (ErrorCode != ERROR_SUCCESS)
2003     {
2004       SetLastError(ErrorCode);
2005     }
2006
2007   return ErrorCode;
2008 }
2009
2010
2011 /************************************************************************
2012  *  RegQueryMultipleValuesA
2013  *
2014  * @unimplemented
2015  */
2016 LONG STDCALL
2017 RegQueryMultipleValuesA (HKEY hKey,
2018                          PVALENTA val_list,
2019                          DWORD num_vals,
2020                          LPSTR lpValueBuf,
2021                          LPDWORD ldwTotsize)
2022 {
2023   UNIMPLEMENTED;
2024   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2025   return ERROR_CALL_NOT_IMPLEMENTED;
2026 }
2027
2028
2029 /************************************************************************
2030  *  RegQueryMultipleValuesW
2031  *
2032  * @implemented
2033  */
2034 LONG STDCALL
2035 RegQueryMultipleValuesW (HKEY hKey,
2036                          PVALENTW val_list,
2037                          DWORD num_vals,
2038                          LPWSTR lpValueBuf,
2039                          LPDWORD ldwTotsize)
2040 {
2041   ULONG i;
2042   DWORD maxBytes = *ldwTotsize;
2043   HRESULT status;
2044   LPSTR bufptr = (LPSTR)lpValueBuf;
2045
2046   if ( maxBytes >= (1024*1024) )
2047     return ERROR_TRANSFER_TOO_LONG;
2048
2049   *ldwTotsize = 0;
2050
2051   //TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2052
2053   for(i=0; i < num_vals; ++i)
2054     {
2055       val_list[i].ve_valuelen=0;
2056       status = RegQueryValueExW(hKey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
2057       if(status != ERROR_SUCCESS)
2058         {
2059           return status;
2060         }
2061
2062       if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2063         {
2064           status = RegQueryValueExW(hKey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
2065                                     bufptr, &val_list[i].ve_valuelen);
2066           if(status != ERROR_SUCCESS)
2067             {
2068               return status;
2069             }
2070
2071           val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2072
2073           bufptr += val_list[i].ve_valuelen;
2074         }
2075
2076       *ldwTotsize += val_list[i].ve_valuelen;
2077     }
2078   return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
2079 }
2080
2081
2082 /************************************************************************
2083  *  RegQueryValueExW
2084  *
2085  * @implemented
2086  */
2087 LONG STDCALL
2088 RegQueryValueExW (HKEY hKey,
2089                   LPCWSTR lpValueName,
2090                   LPDWORD lpReserved,
2091                   LPDWORD lpType,
2092                   LPBYTE lpData,
2093                   LPDWORD lpcbData)
2094 {
2095   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
2096   UNICODE_STRING ValueName;
2097   NTSTATUS Status;
2098   LONG ErrorCode = ERROR_SUCCESS;
2099   ULONG BufferSize;
2100   ULONG ResultSize;
2101   HKEY KeyHandle;
2102
2103   DPRINT("hKey 0x%X  lpValueName %S  lpData 0x%X  lpcbData %d\n",
2104          hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
2105
2106   Status = MapDefaultKey (&KeyHandle,
2107                           hKey);
2108   if (!NT_SUCCESS(Status))
2109     {
2110       ErrorCode = RtlNtStatusToDosError (Status);
2111       SetLastError (ErrorCode);
2112       return ErrorCode;
2113     }
2114
2115   if (lpData != NULL && lpcbData == NULL)
2116     {
2117       SetLastError (ERROR_INVALID_PARAMETER);
2118       return ERROR_INVALID_PARAMETER;
2119     }
2120
2121   RtlInitUnicodeString (&ValueName,
2122                         lpValueName);
2123   BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + *lpcbData;
2124   ValueInfo = RtlAllocateHeap (ProcessHeap,
2125                                0,
2126                                BufferSize);
2127   if (ValueInfo == NULL)
2128     {
2129       SetLastError(ERROR_OUTOFMEMORY);
2130       return ERROR_OUTOFMEMORY;
2131     }
2132
2133   Status = NtQueryValueKey (hKey,
2134                             &ValueName,
2135                             KeyValuePartialInformation,
2136                             ValueInfo,
2137                             BufferSize,
2138                             &ResultSize);
2139   DPRINT("Status 0x%X\n", Status);
2140   if (Status == STATUS_BUFFER_TOO_SMALL)
2141     {
2142       /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
2143       ErrorCode = ERROR_SUCCESS;
2144     }
2145   else if (!NT_SUCCESS(Status))
2146     {
2147       ErrorCode = RtlNtStatusToDosError (Status);
2148       SetLastError (ErrorCode);
2149     }
2150   else
2151     {
2152       if (lpType != NULL)
2153         {
2154           *lpType = ValueInfo->Type;
2155         }
2156       RtlMoveMemory (lpData,
2157                      ValueInfo->Data,
2158                      ValueInfo->DataLength);
2159       if ((ValueInfo->Type == REG_SZ) ||
2160           (ValueInfo->Type == REG_MULTI_SZ) ||
2161           (ValueInfo->Type == REG_EXPAND_SZ))
2162         {
2163           ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
2164         }
2165     }
2166   DPRINT("Type %d  Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
2167
2168   if (NULL != lpcbData)
2169     {
2170       *lpcbData = (DWORD)ValueInfo->DataLength;
2171     }
2172   RtlFreeHeap (ProcessHeap,
2173                0,
2174                ValueInfo);
2175
2176   return ErrorCode;
2177 }
2178
2179
2180 /************************************************************************
2181  *  RegQueryValueExA
2182  *
2183  * @unimplemented
2184  */
2185 LONG
2186 STDCALL
2187 RegQueryValueExA(
2188   HKEY  hKey,
2189   LPCSTR  lpValueName,
2190   LPDWORD lpReserved,
2191   LPDWORD lpType,
2192   LPBYTE  lpData,
2193   LPDWORD lpcbData)
2194 {
2195   WCHAR ValueNameBuffer[MAX_PATH+1];
2196   UNICODE_STRING ValueName;
2197   UNICODE_STRING ValueData;
2198   ANSI_STRING AnsiString;
2199   LONG ErrorCode;
2200   DWORD ResultSize;
2201   DWORD Type;
2202
2203   /* FIXME: HKEY_PERFORMANCE_DATA is special, see MS SDK */
2204
2205   if ((lpData) && (!lpcbData)) {
2206     SetLastError(ERROR_INVALID_PARAMETER);
2207     return ERROR_INVALID_PARAMETER;
2208   }
2209   RtlInitUnicodeString(&ValueData, NULL);
2210   if (lpData) {
2211     ValueData.MaximumLength = *lpcbData * sizeof(WCHAR);
2212     ValueData.Buffer = RtlAllocateHeap(
2213       ProcessHeap,
2214       0,
2215       ValueData.MaximumLength);
2216     if (!ValueData.Buffer) {
2217       SetLastError(ERROR_OUTOFMEMORY);
2218       return ERROR_OUTOFMEMORY;
2219     }
2220   }
2221   RtlInitAnsiString(&AnsiString, (LPSTR)lpValueName);
2222   RtlInitUnicodeString(&ValueName, NULL);
2223   ValueName.Buffer = &ValueNameBuffer[0];
2224   ValueName.MaximumLength = sizeof(ValueNameBuffer);
2225   RtlAnsiStringToUnicodeString(&ValueName, &AnsiString, FALSE);
2226   if (lpcbData) {
2227     ResultSize = *lpcbData;
2228   } else {
2229     ResultSize = 0;
2230   }
2231   ErrorCode = RegQueryValueExW(
2232     hKey,
2233     ValueName.Buffer,
2234     lpReserved,
2235     &Type,
2236     (LPBYTE)ValueData.Buffer,
2237     &ResultSize);
2238   if ((ErrorCode == ERROR_SUCCESS) && (ValueData.Buffer != NULL)) {
2239     if (lpType) {
2240       *lpType = Type;
2241     }
2242     if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ)) {
2243       ValueData.Length = ResultSize;
2244       RtlInitAnsiString(&AnsiString, NULL);
2245       AnsiString.Buffer = lpData;
2246       AnsiString.MaximumLength = *lpcbData;
2247       RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
2248     } else {
2249       RtlMoveMemory(lpData, ValueData.Buffer, ResultSize);
2250     }
2251   }
2252   if (lpcbData) {
2253     *lpcbData = ResultSize;
2254   }
2255   if (ValueData.Buffer) {
2256     RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
2257   }
2258   return ErrorCode;
2259 }
2260
2261
2262 /************************************************************************
2263  *  RegQueryValueA
2264  *
2265  * @implemented
2266  */
2267 LONG STDCALL
2268 RegQueryValueA (HKEY hKey,
2269                 LPCSTR lpSubKey,
2270                 LPSTR lpValue,
2271                 PLONG lpcbValue)
2272 {
2273   WCHAR SubKeyNameBuffer[MAX_PATH+1];
2274   UNICODE_STRING SubKeyName;
2275   UNICODE_STRING Value;
2276   ANSI_STRING AnsiString;
2277   LONG ValueSize;
2278   LONG ErrorCode;
2279
2280   if (lpValue != NULL &&
2281       lpcbValue == NULL)
2282     {
2283       SetLastError(ERROR_INVALID_PARAMETER);
2284       return ERROR_INVALID_PARAMETER;
2285     }
2286
2287   RtlInitUnicodeString (&SubKeyName,
2288                         NULL);
2289   RtlInitUnicodeString (&Value,
2290                         NULL);
2291   if (lpSubKey != NULL &&
2292       strlen(lpSubKey) != 0)
2293     {
2294       RtlInitAnsiString (&AnsiString,
2295                          (LPSTR)lpSubKey);
2296       SubKeyName.Buffer = &SubKeyNameBuffer[0];
2297       SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
2298       RtlAnsiStringToUnicodeString (&SubKeyName,
2299                                     &AnsiString,
2300                                     FALSE);
2301     }
2302
2303   if (lpValue != NULL)
2304     {
2305       ValueSize = *lpcbValue * sizeof(WCHAR);
2306       Value.MaximumLength = ValueSize;
2307       Value.Buffer = RtlAllocateHeap (ProcessHeap,
2308                                       0,
2309                                       ValueSize);
2310       if (Value.Buffer == NULL)
2311         {
2312           SetLastError(ERROR_OUTOFMEMORY);
2313           return ERROR_OUTOFMEMORY;
2314         }
2315     }
2316   else
2317     {
2318       ValueSize = 0;
2319     }
2320
2321   ErrorCode = RegQueryValueW (hKey,
2322                               (LPCWSTR)SubKeyName.Buffer,
2323                               Value.Buffer,
2324                               &ValueSize);
2325   if (ErrorCode == ERROR_SUCCESS)
2326     {
2327       Value.Length = ValueSize;
2328       RtlInitAnsiString (&AnsiString,
2329                          NULL);
2330       AnsiString.Buffer = lpValue;
2331       AnsiString.MaximumLength = *lpcbValue;
2332       RtlUnicodeStringToAnsiString (&AnsiString,
2333                                     &Value,
2334                                     FALSE);
2335     }
2336
2337   *lpcbValue = ValueSize;
2338   if (Value.Buffer != NULL)
2339     {
2340       RtlFreeHeap (ProcessHeap,
2341                    0,
2342                    Value.Buffer);
2343     }
2344
2345   return ErrorCode;
2346 }
2347
2348
2349 /************************************************************************
2350  *  RegQueryValueW
2351  *
2352  * @implemented
2353  */
2354 LONG STDCALL
2355 RegQueryValueW (HKEY hKey,
2356                 LPCWSTR lpSubKey,
2357                 LPWSTR lpValue,
2358                 PLONG lpcbValue)
2359 {
2360   OBJECT_ATTRIBUTES ObjectAttributes;
2361   UNICODE_STRING SubKeyString;
2362   HKEY KeyHandle;
2363   HANDLE RealKey;
2364   LONG ErrorCode;
2365   BOOL CloseRealKey;
2366   NTSTATUS Status;
2367
2368   Status = MapDefaultKey (&KeyHandle,
2369                           hKey);
2370   if (!NT_SUCCESS(Status))
2371     {
2372       ErrorCode = RtlNtStatusToDosError (Status);
2373       SetLastError (ErrorCode);
2374       return ErrorCode;
2375     }
2376
2377   if (lpSubKey != NULL &&
2378       wcslen(lpSubKey) != 0)
2379     {
2380       RtlInitUnicodeString (&SubKeyString,
2381                             (LPWSTR)lpSubKey);
2382       InitializeObjectAttributes (&ObjectAttributes,
2383                                   &SubKeyString,
2384                                   OBJ_CASE_INSENSITIVE,
2385                                   KeyHandle,
2386                                   NULL);
2387       Status = NtOpenKey (&RealKey,
2388                           KEY_ALL_ACCESS,
2389                           &ObjectAttributes);
2390       if (!NT_SUCCESS(Status))
2391         {
2392           ErrorCode = RtlNtStatusToDosError (Status);
2393           SetLastError (ErrorCode);
2394           return ErrorCode;
2395         }
2396       CloseRealKey = TRUE;
2397     }
2398   else
2399     {
2400       RealKey = hKey;
2401       CloseRealKey = FALSE;
2402     }
2403
2404   ErrorCode = RegQueryValueExW (RealKey,
2405                                 NULL,
2406                                 NULL,
2407                                 NULL,
2408                                 (LPBYTE)lpValue,
2409                                 (LPDWORD)lpcbValue);
2410   if (CloseRealKey)
2411     {
2412       NtClose (RealKey);
2413     }
2414
2415   return ErrorCode;
2416 }
2417
2418
2419 /************************************************************************
2420  *  RegReplaceKeyA
2421  *
2422  * @implemented
2423  */
2424 LONG STDCALL
2425 RegReplaceKeyA (HKEY hKey,
2426                 LPCSTR lpSubKey,
2427                 LPCSTR lpNewFile,
2428                 LPCSTR lpOldFile)
2429 {
2430   UNICODE_STRING lpSubKeyW;
2431   UNICODE_STRING lpNewFileW;
2432   UNICODE_STRING lpOldFileW;
2433   LONG ret;
2434
2435   RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, (PCSZ)lpSubKey );
2436   RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, (PCSZ)lpOldFile );
2437   RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, (PCSZ)lpNewFile );
2438   ret = RegReplaceKeyW( hKey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2439   RtlFreeUnicodeString( &lpOldFileW );
2440   RtlFreeUnicodeString( &lpNewFileW );
2441   RtlFreeUnicodeString( &lpSubKeyW );
2442   return ret;
2443 }
2444
2445
2446 /************************************************************************
2447  *  RegReplaceKeyW
2448  *
2449  * @unimplemented
2450  */
2451 LONG STDCALL
2452 RegReplaceKeyW (HKEY hKey,
2453                 LPCWSTR lpSubKey,
2454                 LPCWSTR lpNewFile,
2455                 LPCWSTR lpOldFile)
2456 {
2457   UNIMPLEMENTED;
2458   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2459   return ERROR_CALL_NOT_IMPLEMENTED;
2460 }
2461
2462
2463 /************************************************************************
2464  *  RegRestoreKeyA
2465  *
2466  * @implemented
2467  */
2468 LONG STDCALL
2469 RegRestoreKeyA (HKEY hKey,
2470                 LPCSTR lpFile,
2471                 DWORD dwFlags)
2472 {
2473   UNICODE_STRING lpFileW;
2474   LONG ret;
2475
2476   RtlCreateUnicodeStringFromAsciiz( &lpFileW, (PCSZ)lpFile );
2477   ret = RegRestoreKeyW( hKey, lpFileW.Buffer, dwFlags );
2478   RtlFreeUnicodeString( &lpFileW );
2479   return ret;
2480 }
2481
2482
2483 /************************************************************************
2484  *  RegRestoreKeyW
2485  *
2486  * @unimplemented
2487  */
2488 LONG STDCALL
2489 RegRestoreKeyW (HKEY hKey,
2490                 LPCWSTR lpFile,
2491                 DWORD dwFlags)
2492 {
2493   UNIMPLEMENTED;
2494   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2495   return ERROR_CALL_NOT_IMPLEMENTED;
2496 }
2497
2498
2499 /************************************************************************
2500  *  RegSaveKeyA
2501  *
2502  * @implemented
2503  */
2504 LONG STDCALL
2505 RegSaveKeyA(HKEY hKey,
2506             LPCSTR lpFile,
2507             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2508 {
2509   UNICODE_STRING FileName;
2510   LONG ErrorCode;
2511
2512   RtlCreateUnicodeStringFromAsciiz (&FileName,
2513                                     (LPSTR)lpFile);
2514   ErrorCode = RegSaveKeyW (hKey,
2515                            FileName.Buffer,
2516                            lpSecurityAttributes);
2517   RtlFreeUnicodeString (&FileName);
2518
2519   return ErrorCode;
2520 }
2521
2522
2523 /************************************************************************
2524  *  RegSaveKeyW
2525  *
2526  * @implemented
2527  */
2528 LONG STDCALL
2529 RegSaveKeyW (HKEY hKey,
2530              LPCWSTR lpFile,
2531              LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2532 {
2533   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
2534   OBJECT_ATTRIBUTES ObjectAttributes;
2535   UNICODE_STRING NtName;
2536   IO_STATUS_BLOCK IoStatusBlock;
2537   HANDLE FileHandle;
2538   HKEY KeyHandle;
2539   NTSTATUS Status;
2540   LONG ErrorCode;
2541
2542   Status = MapDefaultKey (&KeyHandle,
2543                           hKey);
2544   if (!NT_SUCCESS(Status))
2545     {
2546       ErrorCode = RtlNtStatusToDosError (Status);
2547       SetLastError (ErrorCode);
2548       return ErrorCode;
2549     }
2550
2551   if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
2552                                      &NtName,
2553                                      NULL,
2554                                      NULL))
2555     {
2556       SetLastError (ERROR_INVALID_PARAMETER);
2557       return ERROR_INVALID_PARAMETER;
2558     }
2559
2560   if (lpSecurityAttributes != NULL)
2561     {
2562       SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
2563     }
2564
2565   InitializeObjectAttributes (&ObjectAttributes,
2566                               &NtName,
2567                               OBJ_CASE_INSENSITIVE,
2568                               NULL,
2569                               SecurityDescriptor);
2570   Status = NtCreateFile (&FileHandle,
2571                          GENERIC_WRITE | SYNCHRONIZE,
2572                          &ObjectAttributes,
2573                          &IoStatusBlock,
2574                          NULL,
2575                          FILE_ATTRIBUTE_NORMAL,
2576                          FILE_SHARE_READ,
2577                          FILE_CREATE,
2578                          FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
2579                          NULL,
2580                          0);
2581   RtlFreeUnicodeString (&NtName);
2582   if (!NT_SUCCESS(Status))
2583     {
2584       ErrorCode = RtlNtStatusToDosError (Status);
2585       SetLastError (ErrorCode);
2586       return ErrorCode;
2587     }
2588
2589   Status = NtSaveKey (KeyHandle,
2590                       FileHandle);
2591   NtClose (FileHandle);
2592   if (!NT_SUCCESS(Status))
2593     {
2594       ErrorCode = RtlNtStatusToDosError (Status);
2595       SetLastError (ErrorCode);
2596       return ErrorCode;
2597     }
2598
2599   return ERROR_SUCCESS;
2600 }
2601
2602
2603 /************************************************************************
2604  *  RegSetKeySecurity
2605  *
2606  * @implemented
2607  */
2608 LONG STDCALL
2609 RegSetKeySecurity (HKEY hKey,
2610                    SECURITY_INFORMATION SecurityInformation,
2611                    PSECURITY_DESCRIPTOR pSecurityDescriptor)
2612 {
2613   HKEY KeyHandle;
2614   NTSTATUS Status;
2615   LONG ErrorCode;
2616
2617   if (hKey == HKEY_PERFORMANCE_DATA)
2618     return ERROR_INVALID_HANDLE;
2619
2620   Status = MapDefaultKey (&KeyHandle,
2621                           hKey);
2622   if (!NT_SUCCESS(Status))
2623     {
2624       ErrorCode = RtlNtStatusToDosError (Status);
2625       SetLastError (ErrorCode);
2626       return ErrorCode;
2627     }
2628
2629   Status = NtSetSecurityObject (KeyHandle,
2630                                 SecurityInformation,
2631                                 pSecurityDescriptor);
2632   if (!NT_SUCCESS(Status))
2633     {
2634       ErrorCode = RtlNtStatusToDosError (Status);
2635       SetLastError (ErrorCode);
2636       return ErrorCode;
2637     }
2638
2639   return ERROR_SUCCESS;
2640 }
2641
2642
2643 /************************************************************************
2644  *  RegSetValueExA
2645  *
2646  * @implemented
2647  */
2648 LONG STDCALL
2649 RegSetValueExA (HKEY hKey,
2650                 LPCSTR lpValueName,
2651                 DWORD Reserved,
2652                 DWORD dwType,
2653                 CONST BYTE* lpData,
2654                 DWORD cbData)
2655 {
2656   UNICODE_STRING ValueName;
2657   LPWSTR pValueName;
2658   ANSI_STRING AnsiString;
2659   UNICODE_STRING Data;
2660   LONG ErrorCode;
2661   LPBYTE pData;
2662   DWORD DataSize;
2663
2664   if (lpData == NULL)
2665     {
2666       SetLastError (ERROR_INVALID_PARAMETER);
2667       return ERROR_INVALID_PARAMETER;
2668     }
2669
2670   if (lpValueName != NULL &&
2671       strlen(lpValueName) != 0)
2672     {
2673       RtlCreateUnicodeStringFromAsciiz (&ValueName,
2674                                         (LPSTR)lpValueName);
2675       pValueName = (LPWSTR)ValueName.Buffer;
2676     }
2677   else
2678     {
2679       pValueName = NULL;
2680     }
2681
2682   if ((dwType == REG_SZ) ||
2683       (dwType == REG_MULTI_SZ) ||
2684       (dwType == REG_EXPAND_SZ))
2685     {
2686       RtlInitAnsiString (&AnsiString,
2687                          NULL);
2688       AnsiString.Buffer = (LPSTR)lpData;
2689       AnsiString.Length = cbData;
2690       AnsiString.MaximumLength = cbData;
2691       RtlAnsiStringToUnicodeString (&Data,
2692                                     &AnsiString,
2693                                     TRUE);
2694       pData = (LPBYTE)Data.Buffer;
2695       DataSize = cbData * sizeof(WCHAR);
2696     }
2697   else
2698     {
2699       RtlInitUnicodeString (&Data,
2700                             NULL);
2701       pData = (LPBYTE)lpData;
2702       DataSize = cbData;
2703     }
2704
2705   ErrorCode = RegSetValueExW (hKey,
2706                               pValueName,
2707                               Reserved,
2708                               dwType,
2709                               pData,
2710                               DataSize);
2711   if (pValueName != NULL)
2712     {
2713       RtlFreeHeap (ProcessHeap,
2714                    0,
2715                    ValueName.Buffer);
2716     }
2717
2718   if (Data.Buffer != NULL)
2719     {
2720       RtlFreeHeap (ProcessHeap,
2721                    0,
2722                    Data.Buffer);
2723     }
2724
2725   return ErrorCode;
2726 }
2727
2728
2729 /************************************************************************
2730  *  RegSetValueExW
2731  *
2732  * @implemented
2733  */
2734 LONG STDCALL
2735 RegSetValueExW (HKEY hKey,
2736                 LPCWSTR lpValueName,
2737                 DWORD Reserved,
2738                 DWORD dwType,
2739                 CONST BYTE* lpData,
2740                 DWORD cbData)
2741 {
2742   UNICODE_STRING ValueName;
2743   PUNICODE_STRING pValueName;
2744   HKEY KeyHandle;
2745   NTSTATUS Status;
2746   LONG ErrorCode;
2747
2748   Status = MapDefaultKey (&KeyHandle,
2749                           hKey);
2750   if (!NT_SUCCESS(Status))
2751     {
2752       ErrorCode = RtlNtStatusToDosError (Status);
2753       SetLastError (ErrorCode);
2754       return ErrorCode;
2755     }
2756
2757   if (lpValueName != NULL)
2758     {
2759       RtlInitUnicodeString (&ValueName,
2760                             lpValueName);
2761       pValueName = &ValueName;
2762     }
2763   else
2764     {
2765       pValueName = NULL;
2766     }
2767
2768   Status = NtSetValueKey (KeyHandle,
2769                           pValueName,
2770                           0,
2771                           dwType,
2772                           (PVOID)lpData,
2773                           (ULONG)cbData);
2774   if (!NT_SUCCESS(Status))
2775     {
2776       ErrorCode = RtlNtStatusToDosError (Status);
2777       SetLastError (ErrorCode);
2778       return ErrorCode;
2779     }
2780
2781   return ERROR_SUCCESS;
2782 }
2783
2784
2785 /************************************************************************
2786  *  RegSetValueA
2787  *
2788  * @implemented
2789  */
2790 LONG STDCALL
2791 RegSetValueA (HKEY hKey,
2792               LPCSTR lpSubKey,
2793               DWORD dwType,
2794               LPCSTR lpData,
2795               DWORD cbData)
2796 {
2797   WCHAR SubKeyNameBuffer[MAX_PATH+1];
2798   UNICODE_STRING SubKeyName;
2799   UNICODE_STRING Data;
2800   ANSI_STRING AnsiString;
2801   LONG DataSize;
2802   LONG ErrorCode;
2803
2804   if (lpData == NULL)
2805     {
2806       SetLastError (ERROR_INVALID_PARAMETER);
2807       return ERROR_INVALID_PARAMETER;
2808     }
2809
2810   RtlInitUnicodeString (&SubKeyName, NULL);
2811   RtlInitUnicodeString (&Data, NULL);
2812   if (lpSubKey != NULL && (strlen(lpSubKey) != 0))
2813     {
2814       RtlInitAnsiString (&AnsiString, (LPSTR)lpSubKey);
2815       SubKeyName.Buffer = &SubKeyNameBuffer[0];
2816       SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
2817       RtlAnsiStringToUnicodeString (&SubKeyName, &AnsiString, FALSE);
2818     }
2819
2820   DataSize = cbData * sizeof(WCHAR);
2821   Data.MaximumLength = DataSize;
2822   Data.Buffer = RtlAllocateHeap (ProcessHeap,
2823                                  0,
2824                                  DataSize);
2825   if (Data.Buffer == NULL)
2826     {
2827       SetLastError (ERROR_OUTOFMEMORY);
2828       return ERROR_OUTOFMEMORY;
2829     }
2830
2831   ErrorCode = RegSetValueW (hKey,
2832                             (LPCWSTR)SubKeyName.Buffer,
2833                             dwType,
2834                             Data.Buffer,
2835                             DataSize);
2836   RtlFreeHeap (ProcessHeap,
2837                0,
2838                Data.Buffer);
2839
2840   return ErrorCode;
2841 }
2842
2843
2844 /************************************************************************
2845  *  RegSetValueW
2846  *
2847  * @implemented
2848  */
2849 LONG STDCALL
2850 RegSetValueW (HKEY hKey,
2851               LPCWSTR lpSubKey,
2852               DWORD dwType,
2853               LPCWSTR lpData,
2854               DWORD cbData)
2855 {
2856   OBJECT_ATTRIBUTES ObjectAttributes;
2857   UNICODE_STRING SubKeyString;
2858   HKEY KeyHandle;
2859   HANDLE RealKey;
2860   LONG ErrorCode;
2861   BOOL CloseRealKey;
2862   NTSTATUS Status;
2863
2864   Status = MapDefaultKey (&KeyHandle,
2865                           hKey);
2866   if (!NT_SUCCESS(Status))
2867     {
2868       ErrorCode = RtlNtStatusToDosError (Status);
2869       SetLastError (ErrorCode);
2870       return ErrorCode;
2871     }
2872
2873   if ((lpSubKey) && (wcslen(lpSubKey) != 0))
2874     {
2875       RtlInitUnicodeString (&SubKeyString,
2876                             (LPWSTR)lpSubKey);
2877       InitializeObjectAttributes (&ObjectAttributes,
2878                                   &SubKeyString,
2879                                   OBJ_CASE_INSENSITIVE,
2880                                   KeyHandle,
2881                                   NULL);
2882       Status = NtOpenKey (&RealKey,
2883                           KEY_ALL_ACCESS,
2884                           &ObjectAttributes);
2885       if (!NT_SUCCESS(Status))
2886         {
2887           ErrorCode = RtlNtStatusToDosError (Status);
2888           SetLastError (ErrorCode);
2889           return ErrorCode;
2890         }
2891       CloseRealKey = TRUE;
2892     }
2893   else
2894     {
2895       RealKey = hKey;
2896       CloseRealKey = FALSE;
2897     }
2898
2899   ErrorCode = RegSetValueExW (RealKey,
2900                               NULL,
2901                               0,
2902                               dwType,
2903                               (LPBYTE)lpData,
2904                               cbData);
2905   if (CloseRealKey == TRUE)
2906     {
2907       NtClose (RealKey);
2908     }
2909
2910   return ErrorCode;
2911 }
2912
2913
2914 /************************************************************************
2915  *  RegUnLoadKeyA
2916  *
2917  * @implemented
2918  */
2919 LONG STDCALL
2920 RegUnLoadKeyA (HKEY hKey,
2921                LPCSTR lpSubKey)
2922 {
2923   UNICODE_STRING KeyName;
2924   DWORD ErrorCode;
2925
2926   RtlCreateUnicodeStringFromAsciiz (&KeyName,
2927                                     (LPSTR)lpSubKey);
2928
2929   ErrorCode = RegUnLoadKeyW (hKey,
2930                              KeyName.Buffer);
2931
2932   RtlFreeUnicodeString (&KeyName);
2933
2934   return ErrorCode;
2935 }
2936
2937
2938 /************************************************************************
2939  *  RegUnLoadKeyW
2940  *
2941  * @implemented
2942  */
2943 LONG STDCALL
2944 RegUnLoadKeyW (HKEY  hKey,
2945                LPCWSTR lpSubKey)
2946 {
2947   OBJECT_ATTRIBUTES ObjectAttributes;
2948   UNICODE_STRING KeyName;
2949   HANDLE KeyHandle;
2950   DWORD ErrorCode;
2951   NTSTATUS Status;
2952
2953   if (hKey == HKEY_PERFORMANCE_DATA)
2954     return ERROR_INVALID_HANDLE;
2955
2956   Status = MapDefaultKey (&KeyHandle, hKey);
2957   if (!NT_SUCCESS(Status))
2958     {
2959       ErrorCode = RtlNtStatusToDosError (Status);
2960       SetLastError (ErrorCode);
2961       return ErrorCode;
2962     }
2963
2964   RtlInitUnicodeString (&KeyName,
2965                         (LPWSTR)lpSubKey);
2966
2967   InitializeObjectAttributes (&ObjectAttributes,
2968                               &KeyName,
2969                               OBJ_CASE_INSENSITIVE,
2970                               KeyHandle,
2971                               NULL);
2972
2973   Status = NtUnloadKey (&ObjectAttributes);
2974
2975   if (!NT_SUCCESS(Status))
2976     {
2977       ErrorCode = RtlNtStatusToDosError (Status);
2978       SetLastError (ErrorCode);
2979       return ErrorCode;
2980     }
2981
2982   return ERROR_SUCCESS;
2983 }
2984
2985 /* EOF */