8296a41a88d7e084042d27bfcd3a6f2ac4fddc43
[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(LPSTR 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(LPWSTR 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         HANDLE TargetKey;
500         NTSTATUS Status;
501         LONG ErrorCode;
502
503         Status = MapDefaultKey(&ParentKey,
504                                hKey);
505         if (!NT_SUCCESS(Status))
506         {
507                 ErrorCode = RtlNtStatusToDosError(Status);
508
509                 SetLastError (ErrorCode);
510                 return ErrorCode;
511         }
512
513         RtlInitAnsiString(&SubKeyStringA,
514                           (LPSTR)lpSubKey);
515         RtlAnsiStringToUnicodeString(&SubKeyStringW,
516                                      &SubKeyStringA,
517                                      TRUE);
518
519         InitializeObjectAttributes (&ObjectAttributes,
520                                     &SubKeyStringW,
521                                     OBJ_CASE_INSENSITIVE,
522                                     (HANDLE)ParentKey,
523                                     NULL);
524
525         Status = NtOpenKey (&TargetKey,
526                             DELETE,
527                             &ObjectAttributes);
528
529         RtlFreeUnicodeString (&SubKeyStringW);
530
531         if (!NT_SUCCESS(Status))
532         {
533                 ErrorCode = RtlNtStatusToDosError(Status);
534
535                 SetLastError (ErrorCode);
536                 return ErrorCode;
537         }
538
539         Status = NtDeleteKey(TargetKey);
540
541         NtClose(TargetKey);
542
543         if (!NT_SUCCESS(Status))
544         {
545                 ErrorCode = RtlNtStatusToDosError(Status);
546
547                 SetLastError (ErrorCode);
548                 return ErrorCode;
549         }
550         return ERROR_SUCCESS;
551 }
552
553
554 /************************************************************************
555  *      RegDeleteKeyW
556  */
557 LONG
558 STDCALL
559 RegDeleteKeyW(
560         HKEY    hKey,
561         LPCWSTR lpSubKey
562         )
563 {
564         OBJECT_ATTRIBUTES ObjectAttributes;
565         UNICODE_STRING SubKeyString;
566         HANDLE ParentKey;
567         HANDLE TargetKey;
568         NTSTATUS Status;
569         LONG ErrorCode;
570
571         Status = MapDefaultKey(&ParentKey,
572                                hKey);
573         if (!NT_SUCCESS(Status))
574         {
575                 ErrorCode = RtlNtStatusToDosError(Status);
576
577                 SetLastError (ErrorCode);
578                 return ErrorCode;
579         }
580
581         RtlInitUnicodeString(&SubKeyString,
582                              (LPWSTR)lpSubKey);
583
584         InitializeObjectAttributes (&ObjectAttributes,
585                                     &SubKeyString,
586                                     OBJ_CASE_INSENSITIVE,
587                                     (HANDLE)ParentKey,
588                                     NULL);
589
590         Status = NtOpenKey (&TargetKey,
591                             DELETE,
592                             &ObjectAttributes);
593         if (!NT_SUCCESS(Status))
594         {
595                 ErrorCode = RtlNtStatusToDosError(Status);
596
597                 SetLastError (ErrorCode);
598                 return ErrorCode;
599         }
600
601         Status = NtDeleteKey(TargetKey);
602
603         NtClose(TargetKey);
604
605         if (!NT_SUCCESS(Status))
606         {
607                 ErrorCode = RtlNtStatusToDosError(Status);
608
609                 SetLastError (ErrorCode);
610                 return ErrorCode;
611         }
612         return ERROR_SUCCESS;
613 }
614
615
616 /************************************************************************
617  *      RegDeleteValueA
618  */
619 LONG
620 STDCALL
621 RegDeleteValueA(
622         HKEY    hKey,
623         LPCSTR  lpValueName
624         )
625 {
626         UNICODE_STRING ValueNameW;
627         ANSI_STRING ValueNameA;
628         NTSTATUS Status;
629         LONG ErrorCode;
630         HANDLE KeyHandle;
631
632         Status = MapDefaultKey(&KeyHandle,
633                                hKey);
634         if (!NT_SUCCESS(Status))
635         {
636                 ErrorCode = RtlNtStatusToDosError(Status);
637
638                 SetLastError (ErrorCode);
639                 return ErrorCode;
640         }
641
642         RtlInitAnsiString(&ValueNameA,
643                           (LPSTR)lpValueName);
644         RtlAnsiStringToUnicodeString(&ValueNameW,
645                                      &ValueNameA,
646                                      TRUE);
647
648         Status = NtDeleteValueKey(KeyHandle,
649                                   &ValueNameW);
650
651         RtlFreeUnicodeString (&ValueNameW);
652
653         if (!NT_SUCCESS(Status))
654         {
655                 ErrorCode = RtlNtStatusToDosError(Status);
656
657                 SetLastError (ErrorCode);
658                 return ErrorCode;
659         }
660
661         return ERROR_SUCCESS;
662 }
663
664
665 /************************************************************************
666  *      RegDeleteValueW
667  */
668 LONG
669 STDCALL
670 RegDeleteValueW(
671         HKEY    hKey,
672         LPCWSTR lpValueName
673         )
674 {
675         UNICODE_STRING ValueName;
676         NTSTATUS Status;
677         LONG ErrorCode;
678         HANDLE KeyHandle;
679
680         Status = MapDefaultKey(&KeyHandle,
681                                hKey);
682         if (!NT_SUCCESS(Status))
683         {
684                 ErrorCode = RtlNtStatusToDosError(Status);
685
686                 SetLastError (ErrorCode);
687                 return ErrorCode;
688         }
689
690         RtlInitUnicodeString(&ValueName,
691                              (LPWSTR)lpValueName);
692
693         Status = NtDeleteValueKey(KeyHandle,
694                                   &ValueName);
695         if (!NT_SUCCESS(Status))
696         {
697                 ErrorCode = RtlNtStatusToDosError(Status);
698
699                 SetLastError (ErrorCode);
700                 return ErrorCode;
701         }
702
703         return ERROR_SUCCESS;
704 }
705
706
707 /************************************************************************
708  *      RegEnumKeyA
709  */
710 LONG
711 STDCALL
712 RegEnumKeyA(
713         HKEY    hKey,
714         DWORD   dwIndex,
715         LPSTR   lpName,
716         DWORD   cbName
717         )
718 {
719         DWORD dwLength = cbName;
720
721         return RegEnumKeyExA(hKey,
722                              dwIndex,
723                              lpName,
724                              &dwLength,
725                              NULL,
726                              NULL,
727                              NULL,
728                              NULL);
729 }
730
731
732 /************************************************************************
733  *      RegEnumKeyExA
734  */
735 LONG
736 STDCALL
737 RegEnumKeyExA(
738         HKEY            hKey,
739         DWORD           dwIndex,
740         LPSTR           lpName,
741         LPDWORD         lpcbName,
742         LPDWORD         lpReserved,
743         LPSTR           lpClass,
744         LPDWORD         lpcbClass,
745         PFILETIME       lpftLastWriteTime
746         )
747 {
748   WCHAR Name[MAX_PATH+1];
749   UNICODE_STRING UnicodeStringName;
750   WCHAR Class[MAX_PATH+1];
751   UNICODE_STRING UnicodeStringClass;
752   ANSI_STRING AnsiString;
753   LONG ErrorCode;
754   DWORD NameLength;
755   DWORD ClassLength;
756
757   DPRINT("hKey 0x%x  dwIndex %d  lpName 0x%x  *lpcbName %d  lpClass 0x%x  lpcbClass %d\n",
758     hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass);
759
760   if ((lpClass) && (!lpcbClass))
761   {
762     SetLastError(ERROR_INVALID_PARAMETER);
763     return ERROR_INVALID_PARAMETER;
764   }
765
766   RtlInitUnicodeString(&UnicodeStringName, NULL);
767   UnicodeStringName.Buffer = &Name[0];
768   UnicodeStringName.MaximumLength = sizeof(Name);
769
770   RtlInitUnicodeString(&UnicodeStringClass, NULL);
771
772   if (lpClass)
773   {
774     UnicodeStringClass.Buffer = &Class[0];
775     UnicodeStringClass.MaximumLength = sizeof(Class);
776     ClassLength = *lpcbClass;
777   }
778   else
779   {
780     ClassLength = 0;
781   }
782
783   NameLength = *lpcbName;
784
785   ErrorCode = RegEnumKeyExW(
786           hKey,
787           dwIndex,
788           UnicodeStringName.Buffer,
789           &NameLength,
790     lpReserved,
791           UnicodeStringClass.Buffer,
792           &ClassLength,
793           lpftLastWriteTime);
794
795   if (ErrorCode != ERROR_SUCCESS)
796     return ErrorCode;
797
798   UnicodeStringName.Length = NameLength * sizeof(WCHAR);
799   UnicodeStringClass.Length = ClassLength * sizeof(WCHAR);
800
801   RtlInitAnsiString(&AnsiString, NULL);
802   AnsiString.Buffer = lpName;
803   AnsiString.MaximumLength = *lpcbName;
804   RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeStringName, FALSE);
805   *lpcbName = AnsiString.Length;
806
807   DPRINT("Key Namea0 Length %d\n", UnicodeStringName.Length);
808   DPRINT("Key Namea1 Length %d\n", NameLength);
809   DPRINT("Key Namea Length %d\n", *lpcbName);
810   DPRINT("Key Namea %s\n", lpName);
811
812   if (lpClass)
813   {
814     RtlInitAnsiString(&AnsiString, NULL);
815     AnsiString.Buffer = lpClass;
816     AnsiString.MaximumLength = *lpcbClass;
817     RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeStringClass, FALSE);
818     *lpcbClass = AnsiString.Length;
819   }
820
821   return ERROR_SUCCESS;
822 }
823
824
825 /************************************************************************
826  *      RegEnumKeyExW
827  */
828 LONG
829 STDCALL
830 RegEnumKeyExW(
831         HKEY            hKey,
832         DWORD           dwIndex,
833         LPWSTR          lpName,
834         LPDWORD         lpcbName,
835         LPDWORD         lpReserved,
836         LPWSTR          lpClass,
837         LPDWORD         lpcbClass,
838         PFILETIME       lpftLastWriteTime
839         )
840 {
841   PKEY_NODE_INFORMATION KeyInfo;
842         NTSTATUS Status;
843         DWORD dwError = ERROR_SUCCESS;
844         ULONG BufferSize;
845         ULONG ResultSize;
846   HANDLE KeyHandle;
847
848   Status = MapDefaultKey(&KeyHandle, hKey);
849         if (!NT_SUCCESS(Status))
850         {
851                 dwError = RtlNtStatusToDosError(Status);
852                 SetLastError (dwError);
853                 return dwError;
854         }
855
856         BufferSize = sizeof (KEY_NODE_INFORMATION) + *lpcbName * sizeof(WCHAR);
857         if (lpClass)
858                 BufferSize += *lpcbClass;
859         KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
860
861   /* We don't know the exact size of the data returned, so call
862      NtEnumerateKey() with a buffer size determined from parameters
863      to this function. If that call fails with a status code of
864      STATUS_BUFFER_OVERFLOW, allocate a new buffer and try again */
865   while (TRUE) {
866     KeyInfo = RtlAllocateHeap(
867       RtlGetProcessHeap(),
868                 0,
869                 BufferSize);
870           if (KeyInfo == NULL)
871     {
872       SetLastError(ERROR_OUTOFMEMORY);
873       return ERROR_OUTOFMEMORY;
874     }
875
876     Status = NtEnumerateKey(
877       KeyHandle,
878                 (ULONG)dwIndex,
879                 KeyNodeInformation,
880                 KeyInfo,
881                 BufferSize,
882                 &ResultSize);
883
884     DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
885
886     if (Status == STATUS_BUFFER_OVERFLOW)
887     {
888       RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
889       BufferSize = ResultSize;
890       continue;
891     }
892
893     if (!NT_SUCCESS(Status))
894           {
895                 dwError = RtlNtStatusToDosError(Status);
896                 SetLastError(dwError);
897       break;
898           }
899           else
900           {
901       if ((lpClass) && (*lpcbClass != 0) && (KeyInfo->ClassLength > *lpcbClass))
902       {
903                   dwError = ERROR_MORE_DATA;
904                   SetLastError(dwError);
905         break;
906       }
907
908       RtlMoveMemory(lpName, KeyInfo->Name, KeyInfo->NameLength);
909                   *lpcbName = (DWORD)(KeyInfo->NameLength / sizeof(WCHAR));
910       RegiTerminateWideString(lpName, *lpcbName);
911
912                   if (lpClass)
913                   {
914                         RtlMoveMemory(lpClass,
915                                 (PVOID)((ULONG_PTR)KeyInfo->Name + KeyInfo->ClassOffset),
916                                 KeyInfo->ClassLength);
917                         *lpcbClass = (DWORD)(KeyInfo->ClassLength / sizeof(WCHAR));
918                   }
919
920                   if (lpftLastWriteTime)
921                   {
922         /* FIXME: Fill lpftLastWriteTime */
923                   }
924
925       break;
926         }
927   }
928
929   RtlFreeHeap (RtlGetProcessHeap(), 0, KeyInfo);
930
931         return dwError;
932 }
933
934
935 /************************************************************************
936  *      RegEnumKeyW
937  */
938 LONG
939 STDCALL
940 RegEnumKeyW(
941         HKEY    hKey,
942         DWORD   dwIndex,
943         LPWSTR  lpName,
944         DWORD   cbName
945         )
946 {
947         DWORD dwLength = cbName;
948
949         return RegEnumKeyExW(hKey,
950                              dwIndex,
951                              lpName,
952                              &dwLength,
953                              NULL,
954                              NULL,
955                              NULL,
956                              NULL);
957 }
958
959
960 /************************************************************************
961  *      RegEnumValueA
962  */
963 LONG
964 STDCALL
965 RegEnumValueA(
966         HKEY    hKey,
967         DWORD   dwIndex,
968         LPSTR   lpValueName,
969         LPDWORD lpcbValueName,
970         LPDWORD lpReserved,
971         LPDWORD lpType,
972         LPBYTE  lpData,
973         LPDWORD lpcbData
974         )
975 {
976   WCHAR ValueName[MAX_PATH+1];
977   UNICODE_STRING UnicodeString;
978   ANSI_STRING AnsiString;
979   LONG ErrorCode;
980   DWORD ValueNameLength;
981
982   RtlInitUnicodeString(&UnicodeString, NULL);
983   UnicodeString.Buffer = &ValueName[0];
984   UnicodeString.MaximumLength = sizeof(ValueName);
985
986   ValueNameLength = *lpcbValueName;
987
988   ErrorCode = RegEnumValueW(
989           hKey,
990           dwIndex,
991           UnicodeString.Buffer,
992           &ValueNameLength,
993           lpReserved,
994           lpType,
995           lpData,
996           lpcbData);
997
998   if (ErrorCode != ERROR_SUCCESS)
999     return ErrorCode;
1000
1001   UnicodeString.Length = ValueNameLength * sizeof(WCHAR);
1002
1003   RtlInitAnsiString(&AnsiString, NULL);
1004   AnsiString.Buffer = lpValueName;
1005   AnsiString.MaximumLength = *lpcbValueName;
1006   RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
1007   *lpcbValueName = AnsiString.Length;
1008
1009   return ERROR_SUCCESS;
1010 }
1011
1012
1013 /************************************************************************
1014  *      RegEnumValueW
1015  */
1016 LONG
1017 STDCALL
1018 RegEnumValueW(
1019         HKEY    hKey,
1020         DWORD   dwIndex,
1021         LPWSTR  lpValueName,
1022         LPDWORD lpcbValueName,
1023         LPDWORD lpReserved,
1024         LPDWORD lpType,
1025         LPBYTE  lpData,
1026         LPDWORD lpcbData
1027         )
1028 {
1029         PKEY_VALUE_FULL_INFORMATION ValueInfo;
1030         NTSTATUS Status;
1031         DWORD dwError = ERROR_SUCCESS;
1032         ULONG BufferSize;
1033         ULONG ResultSize;
1034   HANDLE KeyHandle;
1035
1036   Status = MapDefaultKey(&KeyHandle, hKey);
1037   if (!NT_SUCCESS(Status))
1038     {
1039       dwError = RtlNtStatusToDosError(Status);
1040       SetLastError(dwError);
1041       return(dwError);
1042     }
1043
1044   BufferSize = sizeof (KEY_VALUE_FULL_INFORMATION) +
1045                 *lpcbValueName * sizeof(WCHAR);
1046   if (lpcbData)
1047     BufferSize += *lpcbData;
1048
1049   /* We don't know the exact size of the data returned, so call
1050      NtEnumerateValueKey() with a buffer size determined from parameters
1051      to this function. If that call fails with a status code of
1052      STATUS_BUFFER_OVERFLOW, allocate a new buffer and try again */
1053   while (TRUE) {
1054     ValueInfo = RtlAllocateHeap(
1055       RtlGetProcessHeap(),
1056                 0,
1057                 BufferSize);
1058           if (ValueInfo == NULL)
1059     {
1060       SetLastError(ERROR_OUTOFMEMORY);
1061                 return ERROR_OUTOFMEMORY;
1062     }
1063
1064           Status = NtEnumerateValueKey(
1065                 KeyHandle,
1066                 (ULONG)dwIndex,
1067                 KeyValueFullInformation,
1068                 ValueInfo,
1069                 BufferSize,
1070                 &ResultSize);
1071
1072     DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
1073
1074     if (Status == STATUS_BUFFER_OVERFLOW)
1075     {
1076           RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
1077       BufferSize = ResultSize;
1078       continue;
1079     }
1080
1081     if (!NT_SUCCESS(Status))
1082           {
1083                 dwError = RtlNtStatusToDosError(Status);
1084                 SetLastError(dwError);
1085       break;
1086           }
1087           else
1088           {
1089       if ((lpData) && (*lpcbData != 0) && (ValueInfo->DataLength > *lpcbData))
1090       {
1091                   dwError = ERROR_MORE_DATA;
1092                   SetLastError(dwError);
1093         break;
1094       }
1095
1096       memcpy(lpValueName, ValueInfo->Name, ValueInfo->NameLength);
1097                 *lpcbValueName = (DWORD)(ValueInfo->NameLength / sizeof(WCHAR));
1098       RegiTerminateWideString(lpValueName, *lpcbValueName);
1099
1100                 if (lpType)
1101                         *lpType = ValueInfo->Type;
1102
1103                 if (lpData)
1104                 {
1105                         memcpy(lpData,
1106                                 (PVOID)((ULONG_PTR)ValueInfo->Name + ValueInfo->DataOffset),
1107                                 ValueInfo->DataLength);
1108                         *lpcbData = (DWORD)ValueInfo->DataLength;
1109                 }
1110
1111       break;
1112         }
1113   }
1114
1115   RtlFreeHeap (RtlGetProcessHeap(), 0, ValueInfo);
1116
1117         return dwError;
1118 }
1119
1120
1121 /************************************************************************
1122  *      RegFlushKey
1123  */
1124 LONG STDCALL
1125 RegFlushKey(HKEY hKey)
1126 {
1127   HANDLE KeyHandle;
1128   NTSTATUS Status;
1129   LONG ErrorCode;
1130   
1131   if (hKey == HKEY_PERFORMANCE_DATA)
1132     return(ERROR_SUCCESS);
1133
1134   Status = MapDefaultKey(&KeyHandle,
1135                          hKey);
1136   if (!NT_SUCCESS(Status))
1137     {
1138       ErrorCode = RtlNtStatusToDosError(Status);
1139
1140       SetLastError(ErrorCode);
1141       return(ErrorCode);
1142     }
1143
1144   Status = NtFlushKey(KeyHandle);
1145   if (!NT_SUCCESS(Status))
1146     {
1147       ErrorCode = RtlNtStatusToDosError(Status);
1148
1149       SetLastError(ErrorCode);
1150       return(ErrorCode);
1151     }
1152
1153   return(ERROR_SUCCESS);
1154 }
1155
1156
1157 /************************************************************************
1158  *      RegGetKeySecurity
1159  */
1160 LONG
1161 STDCALL
1162 RegGetKeySecurity (
1163         HKEY                    hKey,
1164         SECURITY_INFORMATION    SecurityInformation,
1165         PSECURITY_DESCRIPTOR    pSecurityDescriptor,
1166         LPDWORD                 lpcbSecurityDescriptor
1167         )
1168 {
1169   UNIMPLEMENTED;
1170         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1171         return ERROR_CALL_NOT_IMPLEMENTED;
1172 }
1173
1174
1175 /************************************************************************
1176  *      RegLoadKeyA
1177  */
1178 LONG
1179 STDCALL
1180 RegLoadKey(
1181         HKEY    hKey,
1182         LPCSTR  lpSubKey,
1183         LPCSTR  lpFile
1184         )
1185 {
1186   UNIMPLEMENTED;
1187         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1188         return ERROR_CALL_NOT_IMPLEMENTED;
1189 }
1190
1191
1192 /************************************************************************
1193  *      RegLoadKeyW
1194  */
1195 LONG
1196 STDCALL
1197 RegLoadKeyW(
1198         HKEY    hKey,
1199         LPCWSTR lpSubKey,
1200         LPCWSTR lpFile
1201         )
1202 {
1203         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1204         return ERROR_CALL_NOT_IMPLEMENTED;
1205 }
1206
1207
1208 /************************************************************************
1209  *      RegNotifyChangeKeyValue
1210  */
1211 LONG
1212 STDCALL
1213 RegNotifyChangeKeyValue(
1214         HKEY    hKey,
1215         BOOL    bWatchSubtree,
1216         DWORD   dwNotifyFilter,
1217         HANDLE  hEvent,
1218         BOOL    fAsynchronous
1219         )
1220 {
1221   UNIMPLEMENTED;
1222         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1223         return ERROR_CALL_NOT_IMPLEMENTED;
1224 }
1225
1226
1227
1228 /************************************************************************
1229  *      RegOpenKeyA
1230  */
1231 LONG STDCALL
1232 RegOpenKeyA(HKEY hKey,
1233             LPCSTR lpSubKey,
1234             PHKEY phkResult)
1235 {
1236   OBJECT_ATTRIBUTES ObjectAttributes;
1237   UNICODE_STRING SubKeyString;
1238   HANDLE KeyHandle;
1239   LONG ErrorCode;
1240   NTSTATUS Status;
1241
1242   Status = MapDefaultKey(&KeyHandle,
1243                          hKey);
1244   if (!NT_SUCCESS(Status))
1245     {
1246       ErrorCode = RtlNtStatusToDosError(Status);
1247
1248       SetLastError(ErrorCode);
1249       return(ErrorCode);
1250     }
1251
1252   RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
1253                                    (LPSTR)lpSubKey);
1254
1255   InitializeObjectAttributes(&ObjectAttributes,
1256                              &SubKeyString,
1257                              OBJ_CASE_INSENSITIVE,
1258                              KeyHandle,
1259                              NULL);
1260
1261   Status = NtOpenKey(phkResult,
1262                      KEY_ALL_ACCESS,
1263                      &ObjectAttributes);
1264
1265   RtlFreeUnicodeString(&SubKeyString);
1266
1267   if (!NT_SUCCESS(Status))
1268     {
1269       ErrorCode = RtlNtStatusToDosError(Status);
1270
1271       SetLastError(ErrorCode);
1272       return(ErrorCode);
1273     }
1274   return(ERROR_SUCCESS);
1275 }
1276
1277
1278 /************************************************************************
1279  *      RegOpenKeyW
1280  *
1281  *      19981101 Ariadne
1282  *      19990525 EA
1283  */
1284 LONG
1285 STDCALL
1286 RegOpenKeyW (
1287         HKEY    hKey,
1288         LPCWSTR lpSubKey,
1289         PHKEY   phkResult
1290         )
1291 {
1292         NTSTATUS                errCode;
1293         UNICODE_STRING          SubKeyString;
1294         OBJECT_ATTRIBUTES       ObjectAttributes;
1295         HANDLE                  KeyHandle;
1296         LONG                    ErrorCode;
1297
1298         errCode = MapDefaultKey(&KeyHandle,
1299                                 hKey);
1300         if (!NT_SUCCESS(errCode))
1301         {
1302                 ErrorCode = RtlNtStatusToDosError(errCode);
1303
1304                 SetLastError (ErrorCode);
1305                 return ErrorCode;
1306         }
1307
1308         RtlInitUnicodeString(&SubKeyString,
1309                              (LPWSTR)lpSubKey);
1310
1311         InitializeObjectAttributes(&ObjectAttributes,
1312                                    &SubKeyString,
1313                                    OBJ_CASE_INSENSITIVE,
1314                                    KeyHandle,
1315                                    NULL);
1316
1317         errCode = NtOpenKey(
1318                         phkResult,
1319                         KEY_ALL_ACCESS,
1320                         & ObjectAttributes
1321                         );
1322         if ( !NT_SUCCESS(errCode) )
1323         {
1324                 ErrorCode = RtlNtStatusToDosError(errCode);
1325                 
1326                 SetLastError(ErrorCode);
1327                 return ErrorCode;
1328         }
1329         return ERROR_SUCCESS;
1330 }
1331
1332
1333 /************************************************************************
1334  *      RegOpenKeyExA
1335  */
1336 LONG STDCALL
1337 RegOpenKeyExA(HKEY hKey,
1338               LPCSTR lpSubKey,
1339               DWORD ulOptions,
1340               REGSAM samDesired,
1341               PHKEY phkResult)
1342 {
1343   OBJECT_ATTRIBUTES ObjectAttributes;
1344   UNICODE_STRING SubKeyString;
1345   HANDLE KeyHandle;
1346   LONG ErrorCode;
1347   NTSTATUS Status;
1348
1349   Status = MapDefaultKey(&KeyHandle,
1350                          hKey);
1351   if (!NT_SUCCESS(Status))
1352     {
1353       ErrorCode = RtlNtStatusToDosError(Status);
1354
1355       SetLastError(ErrorCode);
1356       return(ErrorCode);
1357     }
1358
1359   RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
1360                                    (LPSTR)lpSubKey);
1361
1362   InitializeObjectAttributes(&ObjectAttributes,
1363                              &SubKeyString,
1364                              OBJ_CASE_INSENSITIVE,
1365                              KeyHandle,
1366                              NULL);
1367
1368   Status = NtOpenKey(phkResult,
1369                      samDesired,
1370                      &ObjectAttributes);
1371
1372   RtlFreeUnicodeString(&SubKeyString);
1373
1374   if (!NT_SUCCESS(Status))
1375     {
1376       ErrorCode = RtlNtStatusToDosError(Status);
1377
1378       SetLastError(ErrorCode);
1379       return(ErrorCode);
1380     }
1381
1382   return(ERROR_SUCCESS);
1383 }
1384
1385
1386 /************************************************************************
1387  *      RegOpenKeyExW
1388  */
1389 LONG STDCALL
1390 RegOpenKeyExW(HKEY hKey,
1391               LPCWSTR lpSubKey,
1392               DWORD ulOptions,
1393               REGSAM samDesired,
1394               PHKEY phkResult)
1395 {
1396   OBJECT_ATTRIBUTES ObjectAttributes;
1397   UNICODE_STRING SubKeyString;
1398   HANDLE KeyHandle;
1399   LONG ErrorCode;
1400   NTSTATUS Status;
1401
1402   Status = MapDefaultKey(&KeyHandle,
1403                          hKey);
1404   if (!NT_SUCCESS(Status))
1405     {
1406       ErrorCode = RtlNtStatusToDosError(Status);
1407
1408       SetLastError (ErrorCode);
1409       return(ErrorCode);
1410     }
1411
1412   RtlInitUnicodeString(&SubKeyString,
1413                        (LPWSTR)lpSubKey);
1414
1415   InitializeObjectAttributes(&ObjectAttributes,
1416                              &SubKeyString,
1417                              OBJ_CASE_INSENSITIVE,
1418                              KeyHandle,
1419                              NULL);
1420
1421   Status = NtOpenKey(phkResult,
1422                      samDesired,
1423                      &ObjectAttributes);
1424   if (!NT_SUCCESS(Status))
1425     {
1426       ErrorCode = RtlNtStatusToDosError(Status);
1427
1428       SetLastError(ErrorCode);
1429       return(ErrorCode);
1430     }
1431   return(ERROR_SUCCESS);
1432 }
1433
1434
1435 /************************************************************************
1436  *      RegQueryInfoKeyA
1437  */
1438 LONG
1439 STDCALL
1440 RegQueryInfoKeyA(
1441         HKEY            hKey,
1442         LPSTR           lpClass,
1443         LPDWORD         lpcbClass,
1444         LPDWORD         lpReserved,
1445         LPDWORD         lpcSubKeys,
1446         LPDWORD         lpcbMaxSubKeyLen,
1447         LPDWORD         lpcbMaxClassLen,
1448         LPDWORD         lpcValues,
1449         LPDWORD         lpcbMaxValueNameLen,
1450         LPDWORD         lpcbMaxValueLen,
1451         LPDWORD         lpcbSecurityDescriptor,
1452         PFILETIME       lpftLastWriteTime
1453         )
1454 {
1455   WCHAR ClassName[MAX_PATH];
1456   UNICODE_STRING UnicodeString;
1457   ANSI_STRING AnsiString;
1458   LONG ErrorCode;
1459
1460   RtlInitUnicodeString(&UnicodeString, NULL);
1461
1462   if (lpClass)
1463   {
1464     UnicodeString.Buffer = &ClassName[0];
1465     UnicodeString.MaximumLength = sizeof(ClassName);
1466   }
1467
1468   ErrorCode = RegQueryInfoKeyW(
1469           hKey,
1470           UnicodeString.Buffer,
1471           lpcbClass,
1472           lpReserved,
1473           lpcSubKeys,
1474           lpcbMaxSubKeyLen,
1475           lpcbMaxClassLen,
1476           lpcValues,
1477           lpcbMaxValueNameLen,
1478           lpcbMaxValueLen,
1479           lpcbSecurityDescriptor,
1480           lpftLastWriteTime);
1481
1482   if ((ErrorCode == ERROR_SUCCESS) && (lpClass))
1483   {
1484     RtlInitAnsiString(&AnsiString, NULL);
1485     AnsiString.Buffer = lpClass;
1486     AnsiString.MaximumLength = *lpcbClass;
1487     RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
1488     *lpcbClass = AnsiString.Length;
1489   }
1490
1491   return ErrorCode;
1492 }
1493
1494
1495 /************************************************************************
1496  *      RegQueryInfoKeyW
1497  */
1498 LONG
1499 STDCALL
1500 RegQueryInfoKeyW(
1501         HKEY            hKey,
1502         LPWSTR          lpClass,
1503         LPDWORD         lpcbClass,
1504         LPDWORD         lpReserved,
1505         LPDWORD         lpcSubKeys,
1506         LPDWORD         lpcbMaxSubKeyLen,
1507         LPDWORD         lpcbMaxClassLen,
1508         LPDWORD         lpcValues,
1509         LPDWORD         lpcbMaxValueNameLen,
1510         LPDWORD         lpcbMaxValueLen,
1511         LPDWORD         lpcbSecurityDescriptor,
1512         PFILETIME       lpftLastWriteTime
1513         )
1514 {
1515   KEY_FULL_INFORMATION FullInfoBuffer;
1516   PKEY_FULL_INFORMATION FullInfo;
1517   ULONG FullInfoSize;
1518   HANDLE KeyHandle;
1519   NTSTATUS Status;
1520   LONG ErrorCode;
1521   ULONG Length;
1522
1523   if ((lpClass) && (!lpcbClass))
1524   {
1525         SetLastError(ERROR_INVALID_PARAMETER);
1526           return ERROR_INVALID_PARAMETER;
1527   }
1528
1529   Status = MapDefaultKey(&KeyHandle, hKey);
1530   CHECK_STATUS;
1531
1532   if (lpClass)
1533   {
1534     FullInfoSize = sizeof(KEY_FULL_INFORMATION) + *lpcbClass;
1535     FullInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullInfoSize);
1536     if (!FullInfo)
1537     {
1538                   SetLastError(ERROR_OUTOFMEMORY);
1539                   return ERROR_OUTOFMEMORY;
1540         }
1541
1542     FullInfo->ClassLength = *lpcbClass;
1543   }
1544   else
1545   {
1546     FullInfoSize = sizeof(KEY_FULL_INFORMATION);
1547     FullInfo = &FullInfoBuffer;
1548     FullInfo->ClassLength = 1;
1549   }
1550
1551   FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
1552
1553   Status = NtQueryKey(
1554     KeyHandle,
1555     KeyFullInformation,
1556     FullInfo,
1557     FullInfoSize,
1558     &Length);
1559
1560   if (!NT_SUCCESS(Status))
1561         {
1562     if (lpClass)
1563     {
1564       RtlFreeHeap(RtlGetProcessHeap(), 0, FullInfo);
1565     }
1566
1567                 ErrorCode = RtlNtStatusToDosError(Status);
1568                 SetLastError(ErrorCode);
1569                 return ErrorCode;
1570         }
1571
1572   if (lpcSubKeys)
1573   {
1574     *lpcSubKeys = FullInfo->SubKeys;
1575   }
1576
1577   if (lpcbMaxSubKeyLen)
1578   {
1579     *lpcbMaxSubKeyLen = FullInfo->MaxNameLen;
1580   }
1581
1582   if (lpcbMaxClassLen)
1583   {
1584     *lpcbMaxClassLen = FullInfo->MaxClassLen;
1585   }
1586
1587   if (lpcValues)
1588   {
1589     *lpcValues = FullInfo->Values;
1590   }
1591
1592   if (lpcbMaxValueNameLen)
1593   {
1594     *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen;
1595   }
1596
1597   if (lpcbMaxValueLen)
1598   {
1599     *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
1600   }
1601
1602   if (lpcbSecurityDescriptor)
1603   {
1604     *lpcbSecurityDescriptor = 0;
1605     /* FIXME */
1606   }
1607
1608   if (lpftLastWriteTime != NULL)
1609   {
1610     lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
1611     lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
1612   }
1613
1614   if (lpClass)
1615   {
1616     wcsncpy(lpClass, FullInfo->Class, *lpcbClass);
1617     RtlFreeHeap(RtlGetProcessHeap(), 0, FullInfo);
1618   }
1619
1620   SetLastError(ERROR_SUCCESS);
1621         return ERROR_SUCCESS;
1622 }
1623
1624
1625 /************************************************************************
1626  *      RegQueryMultipleValuesA
1627  */
1628 LONG
1629 STDCALL
1630 RegQueryMultipleValuesA(
1631         HKEY    hKey,
1632         PVALENT val_list,
1633         DWORD   num_vals,
1634         LPSTR   lpValueBuf,
1635         LPDWORD ldwTotsize
1636         )
1637 {
1638   UNIMPLEMENTED;
1639         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1640         return ERROR_CALL_NOT_IMPLEMENTED;
1641 }
1642
1643
1644 /************************************************************************
1645  *      RegQueryMultipleValuesW
1646  */
1647 LONG
1648 STDCALL
1649 RegQueryMultipleValuesW(
1650         HKEY    hKey,
1651         PVALENT val_list,
1652         DWORD   num_vals,
1653         LPWSTR  lpValueBuf,
1654         LPDWORD ldwTotsize
1655         )
1656 {
1657   UNIMPLEMENTED;
1658         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1659         return ERROR_CALL_NOT_IMPLEMENTED;
1660 }
1661
1662
1663 /************************************************************************
1664  *      RegQueryValueA
1665  */
1666 LONG
1667 STDCALL
1668 RegQueryValueA(
1669         HKEY    hKey,
1670         LPCSTR  lpSubKey,
1671         LPSTR   lpValue,
1672         PLONG   lpcbValue
1673         )
1674 {
1675   WCHAR SubKeyNameBuffer[MAX_PATH+1];
1676   UNICODE_STRING SubKeyName;
1677   UNICODE_STRING Value;
1678   ANSI_STRING AnsiString;
1679   LONG ValueSize;
1680   LONG ErrorCode;
1681
1682   if ((lpValue) && (!lpcbValue))
1683   {
1684         SetLastError(ERROR_INVALID_PARAMETER);
1685           return ERROR_INVALID_PARAMETER;
1686   }
1687
1688   RtlInitUnicodeString(&SubKeyName, NULL);
1689   RtlInitUnicodeString(&Value, NULL);
1690
1691   if ((lpSubKey) && (strlen(lpSubKey) != 0))
1692   {
1693     RtlInitAnsiString(&AnsiString, (LPSTR)lpSubKey);
1694     SubKeyName.Buffer = &SubKeyNameBuffer[0];
1695     SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
1696     RtlAnsiStringToUnicodeString(&SubKeyName, &AnsiString, FALSE);
1697   }
1698
1699   if (lpValue)
1700   {
1701     ValueSize = *lpcbValue * sizeof(WCHAR);
1702     Value.MaximumLength = ValueSize;
1703     Value.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueSize);
1704     if (!Value.Buffer)
1705     {
1706             SetLastError(ERROR_OUTOFMEMORY);
1707             return ERROR_OUTOFMEMORY;
1708     }
1709   }
1710   else
1711   {
1712     ValueSize = 0;
1713   }
1714
1715   ErrorCode = RegQueryValueW(
1716         hKey,
1717         (LPCWSTR)SubKeyName.Buffer,
1718         Value.Buffer,
1719         &ValueSize);
1720
1721   if (ErrorCode == ERROR_SUCCESS)
1722   {
1723     Value.Length = ValueSize;
1724     RtlInitAnsiString(&AnsiString, NULL);
1725     AnsiString.Buffer = lpValue;
1726     AnsiString.MaximumLength = *lpcbValue;
1727     RtlUnicodeStringToAnsiString(&AnsiString, &Value, FALSE);
1728   }
1729
1730   *lpcbValue = ValueSize; 
1731
1732   if (Value.Buffer)
1733   {
1734     RtlFreeHeap(RtlGetProcessHeap(), 0, Value.Buffer);
1735   }
1736
1737   return ErrorCode;
1738 }
1739
1740
1741 /************************************************************************
1742  *      RegQueryValueExA
1743  */
1744 LONG
1745 STDCALL
1746 RegQueryValueExA(
1747         HKEY    hKey,
1748         LPSTR   lpValueName,
1749         LPDWORD lpReserved,
1750         LPDWORD lpType,
1751         LPBYTE  lpData,
1752         LPDWORD lpcbData
1753         )
1754 {
1755   WCHAR ValueNameBuffer[MAX_PATH+1];
1756   UNICODE_STRING ValueName;
1757   UNICODE_STRING ValueData;
1758   ANSI_STRING AnsiString;
1759   LONG ErrorCode;
1760   DWORD ResultSize;
1761   DWORD Type;
1762
1763   /* FIXME: HKEY_PERFORMANCE_DATA is special, see MS SDK */
1764
1765   if ((lpData) && (!lpcbData))
1766   {
1767         SetLastError(ERROR_INVALID_PARAMETER);
1768           return ERROR_INVALID_PARAMETER;
1769   }
1770
1771   RtlInitUnicodeString(&ValueData, NULL);
1772
1773   if (lpData)
1774   {
1775     ValueData.MaximumLength = *lpcbData * sizeof(WCHAR);
1776           ValueData.Buffer = RtlAllocateHeap(
1777       RtlGetProcessHeap(),
1778       0,
1779       ValueData.MaximumLength);
1780           if (!ValueData.Buffer)
1781     {
1782       SetLastError(ERROR_OUTOFMEMORY);
1783                 return ERROR_OUTOFMEMORY;
1784     }
1785   }
1786
1787   RtlInitAnsiString(&AnsiString, (LPSTR)lpValueName);
1788   RtlInitUnicodeString(&ValueName, NULL);
1789   ValueName.Buffer = &ValueNameBuffer[0];
1790   ValueName.MaximumLength = sizeof(ValueNameBuffer);
1791   RtlAnsiStringToUnicodeString(&ValueName, &AnsiString, FALSE);
1792
1793   if (lpcbData)
1794   {
1795     ResultSize = *lpcbData;
1796   }
1797   else
1798   {
1799     ResultSize = 0;
1800   }
1801
1802   ErrorCode = RegQueryValueExW(
1803           hKey,
1804           ValueName.Buffer,
1805           lpReserved,
1806           &Type,
1807           (LPBYTE)ValueData.Buffer,
1808           &ResultSize);
1809
1810   if ((ErrorCode == ERROR_SUCCESS) && (ValueData.Buffer != NULL))
1811   {
1812     if (lpType)
1813     {
1814       *lpType = Type;
1815     }
1816
1817     if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
1818     {
1819       ValueData.Length = ResultSize;
1820       RtlInitAnsiString(&AnsiString, NULL);
1821       AnsiString.Buffer = lpData;
1822       AnsiString.MaximumLength = *lpcbData;
1823       RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
1824     }
1825     else
1826     {
1827       RtlMoveMemory(lpData, ValueData.Buffer, ResultSize);
1828     }
1829   }
1830
1831   if (lpcbData)
1832   {
1833     *lpcbData = ResultSize;
1834   }
1835
1836   if (ValueData.Buffer)
1837   {
1838     RtlFreeHeap(RtlGetProcessHeap(), 0, ValueData.Buffer);
1839   }
1840
1841   return ErrorCode;
1842 }
1843
1844
1845 /************************************************************************
1846  *      RegQueryValueExW
1847  */
1848 LONG
1849 STDCALL
1850 RegQueryValueExW(
1851         HKEY    hKey,
1852         LPWSTR  lpValueName,
1853         LPDWORD lpReserved,
1854         LPDWORD lpType,
1855         LPBYTE  lpData,
1856         LPDWORD lpcbData
1857         )
1858 {
1859         PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1860         UNICODE_STRING ValueName;
1861         NTSTATUS Status;
1862         DWORD dwError = ERROR_SUCCESS;
1863         ULONG BufferSize;
1864         ULONG ResultSize;
1865   HANDLE KeyHandle;
1866
1867   DPRINT("hKey 0x%X  lpValueName %S  lpData 0x%X  lpcbData %d\n",
1868     hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
1869
1870   Status = MapDefaultKey(&KeyHandle, hKey);
1871   if (!NT_SUCCESS(Status))
1872     {
1873       dwError = RtlNtStatusToDosError(Status);
1874       SetLastError(dwError);
1875       return(dwError);
1876     }
1877
1878   if ((lpData) && (!lpcbData))
1879   {
1880         SetLastError(ERROR_INVALID_PARAMETER);
1881           return ERROR_INVALID_PARAMETER;
1882   }
1883
1884         RtlInitUnicodeString (&ValueName,
1885                               lpValueName);
1886
1887         BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + *lpcbData;
1888         ValueInfo = RtlAllocateHeap (RtlGetProcessHeap(),
1889                                      0,
1890                                      BufferSize);
1891         if (ValueInfo == NULL)
1892   {
1893     SetLastError(ERROR_OUTOFMEMORY);
1894                 return ERROR_OUTOFMEMORY;
1895   }
1896
1897         Status = NtQueryValueKey (hKey,
1898                                   &ValueName,
1899                                   KeyValuePartialInformation,
1900                                   ValueInfo,
1901                                   BufferSize,
1902                                   &ResultSize);
1903
1904   DPRINT("Status 0x%X\n", Status);
1905
1906   if (Status == STATUS_BUFFER_TOO_SMALL)
1907   {
1908     /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
1909     dwError = ERROR_SUCCESS;
1910   }
1911   else if (!NT_SUCCESS(Status))
1912         {
1913                 dwError = RtlNtStatusToDosError(Status);
1914                 SetLastError(dwError);
1915         }
1916         else
1917         {
1918     if (lpType)
1919     {
1920             *lpType = ValueInfo->Type;
1921     }
1922
1923                 RtlMoveMemory(lpData, ValueInfo->Data, ValueInfo->DataLength);
1924     if ((ValueInfo->Type == REG_SZ) ||
1925       (ValueInfo->Type == REG_MULTI_SZ) ||
1926       (ValueInfo->Type == REG_EXPAND_SZ))
1927     {
1928                         ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
1929     }
1930         }
1931
1932   DPRINT("Type %d  ResultSize %d\n", ValueInfo->Type, ResultSize);
1933
1934         *lpcbData = (DWORD)ResultSize;
1935
1936         RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
1937
1938         return dwError;
1939 }
1940
1941
1942 /************************************************************************
1943  *      RegQueryValueW
1944  */
1945 LONG
1946 STDCALL
1947 RegQueryValueW(
1948         HKEY    hKey,
1949         LPCWSTR lpSubKey,
1950         LPWSTR  lpValue,
1951         PLONG   lpcbValue
1952         )
1953 {
1954         NTSTATUS                errCode;
1955         UNICODE_STRING          SubKeyString;
1956         OBJECT_ATTRIBUTES       ObjectAttributes;
1957         HANDLE                  KeyHandle;
1958   HANDLE                        RealKey;
1959         LONG                      ErrorCode;
1960   BOOL        CloseRealKey;
1961
1962         errCode = MapDefaultKey(&KeyHandle, hKey);
1963         if (!NT_SUCCESS(errCode))
1964         {
1965                 ErrorCode = RtlNtStatusToDosError(errCode);
1966                 SetLastError (ErrorCode);
1967                 return ErrorCode;
1968         }
1969
1970   if ((lpSubKey) && (wcslen(lpSubKey) != 0))
1971   {
1972
1973           RtlInitUnicodeString(&SubKeyString,
1974                              (LPWSTR)lpSubKey);
1975
1976           InitializeObjectAttributes(&ObjectAttributes,
1977                                    &SubKeyString,
1978                                    OBJ_CASE_INSENSITIVE,
1979                                    KeyHandle,
1980                                    NULL);
1981
1982           errCode = NtOpenKey(
1983                         &RealKey,
1984                         KEY_ALL_ACCESS,
1985                         & ObjectAttributes
1986                         );
1987           if ( !NT_SUCCESS(errCode) )
1988           {
1989                 ErrorCode = RtlNtStatusToDosError(errCode);
1990                 SetLastError(ErrorCode);
1991                 return ErrorCode;
1992           }
1993     CloseRealKey = TRUE;
1994   }
1995   else
1996   {
1997     RealKey = hKey;
1998     CloseRealKey = FALSE;
1999   }
2000
2001   ErrorCode = RegQueryValueExW(
2002           RealKey,
2003           NULL,
2004           NULL,
2005           NULL,
2006           (LPBYTE)lpValue,
2007           (LPDWORD)lpcbValue);
2008
2009   if (CloseRealKey)
2010   {
2011     NtClose(RealKey);
2012   }
2013
2014   return ErrorCode;
2015 }
2016
2017
2018 /************************************************************************
2019  *      RegReplaceKeyA
2020  */
2021 LONG
2022 STDCALL
2023 RegReplaceKeyA(
2024         HKEY    hKey,
2025         LPCSTR  lpSubKey,
2026         LPCSTR  lpNewFile,
2027         LPCSTR  lpOldFile
2028         )
2029 {
2030   UNIMPLEMENTED;
2031         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2032         return ERROR_CALL_NOT_IMPLEMENTED;
2033 }
2034
2035
2036 /************************************************************************
2037  *      RegReplaceKeyW
2038  */
2039 LONG
2040 STDCALL
2041 RegReplaceKeyW(
2042         HKEY    hKey,
2043         LPCWSTR lpSubKey,
2044         LPCWSTR lpNewFile,
2045         LPCWSTR lpOldFile
2046         )
2047 {
2048   UNIMPLEMENTED;
2049         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2050         return ERROR_CALL_NOT_IMPLEMENTED;
2051 }
2052
2053
2054 /************************************************************************
2055  *      RegRestoreKeyA
2056  */
2057 LONG
2058 STDCALL
2059 RegRestoreKeyA(
2060         HKEY    hKey,
2061         LPCSTR  lpFile,
2062         DWORD   dwFlags
2063         )
2064 {
2065   UNIMPLEMENTED;
2066         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2067         return ERROR_CALL_NOT_IMPLEMENTED;
2068 }
2069
2070
2071 /************************************************************************
2072  *      RegRestoreKeyW
2073  */
2074 LONG
2075 STDCALL
2076 RegRestoreKeyW(
2077         HKEY    hKey,
2078         LPCWSTR lpFile,
2079         DWORD   dwFlags
2080         )
2081 {
2082   UNIMPLEMENTED;
2083         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2084         return ERROR_CALL_NOT_IMPLEMENTED;
2085 }
2086
2087
2088 /************************************************************************
2089  *      RegSaveKeyA
2090  */
2091 LONG STDCALL
2092 RegSaveKeyA(HKEY hKey,
2093             LPCSTR lpFile,
2094             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2095 {
2096   UNICODE_STRING FileName;
2097   LONG ErrorCode;
2098
2099   RtlCreateUnicodeStringFromAsciiz(&FileName,
2100                                    (LPSTR)lpFile);
2101   ErrorCode = RegSaveKeyW(hKey,
2102                           FileName.Buffer,
2103                           lpSecurityAttributes);
2104   RtlFreeUnicodeString(&FileName);
2105
2106   return(ErrorCode);
2107 }
2108
2109
2110 /************************************************************************
2111  *      RegSaveKeyW
2112  */
2113 LONG STDCALL
2114 RegSaveKeyW(HKEY hKey,
2115             LPCWSTR lpFile,
2116             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2117 {
2118   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
2119   OBJECT_ATTRIBUTES ObjectAttributes;
2120   UNICODE_STRING NtName;
2121   IO_STATUS_BLOCK IoStatusBlock;
2122   HANDLE FileHandle;
2123   HANDLE KeyHandle;
2124   NTSTATUS Status;
2125   LONG ErrorCode;
2126
2127   Status = MapDefaultKey(&KeyHandle,
2128                          hKey);
2129   if (!NT_SUCCESS(Status))
2130     {
2131       ErrorCode = RtlNtStatusToDosError(Status);
2132       SetLastError(ErrorCode);
2133       return(ErrorCode);
2134     }
2135
2136   if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpFile,
2137                                     &NtName,
2138                                     NULL,
2139                                     NULL))
2140     {
2141       SetLastError(ERROR_INVALID_PARAMETER);
2142       return(ERROR_INVALID_PARAMETER);
2143     }
2144
2145   if (lpSecurityAttributes != NULL)
2146     SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
2147
2148   InitializeObjectAttributes(&ObjectAttributes,
2149                              &NtName,
2150                              OBJ_CASE_INSENSITIVE,
2151                              NULL,
2152                              SecurityDescriptor);
2153
2154   Status = NtCreateFile(&FileHandle,
2155                         GENERIC_WRITE | SYNCHRONIZE,
2156                         &ObjectAttributes,
2157                         &IoStatusBlock,
2158                         NULL,
2159                         FILE_ATTRIBUTE_NORMAL,
2160                         FILE_SHARE_READ,
2161                         FILE_CREATE,
2162                         FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
2163                         NULL,
2164                         0);
2165   RtlFreeUnicodeString(&NtName);
2166   if (!NT_SUCCESS(Status))
2167     {
2168       ErrorCode = RtlNtStatusToDosError(Status);
2169       SetLastError(ErrorCode);
2170       return(ErrorCode);
2171     }
2172
2173   Status = NtSaveKey(KeyHandle,
2174                      FileHandle);
2175   NtClose(FileHandle);
2176   if (!NT_SUCCESS(Status))
2177     {
2178       ErrorCode = RtlNtStatusToDosError(Status);
2179       SetLastError(ErrorCode);
2180       return(ErrorCode);
2181     }
2182
2183   return(ERROR_SUCCESS);
2184 }
2185
2186
2187 /************************************************************************
2188  *      RegSetKeySecurity
2189  */
2190 LONG
2191 STDCALL
2192 RegSetKeySecurity(
2193         HKEY                    hKey,
2194         SECURITY_INFORMATION    SecurityInformation,    /* FIXME: ULONG? */
2195         PSECURITY_DESCRIPTOR    pSecurityDescriptor
2196         )
2197 {
2198   UNIMPLEMENTED;
2199         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2200         return ERROR_CALL_NOT_IMPLEMENTED;
2201 }
2202
2203
2204 /************************************************************************
2205  *      RegSetValueA
2206  */
2207 LONG
2208 STDCALL
2209 RegSetValueA(
2210         HKEY    hKey,
2211         LPCSTR  lpSubKey,
2212         DWORD   dwType,
2213         LPCSTR  lpData,
2214         DWORD   cbData
2215         )
2216 {
2217   WCHAR SubKeyNameBuffer[MAX_PATH+1];
2218   UNICODE_STRING SubKeyName;
2219   UNICODE_STRING Data;
2220   ANSI_STRING AnsiString;
2221   LONG DataSize;
2222   LONG ErrorCode;
2223
2224   if (!lpData)
2225   {
2226         SetLastError(ERROR_INVALID_PARAMETER);
2227           return ERROR_INVALID_PARAMETER;
2228   }
2229
2230   RtlInitUnicodeString(&SubKeyName, NULL);
2231   RtlInitUnicodeString(&Data, NULL);
2232
2233   if ((lpSubKey) && (strlen(lpSubKey) != 0))
2234   {
2235     RtlInitAnsiString(&AnsiString, (LPSTR)lpSubKey);
2236     SubKeyName.Buffer = &SubKeyNameBuffer[0];
2237     SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
2238     RtlAnsiStringToUnicodeString(&SubKeyName, &AnsiString, FALSE);
2239   }
2240
2241   DataSize = cbData * sizeof(WCHAR);
2242   Data.MaximumLength = DataSize;
2243   Data.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DataSize);
2244   if (!Data.Buffer)
2245   {
2246           SetLastError(ERROR_OUTOFMEMORY);
2247           return ERROR_OUTOFMEMORY;
2248   }
2249
2250   ErrorCode = RegSetValueW(
2251           hKey,
2252           (LPCWSTR)SubKeyName.Buffer,
2253           dwType,
2254           Data.Buffer,
2255           DataSize);
2256
2257   RtlFreeHeap(RtlGetProcessHeap(), 0, Data.Buffer);
2258
2259   return ErrorCode;
2260 }
2261
2262
2263 /************************************************************************
2264  *      RegSetValueExA
2265  */
2266 LONG
2267 STDCALL
2268 RegSetValueExA(
2269         HKEY            hKey,
2270         LPCSTR          lpValueName,
2271         DWORD           Reserved,
2272         DWORD           dwType,
2273         CONST BYTE      *lpData,
2274         DWORD           cbData
2275         )
2276 {
2277   UNICODE_STRING ValueName;
2278   LPWSTR pValueName;
2279   ANSI_STRING AnsiString;
2280   UNICODE_STRING Data;
2281   LONG ErrorCode;
2282   LPBYTE pData;
2283   DWORD DataSize;
2284
2285   if (!lpData)
2286   {
2287         SetLastError(ERROR_INVALID_PARAMETER);
2288           return ERROR_INVALID_PARAMETER;
2289   }
2290
2291   if ((lpValueName) && (strlen(lpValueName) != 0))
2292   {
2293     RtlCreateUnicodeStringFromAsciiz(&ValueName, (LPSTR)lpValueName);
2294     pValueName = (LPWSTR)ValueName.Buffer;
2295   }
2296   else
2297   {
2298     pValueName = NULL;
2299   }
2300
2301   if ((dwType == REG_SZ) || (dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ))
2302   {
2303     RtlInitAnsiString(&AnsiString, NULL);
2304     AnsiString.Buffer = (LPSTR)lpData;
2305     AnsiString.Length = cbData;
2306     AnsiString.MaximumLength = cbData;
2307     RtlAnsiStringToUnicodeString(&Data, &AnsiString, TRUE);
2308     pData = (LPBYTE)Data.Buffer;
2309     DataSize = cbData * sizeof(WCHAR);
2310   }
2311   else
2312   {
2313     RtlInitUnicodeString(&Data, NULL);
2314     pData = (LPBYTE)lpData;
2315     DataSize = cbData;
2316   }
2317
2318   ErrorCode = RegSetValueExW(
2319           hKey,
2320           pValueName,
2321           Reserved,
2322           dwType,
2323     pData,
2324           DataSize);
2325
2326   if (pValueName)
2327   {
2328     RtlFreeHeap(RtlGetProcessHeap(), 0, ValueName.Buffer);
2329   }
2330
2331   if (Data.Buffer)
2332   {
2333     RtlFreeHeap(RtlGetProcessHeap(), 0, Data.Buffer);
2334   }
2335
2336   return ErrorCode;
2337 }
2338
2339
2340 /************************************************************************
2341  *      RegSetValueExW
2342  */
2343 LONG
2344 STDCALL
2345 RegSetValueExW(
2346         HKEY            hKey,
2347         LPCWSTR         lpValueName,
2348         DWORD           Reserved,
2349         DWORD           dwType,
2350         CONST BYTE      *lpData,
2351         DWORD           cbData
2352         )
2353 {
2354         UNICODE_STRING ValueName;
2355   PUNICODE_STRING pValueName;
2356   HANDLE KeyHandle;
2357         NTSTATUS Status;
2358   LONG ErrorCode;
2359
2360   Status = MapDefaultKey(&KeyHandle, hKey);
2361         if (!NT_SUCCESS(Status))
2362         {
2363                 ErrorCode = RtlNtStatusToDosError(Status);
2364                 SetLastError(ErrorCode);
2365                 return ErrorCode;
2366         }
2367
2368   if (lpValueName)
2369   {
2370           RtlInitUnicodeString(&ValueName, lpValueName);
2371     pValueName = &ValueName;
2372   }
2373   else
2374   {
2375     pValueName = NULL;
2376   }
2377
2378         Status = NtSetValueKey(
2379     KeyHandle,
2380           pValueName,
2381                 0,
2382                 dwType,
2383                 (PVOID)lpData,
2384                 (ULONG)cbData);
2385         if (!NT_SUCCESS(Status))
2386         {
2387                 LONG ErrorCode = RtlNtStatusToDosError(Status);
2388                 SetLastError (ErrorCode);
2389                 return ErrorCode;
2390         }
2391
2392         return ERROR_SUCCESS;
2393 }
2394
2395
2396 /************************************************************************
2397  *      RegSetValueW
2398  */
2399 LONG
2400 STDCALL
2401 RegSetValueW(
2402         HKEY    hKey,
2403         LPCWSTR lpSubKey,
2404         DWORD   dwType,
2405         LPCWSTR lpData,
2406         DWORD   cbData
2407         )
2408 {
2409         NTSTATUS                errCode;
2410         UNICODE_STRING          SubKeyString;
2411         OBJECT_ATTRIBUTES       ObjectAttributes;
2412         HANDLE                  KeyHandle;
2413   HANDLE                        RealKey;
2414         LONG                      ErrorCode;
2415   BOOL        CloseRealKey;
2416
2417         errCode = MapDefaultKey(&KeyHandle, hKey);
2418         if (!NT_SUCCESS(errCode))
2419         {
2420                 ErrorCode = RtlNtStatusToDosError(errCode);
2421                 SetLastError (ErrorCode);
2422                 return ErrorCode;
2423         }
2424
2425   if ((lpSubKey) && (wcslen(lpSubKey) != 0))
2426   {
2427
2428           RtlInitUnicodeString(&SubKeyString,
2429                              (LPWSTR)lpSubKey);
2430
2431           InitializeObjectAttributes(&ObjectAttributes,
2432                                    &SubKeyString,
2433                                    OBJ_CASE_INSENSITIVE,
2434                                    KeyHandle,
2435                                    NULL);
2436
2437           errCode = NtOpenKey(
2438                         &RealKey,
2439                         KEY_ALL_ACCESS,
2440                         & ObjectAttributes
2441                         );
2442           if ( !NT_SUCCESS(errCode) )
2443           {
2444                 ErrorCode = RtlNtStatusToDosError(errCode);
2445                 SetLastError(ErrorCode);
2446                 return ErrorCode;
2447           }
2448     CloseRealKey = TRUE;
2449   }
2450   else
2451   {
2452     RealKey = hKey;
2453     CloseRealKey = FALSE;
2454   }
2455
2456   ErrorCode = RegSetValueExW(
2457           RealKey,
2458           NULL,
2459           0,
2460           dwType,
2461     (LPBYTE)lpData,
2462           cbData);
2463
2464   if (CloseRealKey)
2465   {
2466     NtClose(RealKey);
2467   }
2468
2469   return ErrorCode;
2470 }
2471
2472
2473 /************************************************************************
2474  *      RegUnLoadKeyA
2475  */
2476 LONG
2477 STDCALL
2478 RegUnLoadKeyA(
2479         HKEY    hKey,
2480         LPCSTR  lpSubKey
2481         )
2482 {
2483   UNIMPLEMENTED;
2484         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2485         return ERROR_CALL_NOT_IMPLEMENTED;
2486 }
2487
2488
2489 /************************************************************************
2490  *      RegUnLoadKeyW
2491  */
2492 LONG
2493 STDCALL
2494 RegUnLoadKeyW(
2495         HKEY    hKey,
2496         LPCWSTR lpSubKey
2497         )
2498 {
2499   UNIMPLEMENTED;
2500         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2501         return ERROR_CALL_NOT_IMPLEMENTED;
2502 }
2503
2504 /* EOF */