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