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