implemented RegDeleteTree() (untested!)
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
index c368491..98a46ef 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: reg.c,v 1.25 2003/07/10 15:05:55 chorns Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
@@ -8,33 +8,39 @@
  * UPDATE HISTORY:
  *                  Created 01/11/98
  *                  19990309 EA Stubs
+ *                  20050502 Fireball imported some stuff from WINE
  */
 
 /* INCLUDES *****************************************************************/
 
-#define NTOS_MODE_USER
-#include <ntos.h>
-#include <ddk/ntddk.h>
-#include <ntdll/rtl.h>
-#include <windows.h>
-#include <wchar.h>
-
+#include <advapi32.h>
 #define NDEBUG
-#include <debug.h>
-
+#include <wine/debug.h>
 
-/* GLOBALS ******************************************************************/
+/* DEFINES ******************************************************************/
 
 #define MAX_DEFAULT_HANDLES   6
+#define REG_MAX_NAME_SIZE     256
+#define REG_MAX_DATA_SIZE     2048
 
-static CRITICAL_SECTION HandleTableCS;
-static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
+/* FIXME: should go into msvcrt.h header? */
+#define offsetof(s,m)       (size_t)&(((s*)NULL)->m)
 
+/* GLOBALS ******************************************************************/
+
+static RTL_CRITICAL_SECTION HandleTableCS;
+static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
+static HANDLE ProcessHeap;
+static BOOLEAN DefaultHandlesDisabled = FALSE;
 
 /* PROTOTYPES ***************************************************************/
 
-static NTSTATUS MapDefaultKey (PHKEY ParentKey, HKEY Key);
+static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
 static VOID CloseDefaultKeys(VOID);
+#define CloseDefaultKey(Handle)                                                \
+    if ((ULONG_PTR)Handle & 0x1) {                                             \
+        NtClose(Handle);                                                       \
+    }
 
 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
@@ -43,18 +49,25 @@ static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
 
 
 /* FUNCTIONS ****************************************************************/
+/* check if value type needs string conversion (Ansi<->Unicode) */
+inline static int is_string( DWORD type )
+{
+    return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
+}
 
 /************************************************************************
  *  RegInitDefaultHandles
  */
 BOOL
-RegInitialize(VOID)
+RegInitialize (VOID)
 {
-  DPRINT("RegInitialize()\n");
+  TRACE("RegInitialize()\n");
+
+  ProcessHeap = RtlGetProcessHeap();
+  RtlZeroMemory (DefaultHandleTable,
+                MAX_DEFAULT_HANDLES * sizeof(HANDLE));
+  RtlInitializeCriticalSection (&HandleTableCS);
 
-  RtlZeroMemory(DefaultHandleTable,
-               MAX_DEFAULT_HANDLES * sizeof(HANDLE));
-  RtlInitializeCriticalSection(&HandleTableCS);
   return TRUE;
 }
 
@@ -63,66 +76,82 @@ RegInitialize(VOID)
  *  RegInit
  */
 BOOL
-RegCleanup(VOID)
+RegCleanup (VOID)
 {
-  DPRINT("RegCleanup()\n");
+  TRACE("RegCleanup()\n");
+
+  CloseDefaultKeys ();
+  RtlDeleteCriticalSection (&HandleTableCS);
 
-  CloseDefaultKeys();
-  RtlDeleteCriticalSection(&HandleTableCS);
-  return(TRUE);
+  return TRUE;
 }
 
 
 static NTSTATUS
-MapDefaultKey(PHKEY RealKey,
-             HKEY Key)
+MapDefaultKey (OUT PHANDLE RealKey,
+               IN HKEY Key)
 {
   PHANDLE Handle;
   ULONG Index;
+  BOOLEAN DoOpen;
   NTSTATUS Status = STATUS_SUCCESS;
 
-  DPRINT("MapDefaultKey (Key %x)\n", Key);
+  TRACE("MapDefaultKey (Key %x)\n", Key);
 
   if (((ULONG)Key & 0xF0000000) != 0x80000000)
     {
-      *RealKey = Key;
-      return(STATUS_SUCCESS);
+      *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
+      return STATUS_SUCCESS;
     }
 
   /* Handle special cases here */
   Index = (ULONG)Key & 0x0FFFFFFF;
   if (Index >= MAX_DEFAULT_HANDLES)
-    return(STATUS_INVALID_PARAMETER);
+    {
+      return STATUS_INVALID_PARAMETER;
+    }
 
-  RtlEnterCriticalSection(&HandleTableCS);
-  Handle = &DefaultHandleTable[Index];
-  if (*Handle == NULL)
+  RtlEnterCriticalSection (&HandleTableCS);
+  
+  if (!DefaultHandlesDisabled)
+    {
+      Handle = &DefaultHandleTable[Index];
+      DoOpen = (*Handle == NULL);
+    }
+  else
+    {
+      Handle = RealKey;
+      DoOpen = TRUE;
+    }
+  
+  if (DoOpen)
     {
       /* create/open the default handle */
       switch (Index)
        {
          case 0: /* HKEY_CLASSES_ROOT */
-           Status = OpenClassesRootKey(Handle);
+           Status = OpenClassesRootKey (Handle);
            break;
 
          case 1: /* HKEY_CURRENT_USER */
-           Status = RtlOpenCurrentUser(KEY_ALL_ACCESS, Handle);
+           Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
+                                        Handle);
            break;
 
          case 2: /* HKEY_LOCAL_MACHINE */
-           Status = OpenLocalMachineKey(Handle);
+           Status = OpenLocalMachineKey (Handle);
            break;
 
          case 3: /* HKEY_USERS */
-           Status = OpenUsersKey(Handle);
+           Status = OpenUsersKey (Handle);
            break;
 #if 0
          case 4: /* HKEY_PERFORMANCE_DATA */
-           Status = OpenPerformanceDataKey(Handle);
+           Status = OpenPerformanceDataKey (Handle);
            break;
 #endif
          case 5: /* HKEY_CURRENT_CONFIG */
-           Status = OpenCurrentConfigKey(Handle);
+           Status = OpenCurrentConfigKey (Handle);
            break;
 
          case 6: /* HKEY_DYN_DATA */
@@ -130,137 +159,163 @@ MapDefaultKey(PHKEY RealKey,
            break;
 
          default:
-           DPRINT("MapDefaultHandle() no handle creator\n");
+           WARN("MapDefaultHandle() no handle creator\n");
            Status = STATUS_INVALID_PARAMETER;
+           break;
        }
     }
-  RtlLeaveCriticalSection(&HandleTableCS);
 
-  if (NT_SUCCESS(Status))
-    {
-      *RealKey = (HKEY)*Handle;
-    }
-
-   return(Status);
+   if (NT_SUCCESS(Status))
+     {
+       if (!DefaultHandlesDisabled)
+          *RealKey = *Handle;
+       else
+          *(PULONG_PTR)Handle |= 0x1;
+     }
+  
+   RtlLeaveCriticalSection (&HandleTableCS);
+
+   return Status;
 }
 
 
 static VOID
-CloseDefaultKeys(VOID)
+CloseDefaultKeys (VOID)
 {
   ULONG i;
 
-  RtlEnterCriticalSection(&HandleTableCS);
+  RtlEnterCriticalSection (&HandleTableCS);
   for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
     {
       if (DefaultHandleTable[i] != NULL)
        {
-         NtClose(DefaultHandleTable[i]);
+         NtClose (DefaultHandleTable[i]);
          DefaultHandleTable[i] = NULL;
        }
     }
-  RtlLeaveCriticalSection(&HandleTableCS);
+  RtlLeaveCriticalSection (&HandleTableCS);
 }
 
 
 static NTSTATUS
-OpenClassesRootKey(PHANDLE KeyHandle)
+OpenClassesRootKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\Software\\CLASSES");
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
 
-  DPRINT("OpenClassesRootKey()\n");
+  TRACE("OpenClassesRootKey()\n");
 
-  InitializeObjectAttributes(&Attributes,
-                            &KeyName,
-                            OBJ_CASE_INSENSITIVE,
-                            NULL,
-                            NULL);
-  return(NtOpenKey(KeyHandle,
-                  KEY_ALL_ACCESS,
-                  &Attributes));
+  InitializeObjectAttributes (&Attributes,
+                             &KeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  return NtOpenKey (KeyHandle,
+                   MAXIMUM_ALLOWED,
+                   &Attributes);
 }
 
 
 static NTSTATUS
-OpenLocalMachineKey(PHANDLE KeyHandle)
+OpenLocalMachineKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine");
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
+  NTSTATUS Status;
+
+  TRACE("OpenLocalMachineKey()\n");
 
-  DPRINT("OpenLocalMachineKey()\n");
+  InitializeObjectAttributes (&Attributes,
+                             &KeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  Status = NtOpenKey (KeyHandle,
+                     MAXIMUM_ALLOWED,
+                     &Attributes);
 
-  InitializeObjectAttributes(&Attributes,
-           &KeyName,
-           OBJ_CASE_INSENSITIVE,
-           NULL,
-           NULL);
-  return(NtOpenKey(KeyHandle,
-       KEY_ALL_ACCESS,
-       &Attributes));
+  TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
+  return Status;
 }
 
 
 static NTSTATUS
-OpenUsersKey(PHANDLE KeyHandle)
+OpenUsersKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\User");
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
 
-  DPRINT("OpenUsersKey()\n");
+  TRACE("OpenUsersKey()\n");
 
-  InitializeObjectAttributes(&Attributes,
-           &KeyName,
-           OBJ_CASE_INSENSITIVE,
-           NULL,
-           NULL);
-  return(NtOpenKey(KeyHandle,
-       KEY_ALL_ACCESS,
-       &Attributes));
+  InitializeObjectAttributes (&Attributes,
+                             &KeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  return NtOpenKey (KeyHandle,
+                   MAXIMUM_ALLOWED,
+                   &Attributes);
 }
 
 
 static NTSTATUS
-OpenCurrentConfigKey(PHANDLE KeyHandle)
+OpenCurrentConfigKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
   UNICODE_STRING KeyName =
-  UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
+  RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
+
+  TRACE("OpenCurrentConfigKey()\n");
+
+  InitializeObjectAttributes (&Attributes,
+                             &KeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  return NtOpenKey (KeyHandle,
+                   MAXIMUM_ALLOWED,
+                   &Attributes);
+}
 
-  DPRINT("OpenCurrentConfigKey()\n");
 
-  InitializeObjectAttributes(&Attributes,
-           &KeyName,
-           OBJ_CASE_INSENSITIVE,
-           NULL,
-           NULL);
-  return(NtOpenKey(KeyHandle,
-       KEY_ALL_ACCESS,
-       &Attributes));
+/************************************************************************
+ *  RegDisablePredefinedCacheEx
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegDisablePredefinedCacheEx(VOID)
+{
+    RtlEnterCriticalSection (&HandleTableCS);
+    DefaultHandlesDisabled = TRUE;
+    RtlLeaveCriticalSection (&HandleTableCS);
+    return ERROR_SUCCESS;
 }
 
+
 /************************************************************************
  *  RegCloseKey
  *
  * @implemented
  */
 LONG STDCALL
-RegCloseKey(HKEY hKey)
+RegCloseKey (HKEY hKey)
 {
   NTSTATUS Status;
 
   /* don't close null handle or a pseudo handle */
   if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
-    return(ERROR_INVALID_HANDLE);
+    {
+      return ERROR_INVALID_HANDLE;
+    }
 
-  Status = NtClose(hKey);
+  Status = NtClose (hKey);
   if (!NT_SUCCESS(Status))
     {
-       LONG ErrorCode = RtlNtStatusToDosError(Status);
-       SetLastError (ErrorCode);
-       return ErrorCode;
+      return RtlNtStatusToDosError (Status);
     }
-  return(ERROR_SUCCESS);
+
+  return ERROR_SUCCESS;
 }
 
 
@@ -270,91 +325,317 @@ RegCloseKey(HKEY hKey)
  * @unimplemented
  */
 LONG STDCALL
-RegConnectRegistryA(LPCSTR lpMachineName,
-        HKEY hKey,
-        PHKEY phkResult)
+RegConnectRegistryA (LPCSTR lpMachineName,
+                    HKEY hKey,
+                    PHKEY phkResult)
 {
   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
   return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
+/************************************************************************
+ *  RegCopyTreeW
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegCopyTreeW(IN HKEY hKeySrc,
+             IN LPCWSTR lpSubKey  OPTIONAL,
+             IN HKEY hKeyDest)
+{
+    HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+    
+    Status = MapDefaultKey(&KeyHandle,
+                           hKeySrc);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+    
+    Status = MapDefaultKey(&DestKeyHandle,
+                           hKeyDest);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup2;
+    }
+
+    if (lpSubKey != NULL)
+    {
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        RtlInitUnicodeString(&SubKeyName,
+                             (LPWSTR)lpSubKey);
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
+
+        Status = NtOpenKey(&SubKeyHandle,
+                           KEY_READ,
+                           &ObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
+    
+    /* FIXME - copy all keys and values recursively */
+    Status = STATUS_NOT_IMPLEMENTED;
+    
+    if (SubKeyHandle != NULL)
+    {
+        NtClose(SubKeyHandle);
+    }
+    
+Cleanup:
+    CloseDefaultKey(DestKeyHandle);
+Cleanup2:
+    CloseDefaultKey(KeyHandle);
+    
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+    
+    return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ *  RegCopyTreeA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegCopyTreeA(IN HKEY hKeySrc,
+             IN LPCSTR lpSubKey  OPTIONAL,
+             IN HKEY hKeyDest)
+{
+    UNICODE_STRING SubKeyName;
+    LONG Ret;
+    
+    if (lpSubKey != NULL)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+                                              (LPSTR)lpSubKey))
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+    else
+        RtlInitUnicodeString(&SubKeyName,
+                             NULL);
+
+    Ret = RegCopyTreeW(hKeySrc,
+                       SubKeyName.Buffer,
+                       hKeyDest);
+
+    RtlFreeUnicodeString(&SubKeyName);
+    
+    return Ret;
+}
+
+
 /************************************************************************
  *  RegConnectRegistryW
  *
  * @unimplemented
  */
 LONG STDCALL
-RegConnectRegistryW(LPCWSTR lpMachineName,
-        HKEY hKey,
-        PHKEY phkResult)
+RegConnectRegistryW (LPCWSTR lpMachineName,
+                    HKEY hKey,
+                    PHKEY phkResult)
 {
   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
   return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
+/************************************************************************
+ *  CreateNestedKey
+ *
+ *  Create key and all necessary intermediate keys
+ */
+static NTSTATUS
+CreateNestedKey(PHKEY KeyHandle,
+               POBJECT_ATTRIBUTES ObjectAttributes,
+                PUNICODE_STRING ClassString,
+                DWORD dwOptions,
+                REGSAM samDesired,
+                DWORD *lpdwDisposition)
+{
+  OBJECT_ATTRIBUTES LocalObjectAttributes;
+  UNICODE_STRING LocalKeyName;
+  ULONG Disposition;
+  NTSTATUS Status;
+  ULONG FullNameLength;
+  ULONG Length;
+  PWCHAR Ptr;
+  HANDLE LocalKeyHandle;
+
+  Status = NtCreateKey((PHANDLE) KeyHandle,
+                       samDesired,
+                       ObjectAttributes,
+                       0,
+                       ClassString,
+                       dwOptions,
+                       (PULONG)lpdwDisposition);
+  TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
+  if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    return Status;
+
+  /* Copy object attributes */
+  RtlCopyMemory (&LocalObjectAttributes,
+                ObjectAttributes,
+                sizeof(OBJECT_ATTRIBUTES));
+  RtlCreateUnicodeString (&LocalKeyName,
+                         ObjectAttributes->ObjectName->Buffer);
+  LocalObjectAttributes.ObjectName = &LocalKeyName;
+  FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
+
+  /* Remove the last part of the key name and try to create the key again. */
+  while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+      Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
+      if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
+       {
+         Status = STATUS_UNSUCCESSFUL;
+         break;
+       }
+      *Ptr = (WCHAR)0;
+      LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
+
+      Status = NtCreateKey (&LocalKeyHandle,
+                           KEY_ALL_ACCESS,
+                           &LocalObjectAttributes,
+                           0,
+                           NULL,
+                           0,
+                           &Disposition);
+      TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
+    }
+
+  if (!NT_SUCCESS(Status))
+    {
+      RtlFreeUnicodeString (&LocalKeyName);
+      return Status;
+    }
+
+  /* Add removed parts of the key name and create them too. */
+  Length = wcslen (LocalKeyName.Buffer);
+  while (TRUE)
+    {
+      NtClose (LocalKeyHandle);
+
+      LocalKeyName.Buffer[Length] = L'\\';
+      Length = wcslen (LocalKeyName.Buffer);
+      LocalKeyName.Length = Length * sizeof(WCHAR);
+
+      if (Length == FullNameLength)
+        {
+          Status = NtCreateKey((PHANDLE) KeyHandle,
+                               samDesired,
+                               ObjectAttributes,
+                               0,
+                               ClassString,
+                               dwOptions,
+                               (PULONG)lpdwDisposition);
+          break;
+        }
+      Status = NtCreateKey (&LocalKeyHandle,
+                           KEY_CREATE_SUB_KEY,
+                           &LocalObjectAttributes,
+                           0,
+                           NULL,
+                           0,
+                           &Disposition);
+      TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
+      if (!NT_SUCCESS(Status))
+       break;
+    }
+
+  RtlFreeUnicodeString (&LocalKeyName);
+
+  return Status;
+}
+
+
 /************************************************************************
  *  RegCreateKeyExA
  *
  * @implemented
  */
 LONG STDCALL
-RegCreateKeyExA(HKEY hKey,
-    LPCSTR lpSubKey,
-    DWORD Reserved,
-    LPSTR lpClass,
-    DWORD dwOptions,
-    REGSAM samDesired,
-    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-    PHKEY phkResult,
-    LPDWORD lpdwDisposition)
+RegCreateKeyExA (HKEY hKey,
+                LPCSTR lpSubKey,
+                DWORD Reserved,
+                LPSTR lpClass,
+                DWORD dwOptions,
+                REGSAM samDesired,
+                LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+                PHKEY phkResult,
+                LPDWORD lpdwDisposition)
 {
   UNICODE_STRING SubKeyString;
   UNICODE_STRING ClassString;
   OBJECT_ATTRIBUTES Attributes;
+  HANDLE ParentKey;
   NTSTATUS Status;
-  HKEY ParentKey;
 
-  DPRINT("RegCreateKeyExW() called\n");
+  TRACE("RegCreateKeyExA() called\n");
 
   /* get the real parent key */
-  Status = MapDefaultKey(&ParentKey, hKey);
+  Status = MapDefaultKey (&ParentKey,
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
-      LONG ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+      return RtlNtStatusToDosError (Status);
     }
-  DPRINT("ParentKey %x\n", (ULONG)ParentKey);
+  TRACE("ParentKey %x\n", (ULONG)ParentKey);
 
   if (lpClass != NULL)
-    RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass);
-  RtlCreateUnicodeStringFromAsciiz(&SubKeyString, (LPSTR)lpSubKey);
-  InitializeObjectAttributes(&Attributes,
-           &SubKeyString,
-           OBJ_CASE_INSENSITIVE,
-           (HANDLE)ParentKey,
-           (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
-  Status = NtCreateKey(phkResult,
-           samDesired,
-           &Attributes,
-           0,
-           (lpClass == NULL)? NULL : &ClassString,
-           dwOptions,
-           (PULONG)lpdwDisposition);
-  RtlFreeUnicodeString(&SubKeyString);
+    {
+      RtlCreateUnicodeStringFromAsciiz (&ClassString,
+                                       lpClass);
+    }
+
+  RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
+                                  (LPSTR)lpSubKey);
+  InitializeObjectAttributes (&Attributes,
+                             &SubKeyString,
+                             OBJ_CASE_INSENSITIVE,
+                             (HANDLE)ParentKey,
+                             (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
+  Status = CreateNestedKey(phkResult,
+                          &Attributes,
+                          (lpClass == NULL)? NULL : &ClassString,
+                          dwOptions,
+                          samDesired,
+                          lpdwDisposition);
+  RtlFreeUnicodeString (&SubKeyString);
   if (lpClass != NULL)
-    RtlFreeUnicodeString(&ClassString);
-  DPRINT("Status %x\n", Status);
+    {
+      RtlFreeUnicodeString (&ClassString);
+    }
+
+  CloseDefaultKey(ParentKey);
+
+  TRACE("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
     {
-      LONG ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
+      return RtlNtStatusToDosError (Status);
     }
 
-  return(ERROR_SUCCESS);
+  return ERROR_SUCCESS;
 }
 
 
@@ -364,52 +645,57 @@ RegCreateKeyExA(HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegCreateKeyExW(HKEY hKey,
-    LPCWSTR   lpSubKey,
-    DWORD     Reserved,
-    LPWSTR    lpClass,
-    DWORD     dwOptions,
-    REGSAM    samDesired,
-    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-    PHKEY     phkResult,
-    LPDWORD   lpdwDisposition)
+RegCreateKeyExW (HKEY hKey,
+                LPCWSTR lpSubKey,
+                DWORD Reserved,
+                LPWSTR lpClass,
+                DWORD dwOptions,
+                REGSAM samDesired,
+                LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+                PHKEY phkResult,
+                LPDWORD lpdwDisposition)
 {
   UNICODE_STRING SubKeyString;
   UNICODE_STRING ClassString;
   OBJECT_ATTRIBUTES Attributes;
+  HANDLE ParentKey;
   NTSTATUS Status;
-  HKEY ParentKey;
 
-  DPRINT("RegCreateKeyExW() called\n");
+  TRACE("RegCreateKeyExW() called\n");
 
   /* get the real parent key */
-  Status = MapDefaultKey (&ParentKey, hKey);
-  if (!NT_SUCCESS(Status)) {
-    LONG ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  DPRINT("ParentKey %x\n", (ULONG)ParentKey);
-  RtlInitUnicodeString (&ClassString, lpClass);
-  RtlInitUnicodeString (&SubKeyString, lpSubKey);
+  Status = MapDefaultKey (&ParentKey,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError(Status);
+    }
+  TRACE("ParentKey %x\n", (ULONG)ParentKey);
+
+  RtlInitUnicodeString (&ClassString,
+                       lpClass);
+  RtlInitUnicodeString (&SubKeyString,
+                       lpSubKey);
   InitializeObjectAttributes (&Attributes,
-            &SubKeyString,
-            OBJ_CASE_INSENSITIVE,
-            (HANDLE)ParentKey,
-            (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
-  Status = NtCreateKey (phkResult,
-            samDesired,
-            &Attributes,
-            0,
-            (lpClass == NULL)? NULL : &ClassString,
-            dwOptions,
-            (PULONG)lpdwDisposition);
-  DPRINT("Status %x\n", Status);
-  if (!NT_SUCCESS(Status)) {
-    LONG ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
+                             &SubKeyString,
+                             OBJ_CASE_INSENSITIVE,
+                             (HANDLE)ParentKey,
+                             (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
+  Status = CreateNestedKey(phkResult,
+                          &Attributes,
+                           (lpClass == NULL)? NULL : &ClassString,
+                           dwOptions,
+                           samDesired,
+                           lpdwDisposition);
+
+  CloseDefaultKey(ParentKey);
+
+  TRACE("Status %x\n", Status);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
   return ERROR_SUCCESS;
 }
 
@@ -420,19 +706,19 @@ RegCreateKeyExW(HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegCreateKeyA(HKEY hKey,
-        LPCSTR lpSubKey,
-        PHKEY phkResult)
+RegCreateKeyA (HKEY hKey,
+              LPCSTR lpSubKey,
+              PHKEY phkResult)
 {
-  return(RegCreateKeyExA(hKey,
-       lpSubKey,
-       0,
-       NULL,
-       0,
-       KEY_ALL_ACCESS,
-       NULL,
-       phkResult,
-       NULL));
+  return RegCreateKeyExA (hKey,
+                         lpSubKey,
+                         0,
+                         NULL,
+                         0,
+                         MAXIMUM_ALLOWED,
+                         NULL,
+                         phkResult,
+                         NULL);
 }
 
 
@@ -442,19 +728,19 @@ RegCreateKeyA(HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegCreateKeyW(HKEY hKey,
-        LPCWSTR lpSubKey,
-        PHKEY phkResult)
+RegCreateKeyW (HKEY hKey,
+              LPCWSTR lpSubKey,
+              PHKEY phkResult)
 {
-  return(RegCreateKeyExW(hKey,
-       lpSubKey,
-       0,
-       NULL,
-       0,
-       KEY_ALL_ACCESS,
-       NULL,
-       phkResult,
-       NULL));
+  return RegCreateKeyExW (hKey,
+                         lpSubKey,
+                         0,
+                         NULL,
+                         0,
+                         MAXIMUM_ALLOWED,
+                         NULL,
+                         phkResult,
+                         NULL);
 }
 
 
@@ -463,53 +749,49 @@ RegCreateKeyW(HKEY hKey,
  *
  * @implemented
  */
-LONG
-STDCALL
-RegDeleteKeyA(
-  HKEY  hKey,
-  LPCSTR  lpSubKey)
+LONG STDCALL
+RegDeleteKeyA (HKEY hKey,
+              LPCSTR lpSubKey)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING SubKeyStringW;
-  ANSI_STRING SubKeyStringA;
-//  HANDLE ParentKey;
-  HKEY ParentKey;
+  UNICODE_STRING SubKeyName;
+  HANDLE ParentKey;
   HANDLE TargetKey;
   NTSTATUS Status;
-  LONG ErrorCode;
 
-  Status = MapDefaultKey(&ParentKey, hKey);
+  Status = MapDefaultKey (&ParentKey,
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+      return RtlNtStatusToDosError (Status);
     }
 
-  RtlInitAnsiString(&SubKeyStringA, (LPSTR)lpSubKey);
-  RtlAnsiStringToUnicodeString(&SubKeyStringW, &SubKeyStringA, TRUE);
+  RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
+                                   (LPSTR)lpSubKey);
   InitializeObjectAttributes(&ObjectAttributes,
-                            &SubKeyStringW,
+                            &SubKeyName,
                             OBJ_CASE_INSENSITIVE,
-                            (HANDLE)ParentKey,
+                            ParentKey,
                             NULL);
 
-  Status = NtOpenKey(&TargetKey, DELETE, &ObjectAttributes);
-  RtlFreeUnicodeString(&SubKeyStringW);
+  Status = NtOpenKey (&TargetKey,
+                     DELETE,
+                     &ObjectAttributes);
+  RtlFreeUnicodeString (&SubKeyName);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return ErrorCode;
+      goto Cleanup;
     }
 
-  Status = NtDeleteKey(TargetKey);
-  NtClose(TargetKey);
+  Status = NtDeleteKey (TargetKey);
+  NtClose (TargetKey);
+  
+Cleanup:
+  CloseDefaultKey(ParentKey);
+
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return ErrorCode;
+      return RtlNtStatusToDosError(Status);
     }
 
   return ERROR_SUCCESS;
@@ -521,1001 +803,1804 @@ RegDeleteKeyA(
  *
  * @implemented
  */
-LONG
-STDCALL
-RegDeleteKeyW(
-  HKEY  hKey,
-  LPCWSTR lpSubKey)
+LONG STDCALL
+RegDeleteKeyW (HKEY hKey,
+              LPCWSTR lpSubKey)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING SubKeyString;
-  HKEY ParentKey;
+  UNICODE_STRING SubKeyName;
+  HANDLE ParentKey;
   HANDLE TargetKey;
   NTSTATUS Status;
-  LONG ErrorCode;
 
-  Status = MapDefaultKey(&ParentKey, hKey);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
+  Status = MapDefaultKey (&ParentKey,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
 
+  RtlInitUnicodeString (&SubKeyName,
+                       (LPWSTR)lpSubKey);
   InitializeObjectAttributes (&ObjectAttributes,
-            &SubKeyString,
-            OBJ_CASE_INSENSITIVE,
-            (HANDLE)ParentKey,
-            NULL);
-  Status = NtOpenKey(&TargetKey, DELETE, &ObjectAttributes);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  Status = NtDeleteKey(TargetKey);
-  NtClose(TargetKey);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  return ERROR_SUCCESS;
-}
+                             &SubKeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             ParentKey,
+                             NULL);
+  Status = NtOpenKey (&TargetKey,
+                     DELETE,
+                     &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      goto Cleanup;
+    }
 
+  Status = NtDeleteKey (TargetKey);
+  NtClose (TargetKey);
+  
+Cleanup:
+  CloseDefaultKey(ParentKey);
 
-/************************************************************************
- *  RegDeleteValueA
- *
- * @implemented
- */
-LONG
-STDCALL
-RegDeleteValueA(
-  HKEY  hKey,
-  LPCSTR  lpValueName)
-{
-  UNICODE_STRING ValueNameW;
-  ANSI_STRING ValueNameA;
-  NTSTATUS Status;
-  LONG ErrorCode;
-  HKEY KeyHandle;
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  RtlInitAnsiString(&ValueNameA, (LPSTR)lpValueName);
-  RtlAnsiStringToUnicodeString(&ValueNameW, &ValueNameA, TRUE);
-  Status = NtDeleteValueKey(KeyHandle, &ValueNameW);
-  RtlFreeUnicodeString (&ValueNameW);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
   return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
- *  RegDeleteValueW
+ *  RegDeleteKeyValueW
  *
  * @implemented
  */
-LONG
-STDCALL
-RegDeleteValueW(
-  HKEY  hKey,
-  LPCWSTR lpValueName)
+LONG STDCALL
+RegDeleteKeyValueW(IN HKEY hKey,
+                   IN LPCWSTR lpSubKey  OPTIONAL,
+                   IN LPCWSTR lpValueName  OPTIONAL)
 {
-  UNICODE_STRING ValueName;
-  NTSTATUS Status;
-  LONG ErrorCode;
-  HKEY KeyHandle;
+    UNICODE_STRING ValueName;
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status))
-  {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  RtlInitUnicodeString(&ValueName, (LPWSTR)lpValueName);
-  Status = NtDeleteValueKey(KeyHandle, &ValueName);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  return ERROR_SUCCESS;
-}
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
 
+    if (lpSubKey != NULL)
+    {
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        RtlInitUnicodeString(&SubKeyName,
+                             (LPWSTR)lpSubKey);
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
+
+        Status = NtOpenKey(&SubKeyHandle,
+                           KEY_SET_VALUE,
+                           &ObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
 
-/************************************************************************
- *  RegEnumKeyExW
- *
- * @implemented
- */
-LONG
-STDCALL
-RegEnumKeyExW(
-  HKEY    hKey,
-  DWORD   dwIndex,
-  LPWSTR    lpName,
-  LPDWORD   lpcbName,
-  LPDWORD   lpReserved,
-  LPWSTR    lpClass,
-  LPDWORD   lpcbClass,
-  PFILETIME lpftLastWriteTime)
-{
-    PKEY_NODE_INFORMATION KeyInfo;
-  NTSTATUS Status;
-  DWORD dwError = ERROR_SUCCESS;
-  ULONG BufferSize;
-  ULONG ResultSize;
-  HKEY KeyHandle;
+    RtlInitUnicodeString(&ValueName,
+                         (LPWSTR)lpValueName);
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-    dwError = RtlNtStatusToDosError(Status);
-    SetLastError (dwError);
-    return dwError;
-  }
+    Status = NtDeleteValueKey(CurKey,
+                              &ValueName);
 
-  BufferSize = sizeof (KEY_NODE_INFORMATION) + *lpcbName * sizeof(WCHAR);
-  if (lpClass)
-    BufferSize += *lpcbClass;
-
-    //
-    // I think this is a memory leak, always allocated again below ???
-    //
-    // KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
-    //
-
-  /* We don't know the exact size of the data returned, so call
-     NtEnumerateKey() with a buffer size determined from parameters
-     to this function. If that call fails with a status code of
-     STATUS_BUFFER_OVERFLOW, allocate a new buffer and try again */
-  while (TRUE) {
-    KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
-    if (KeyInfo == NULL) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-    Status = NtEnumerateKey(
-      KeyHandle,
-      (ULONG)dwIndex,
-      KeyNodeInformation,
-      KeyInfo,
-      BufferSize,
-      &ResultSize);
-
-    DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
-
-    if (Status == STATUS_BUFFER_OVERFLOW) {
-      RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
-      BufferSize = ResultSize;
-      continue;
-    }
-    if (!NT_SUCCESS(Status)) {
-      dwError = RtlNtStatusToDosError(Status);
-      SetLastError(dwError);
-      break;
-    } else {
-      if ((lpClass) && (*lpcbClass != 0) && (KeyInfo->ClassLength > *lpcbClass)) {
-        dwError = ERROR_MORE_DATA;
-        SetLastError(dwError);
-        break;
-      }
-      RtlMoveMemory(lpName, KeyInfo->Name, KeyInfo->NameLength);
-      *lpcbName = (DWORD)(KeyInfo->NameLength / sizeof(WCHAR));
-      lpName[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
-      if (lpClass) {
-        RtlMoveMemory(lpClass,
-          (PVOID)((ULONG_PTR)KeyInfo->Name + KeyInfo->ClassOffset),
-          KeyInfo->ClassLength);
-        *lpcbClass = (DWORD)(KeyInfo->ClassLength / sizeof(WCHAR));
-      }
-      if (lpftLastWriteTime) {
-        /* FIXME: Fill lpftLastWriteTime */
-      }
-      break;
+    if (SubKeyHandle != NULL)
+    {
+        NtClose(SubKeyHandle);
     }
-  }
-  RtlFreeHeap (RtlGetProcessHeap(), 0, KeyInfo);
-  return dwError;
-}
-
+    
+Cleanup:
+    CloseDefaultKey(KeyHandle);
 
-/************************************************************************
- *  RegEnumKeyW
- *
- * @implemented
- */
-LONG
-STDCALL
-RegEnumKeyW(
-  HKEY  hKey,
-  DWORD dwIndex,
-  LPWSTR  lpName,
-  DWORD cbName)
-{
-  DWORD dwLength = cbName;
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
 
-  return RegEnumKeyExW(hKey,
-           dwIndex,
-           lpName,
-           &dwLength,
-           NULL,
-           NULL,
-           NULL,
-           NULL);
+    return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
- *  RegEnumKeyExA
+ *  RegDeleteKeyValueA
  *
  * @implemented
  */
-LONG
-STDCALL
-RegEnumKeyExA(
-  HKEY    hKey,
-  DWORD   dwIndex,
-  LPSTR   lpName,
-  LPDWORD   lpcbName,
-  LPDWORD   lpReserved,
-  LPSTR   lpClass,
-  LPDWORD   lpcbClass,
-  PFILETIME lpftLastWriteTime)
-{
-  WCHAR Name[MAX_PATH+1];
-  UNICODE_STRING UnicodeStringName;
-  WCHAR Class[MAX_PATH+1];
-  UNICODE_STRING UnicodeStringClass;
-  ANSI_STRING AnsiString;
-  LONG ErrorCode;
-  DWORD NameLength;
-  DWORD ClassLength;
+LONG STDCALL
+RegDeleteKeyValueA(IN HKEY hKey,
+                   IN LPCSTR lpSubKey  OPTIONAL,
+                   IN LPCSTR lpValueName  OPTIONAL)
+{
+    UNICODE_STRING SubKey, ValueName;
+    LONG Ret;
+    
+    if (lpSubKey != NULL)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKey,
+                                              (LPSTR)lpSubKey))
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+    else
+        RtlInitUnicodeString(&SubKey,
+                             NULL);
 
-  DPRINT("hKey 0x%x  dwIndex %d  lpName 0x%x  *lpcbName %d  lpClass 0x%x  lpcbClass %d\n",
-    hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass);
+    if (lpValueName != NULL)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&ValueName,
+                                              (LPSTR)lpValueName))
+        {
+            RtlFreeUnicodeString(&SubKey);
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+    else
+        RtlInitUnicodeString(&ValueName,
+                             NULL);
+
+    Ret = RegDeleteKeyValueW(hKey,
+                             SubKey.Buffer,
+                             SubKey.Buffer);
+
+    RtlFreeUnicodeString(&SubKey);
+    RtlFreeUnicodeString(&ValueName);
+    
+    return Ret;
+}
 
-  if ((lpClass) && (!lpcbClass)) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
-  }
-  RtlInitUnicodeString(&UnicodeStringName, NULL);
-  UnicodeStringName.Buffer = &Name[0];
-  UnicodeStringName.MaximumLength = sizeof(Name);
-  RtlInitUnicodeString(&UnicodeStringClass, NULL);
-  if (lpClass) {
-    UnicodeStringClass.Buffer = &Class[0];
-    UnicodeStringClass.MaximumLength = sizeof(Class);
-    ClassLength = *lpcbClass;
-  } else {
-    ClassLength = 0;
-  }
-  NameLength = *lpcbName;
-  ErrorCode = RegEnumKeyExW(
-    hKey,
-    dwIndex,
-    UnicodeStringName.Buffer,
-    &NameLength,
-    lpReserved,
-    UnicodeStringClass.Buffer,
-    &ClassLength,
-    lpftLastWriteTime);
-
-  if (ErrorCode != ERROR_SUCCESS)
-    return ErrorCode;
 
-  UnicodeStringName.Length = NameLength * sizeof(WCHAR);
-  UnicodeStringClass.Length = ClassLength * sizeof(WCHAR);
-  RtlInitAnsiString(&AnsiString, NULL);
-  AnsiString.Buffer = lpName;
-  AnsiString.MaximumLength = *lpcbName;
-  RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeStringName, FALSE);
-  *lpcbName = AnsiString.Length;
-
-  DPRINT("Key Namea0 Length %d\n", UnicodeStringName.Length);
-  DPRINT("Key Namea1 Length %d\n", NameLength);
-  DPRINT("Key Namea Length %d\n", *lpcbName);
-  DPRINT("Key Namea %s\n", lpName);
-
-  if (lpClass) {
-    RtlInitAnsiString(&AnsiString, NULL);
-    AnsiString.Buffer = lpClass;
-    AnsiString.MaximumLength = *lpcbClass;
-    RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeStringClass, FALSE);
-    *lpcbClass = AnsiString.Length;
-  }
-  return ERROR_SUCCESS;
+static NTSTATUS
+RegpDeleteTree(IN HKEY hKey)
+{
+    typedef struct
+    {
+        LIST_ENTRY ListEntry;
+        HANDLE KeyHandle;
+    } REGP_DEL_KEYS, *PREG_DEL_KEYS;
+
+    LIST_ENTRY delQueueHead;
+    PREG_DEL_KEYS delKeys = NULL, newDelKeys;
+    HANDLE ProcessHeap;
+    ULONG BufferSize;
+    PKEY_BASIC_INFORMATION BasicInfo;
+    PREG_DEL_KEYS KeyDelRoot;
+    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status2 = STATUS_SUCCESS;
+    
+    InitializeListHead(&delQueueHead);
+    
+    ProcessHeap = RtlGetProcessHeap();
+    
+    /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
+             structure for the root key, we only do that for subkeys as we need to
+             allocate REGP_DEL_KEYS structures anyway! */
+    KeyDelRoot = RtlAllocateHeap(ProcessHeap,
+                                 0,
+                                 sizeof(REGP_DEL_KEYS));
+    if (KeyDelRoot != NULL)
+    {
+        KeyDelRoot->KeyHandle = hKey;
+        InsertTailList(&delQueueHead,
+                       &KeyDelRoot->ListEntry);
+
+        do
+        {
+            delKeys = CONTAINING_RECORD(delQueueHead.Flink,
+                                        REGP_DEL_KEYS,
+                                        ListEntry);
+
+            BufferSize = 0;
+            BasicInfo = NULL;
+            newDelKeys = NULL;
+
+ReadFirstSubKey:
+            /* check if this key contains subkeys and delete them first by queuing
+               them at the head of the list */
+            Status2 = NtEnumerateKey(delKeys->KeyHandle,
+                                     0,
+                                     KeyBasicInformation,
+                                     BasicInfo,
+                                     BufferSize,
+                                     &BufferSize);
+
+            if (NT_SUCCESS(Status2))
+            {
+                OBJECT_ATTRIBUTES ObjectAttributes;
+                UNICODE_STRING SubKeyName;
+                
+                ASSERT(newDelKeys != NULL);
+                ASSERT(BasicInfo != NULL);
+
+                /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
+                SubKeyName.Length = BasicInfo->NameLength;
+                SubKeyName.MaximumLength = BasicInfo->NameLength;
+                SubKeyName.Buffer = BasicInfo->Name;
+
+                InitializeObjectAttributes(&ObjectAttributes,
+                                           &SubKeyName,
+                                           OBJ_CASE_INSENSITIVE,
+                                           delKeys->KeyHandle,
+                                           NULL);
+
+                /* open the subkey */
+                Status2 = NtOpenKey(&newDelKeys->KeyHandle,
+                                    DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                                    &ObjectAttributes);
+                if (!NT_SUCCESS(Status2))
+                {
+                    goto SubKeyFailure;
+                }
+
+                /* enqueue this key to the head of the deletion queue */
+                InsertHeadList(&delQueueHead,
+                               &newDelKeys->ListEntry);
+
+                /* try again from the head of the list */
+                continue;
+            }
+            else
+            {
+                if (Status2 == STATUS_BUFFER_TOO_SMALL)
+                {
+                    newDelKeys = RtlAllocateHeap(ProcessHeap,
+                                                 0,
+                                                 BufferSize + sizeof(REGP_DEL_KEYS));
+                    if (newDelKeys != NULL)
+                    {
+                        BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
+
+                        /* try again */
+                        goto ReadFirstSubKey;
+                    }
+                    else
+                    {
+                        /* don't break, let's try to delete as many keys as possible */
+                        Status2 = STATUS_INSUFFICIENT_RESOURCES;
+                        goto SubKeyFailureNoFree;
+                    }
+                }
+                else if (Status2 == STATUS_BUFFER_OVERFLOW)
+                {
+                    PREG_DEL_KEYS newDelKeys2;
+
+                    ASSERT(newDelKeys != NULL);
+
+                    /* we need more memory to query the key name */
+                    newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
+                                                    0,
+                                                    newDelKeys,
+                                                    BufferSize + sizeof(REGP_DEL_KEYS));
+                    if (newDelKeys2 != NULL)
+                    {
+                        newDelKeys = newDelKeys2;
+                        BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
+
+                        /* try again */
+                        goto ReadFirstSubKey;
+                    }
+                    else
+                    {
+                        /* don't break, let's try to delete as many keys as possible */
+                        Status2 = STATUS_INSUFFICIENT_RESOURCES;
+                    }
+                }
+SubKeyFailure:
+                RtlFreeHeap(ProcessHeap,
+                            0,
+                            newDelKeys);
+SubKeyFailureNoFree:
+                /* don't break, let's try to delete as many keys as possible */
+                if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
+                {
+                    Status = Status2;
+                }
+            }
+
+            Status2 = NtDeleteKey(delKeys->KeyHandle);
+            
+            /* NOTE: do NOT close the handle anymore, it's invalid already! */
+
+            if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
+            {
+                /* don't break, let's try to delete as many keys as possible */
+                Status = Status2;
+            }
+            
+            /* remove the entry from the list */
+            RemoveEntryList(&delKeys->ListEntry);
+
+            RtlFreeHeap(ProcessHeap,
+                        0,
+                        delKeys);
+        } while (!IsListEmpty(&delQueueHead));
+    }
+    else
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    
+    return Status;
 }
 
 
 /************************************************************************
- *  RegEnumKeyA
+ *  RegDeleteTreeW
  *
  * @implemented
  */
-LONG
-STDCALL
-RegEnumKeyA(
-  HKEY  hKey,
-  DWORD dwIndex,
-  LPSTR lpName,
-  DWORD cbName)
+LONG STDCALL
+RegDeleteTreeW(IN HKEY hKey,
+               IN LPCWSTR lpSubKey  OPTIONAL)
 {
-  DWORD dwLength = cbName;
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
 
-  return RegEnumKeyExA(hKey,
-           dwIndex,
-           lpName,
-           &dwLength,
-           NULL,
-           NULL,
-           NULL,
-           NULL);
-}
-
-
-/************************************************************************
- *  RegEnumValueW
- *
- * @implemented
- */
-LONG
-STDCALL
-RegEnumValueW(
-  HKEY  hKey,
-  DWORD dwIndex,
-  LPWSTR  lpValueName,
-  LPDWORD lpcbValueName,
-  LPDWORD lpReserved,
-  LPDWORD lpType,
-  LPBYTE  lpData,
-  LPDWORD lpcbData)
-{
-  PKEY_VALUE_FULL_INFORMATION ValueInfo;
-  NTSTATUS Status;
-  DWORD dwError = ERROR_SUCCESS;
-  ULONG BufferSize;
-  ULONG ResultSize;
-  HKEY KeyHandle;
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-      dwError = RtlNtStatusToDosError(Status);
-      SetLastError(dwError);
-      return(dwError);
-  }
-  BufferSize = sizeof (KEY_VALUE_FULL_INFORMATION) + *lpcbValueName * sizeof(WCHAR);
-  if (lpcbData)
-    BufferSize += *lpcbData;
-
-  /* We don't know the exact size of the data returned, so call
-     NtEnumerateValueKey() with a buffer size determined from parameters
-     to this function. If that call fails with a status code of
-     STATUS_BUFFER_OVERFLOW, allocate a new buffer and try again */
-  while (TRUE) {
-    ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
-    if (ValueInfo == NULL) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-    Status = NtEnumerateValueKey(
-    KeyHandle,
-      (ULONG)dwIndex,
-      KeyValueFullInformation,
-      ValueInfo,
-      BufferSize,
-      &ResultSize);
-
-    DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
-
-    if (Status == STATUS_BUFFER_OVERFLOW) {
-      RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
-      BufferSize = ResultSize;
-      continue;
-    }
-    if (!NT_SUCCESS(Status)) {
-      dwError = RtlNtStatusToDosError(Status);
-      SetLastError(dwError);
-      break;
-    } else {
-      if ((lpData) && (*lpcbData != 0) && (ValueInfo->DataLength > *lpcbData)) {
-        dwError = ERROR_MORE_DATA;
-        SetLastError(dwError);
-        break;
-      }
-      RtlCopyMemory(lpValueName, ValueInfo->Name, ValueInfo->NameLength);
-      *lpcbValueName = (DWORD)(ValueInfo->NameLength / sizeof(WCHAR));
-      lpValueName[ValueInfo->NameLength / sizeof(WCHAR)] = 0;
-      if (lpType)
-        *lpType = ValueInfo->Type;
-      if (lpData) {
-        RtlCopyMemory(lpData,
-          //(PVOID)((ULONG_PTR)ValueInfo->Name + ValueInfo->DataOffset),
-          (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset),
-          ValueInfo->DataLength);
-        *lpcbData = (DWORD)ValueInfo->DataLength;
-/*
-                  RtlCopyMemory((PCHAR) ValueFullInformation + ValueFullInformation->DataOffset,
-                    DataCell->Data,
-                    ValueCell->DataSize & LONG_MAX);
- */
+    if (lpSubKey != NULL)
+    {
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        RtlInitUnicodeString(&SubKeyName,
+                             (LPWSTR)lpSubKey);
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
+
+        Status = NtOpenKey(&SubKeyHandle,
+                           DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                           &ObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
         }
-      break;
+        
+        CurKey = SubKeyHandle;
     }
-  }
-  RtlFreeHeap (RtlGetProcessHeap(), 0, ValueInfo);
-  return dwError;
-}
+    else
+        CurKey = KeyHandle;
 
+    Status = RegpDeleteTree(CurKey);
 
-/************************************************************************
- *  RegEnumValueA
- *
- * @implemented
- */
-LONG
-STDCALL
-RegEnumValueA(
-  HKEY  hKey,
-  DWORD dwIndex,
-  LPSTR lpValueName,
-  LPDWORD lpcbValueName,
-  LPDWORD lpReserved,
-  LPDWORD lpType,
-  LPBYTE  lpData,
-  LPDWORD lpcbData)
-{
-  WCHAR ValueName[MAX_PATH+1];
-  UNICODE_STRING UnicodeString;
-  ANSI_STRING AnsiString;
-  LONG ErrorCode;
-  DWORD ValueNameLength;
-  BYTE* lpDataBuffer = NULL;
-  DWORD cbData = 0;
-  DWORD Type;
-  ANSI_STRING AnsiDataString;
-  UNICODE_STRING UnicodeDataString;
+    if (SubKeyHandle != NULL)
+    {
+        NtClose(SubKeyHandle);
+    }
 
-  if (lpData != NULL /*&& lpcbData != NULL*/) {
-    cbData = *lpcbData; // this should always be valid if lpData is valid
-    lpDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, (*lpcbData) * sizeof(WCHAR));
-    if (lpDataBuffer == NULL) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
+Cleanup:
+    CloseDefaultKey(KeyHandle);
+
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
     }
-  }
-  RtlInitUnicodeString(&UnicodeString, NULL);
-  UnicodeString.Buffer = &ValueName[0];
-  UnicodeString.MaximumLength = sizeof(ValueName);
-  ValueNameLength = *lpcbValueName;
-  ErrorCode = RegEnumValueW(
-    hKey,
-    dwIndex,
-    UnicodeString.Buffer,
-    &ValueNameLength,
-    lpReserved,
-    &Type,
-    lpDataBuffer,
-    &cbData);
-  if (ErrorCode != ERROR_SUCCESS)
-    return ErrorCode;
-  UnicodeString.Length = ValueNameLength * sizeof(WCHAR);
-  RtlInitAnsiString(&AnsiString, NULL);
-  AnsiString.Buffer = lpValueName;
-  AnsiString.MaximumLength = *lpcbValueName;
-  RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
-  *lpcbValueName = AnsiString.Length;
-//  if (lpData != lpDataBuffer) { // did we use a temp buffer
-  if (lpDataBuffer) { // did we use a temp buffer
-      if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ)) {
-          RtlInitUnicodeString(&UnicodeDataString, NULL);
-          UnicodeDataString.Buffer = (WCHAR*)lpDataBuffer;
-          UnicodeDataString.MaximumLength = (*lpcbData) * sizeof(WCHAR);
-          UnicodeDataString.Length = cbData /* * sizeof(WCHAR)*/;
-          RtlInitAnsiString(&AnsiDataString, NULL);
-          AnsiDataString.Buffer = lpData;
-          AnsiDataString.MaximumLength = *lpcbData;
-          RtlUnicodeStringToAnsiString(&AnsiDataString, &UnicodeDataString, FALSE);
-          *lpcbData = AnsiDataString.Length;
-//      else if (Type == REG_EXPAND_SZ) {
-      } else {
-          memcpy(lpData, lpDataBuffer, min(*lpcbData, cbData));
-          *lpcbData = cbData;
-      }
-      RtlFreeHeap(RtlGetProcessHeap(), 0, lpDataBuffer);
-  }
-  if (lpType != NULL) {
-    *lpType = Type;
-  }
-  return ERROR_SUCCESS;
+
+    return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
- *  RegFlushKey
+ *  RegDeleteTreeA
  *
  * @implemented
  */
 LONG STDCALL
-RegFlushKey(HKEY hKey)
+RegDeleteTreeA(IN HKEY hKey,
+               IN LPCSTR lpSubKey  OPTIONAL)
 {
-  HKEY KeyHandle;
-  NTSTATUS Status;
-  LONG ErrorCode;
-
-  if (hKey == HKEY_PERFORMANCE_DATA)
-    return(ERROR_SUCCESS);
-
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-    }
+    UNICODE_STRING SubKeyName;
+    LONG Ret;
 
-  Status = NtFlushKey(KeyHandle);
-  if (!NT_SUCCESS(Status))
+    if (lpSubKey != NULL)
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+                                              (LPSTR)lpSubKey))
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
     }
+    else
+        RtlInitUnicodeString(&SubKeyName,
+                             NULL);
 
-  return(ERROR_SUCCESS);
-}
+    Ret = RegDeleteTreeW(hKey,
+                         SubKeyName.Buffer);
 
+    RtlFreeUnicodeString(&SubKeyName);
 
-/************************************************************************
- *  RegGetKeySecurity
- *
- * @unimplemented
- */
-LONG STDCALL
-RegGetKeySecurity (HKEY hKey,
-                  SECURITY_INFORMATION SecurityInformation,
-                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
-                  LPDWORD lpcbSecurityDescriptor)
-{
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+    return Ret;
 }
 
 
 /************************************************************************
- *  RegLoadKeyA
+ *  RegSetKeyValueW
  *
  * @implemented
  */
 LONG STDCALL
-RegLoadKeyA (HKEY hKey,
-            LPCSTR lpSubKey,
-            LPCSTR lpFile)
+RegSetKeyValueW(IN HKEY hKey,
+                IN LPCWSTR lpSubKey  OPTIONAL,
+                IN LPCWSTR lpValueName  OPTIONAL,
+                IN DWORD dwType,
+                IN LPCVOID lpData  OPTIONAL,
+                IN DWORD cbData)
 {
-  UNICODE_STRING FileName;
-  UNICODE_STRING KeyName;
-  DWORD ErrorCode;
-
-  RtlCreateUnicodeStringFromAsciiz (&KeyName,
-                                   (LPSTR)lpSubKey);
-  RtlCreateUnicodeStringFromAsciiz (&FileName,
-                                   (LPSTR)lpFile);
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+    LONG Ret;
 
-  ErrorCode = RegLoadKeyW (hKey,
-                          KeyName.Buffer,
-                          FileName.Buffer);
-
-  RtlFreeUnicodeString (&FileName);
-  RtlFreeUnicodeString (&KeyName);
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+    
+    if (lpSubKey != NULL)
+    {
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        RtlInitUnicodeString(&SubKeyName,
+                             (LPWSTR)lpSubKey);
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
+
+        Status = NtOpenKey(&SubKeyHandle,
+                           KEY_SET_VALUE,
+                           &ObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            Ret = RtlNtStatusToDosError(Status);
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
+    
+    Ret = RegSetValueExW(CurKey,
+                         lpValueName,
+                         0,
+                         dwType,
+                         lpData,
+                         cbData);
+
+    if (SubKeyHandle != NULL)
+    {
+        NtClose(SubKeyHandle);
+    }
+    
+Cleanup:
+    CloseDefaultKey(KeyHandle);
 
-  return ErrorCode;
+    return Ret;
 }
 
 
 /************************************************************************
- *  RegLoadKeyW
+ *  RegSetKeyValueA
  *
  * @implemented
  */
 LONG STDCALL
-RegLoadKeyW (HKEY hKey,
-            LPCWSTR lpSubKey,
-            LPCWSTR lpFile)
+RegSetKeyValueA(IN HKEY hKey,
+                IN LPCSTR lpSubKey  OPTIONAL,
+                IN LPCSTR lpValueName  OPTIONAL,
+                IN DWORD dwType,
+                IN LPCVOID lpData  OPTIONAL,
+                IN DWORD cbData)
 {
-  OBJECT_ATTRIBUTES FileObjectAttributes;
-  OBJECT_ATTRIBUTES KeyObjectAttributes;
-  UNICODE_STRING FileName;
-  UNICODE_STRING KeyName;
-  HANDLE KeyHandle;
-  DWORD ErrorCode;
-  NTSTATUS Status;
-
-  if (hKey == HKEY_PERFORMANCE_DATA)
-    return ERROR_INVALID_HANDLE;
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+    LONG Ret;
 
-  Status = MapDefaultKey (&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status))
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
+        return RtlNtStatusToDosError(Status);
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
-                                    &FileName,
-                                    NULL,
-                                    NULL))
+    if (lpSubKey != NULL)
     {
-      SetLastError (ERROR_BAD_PATHNAME);
-      return ERROR_BAD_PATHNAME;
-    }
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+                                              (LPSTR)lpSubKey))
+        {
+            Ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto Cleanup;
+        }
 
-  InitializeObjectAttributes (&FileObjectAttributes,
-                             &FileName,
-                             OBJ_CASE_INSENSITIVE,
-                             NULL,
-                             NULL);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
 
-  RtlInitUnicodeString (&KeyName,
-                       (LPWSTR)lpSubKey);
+        Status = NtOpenKey(&SubKeyHandle,
+                           KEY_SET_VALUE,
+                           &ObjectAttributes);
 
-  InitializeObjectAttributes (&KeyObjectAttributes,
-                             &KeyName,
-                             OBJ_CASE_INSENSITIVE,
-                             KeyHandle,
-                             NULL);
+        RtlFreeUnicodeString(&SubKeyName);
 
-  Status = NtLoadKey (&KeyObjectAttributes,
-                     &FileObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            Ret = RtlNtStatusToDosError(Status);
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
 
-  RtlFreeUnicodeString (&FileName);
+    Ret = RegSetValueExA(CurKey,
+                         lpValueName,
+                         0,
+                         dwType,
+                         lpData,
+                         cbData);
 
-  if (!NT_SUCCESS(Status))
+    if (SubKeyHandle != NULL)
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
+        NtClose(SubKeyHandle);
     }
+    
+Cleanup:
+    CloseDefaultKey(KeyHandle);
 
-  return ERROR_SUCCESS;
+    return Ret;
 }
 
 
 /************************************************************************
- *  RegNotifyChangeKeyValue
+ *  RegDeleteValueA
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
-RegNotifyChangeKeyValue(HKEY hKey,
-                       BOOL bWatchSubtree,
-                       DWORD dwNotifyFilter,
-                       HANDLE hEvent,
-                       BOOL fAsynchronous)
+RegDeleteValueA (HKEY hKey,
+                LPCSTR lpValueName)
 {
-  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING ValueName;
   HANDLE KeyHandle;
   NTSTATUS Status;
 
-  if (hKey == HKEY_PERFORMANCE_DATA)
-    {
-      return (ERROR_INVALID_HANDLE);
-    }
-
-  if (fAsynchronous && hEvent == NULL)
-    {
-      return (ERROR_INVALID_PARAMETER);
-    }
-
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
-      return (RtlNtStatusToDosError (Status));
+      return RtlNtStatusToDosError (Status);
     }
 
-  /* FIXME: Remote key handles must fail */
-
-  Status = NtNotifyChangeKey (KeyHandle,
-                             hEvent,
-                             0,
-                             0,
-                             &IoStatusBlock,
-                             dwNotifyFilter,
-                             bWatchSubtree,
-                             0,
-                             0,
-                             fAsynchronous);
-  if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
+  RtlCreateUnicodeStringFromAsciiz (&ValueName,
+                                   (LPSTR)lpValueName);
+  Status = NtDeleteValueKey (KeyHandle,
+                            &ValueName);
+  RtlFreeUnicodeString (&ValueName);
+  
+  CloseDefaultKey(KeyHandle);
+  
+  if (!NT_SUCCESS(Status))
     {
-      return (RtlNtStatusToDosError (Status));
+      return RtlNtStatusToDosError (Status);
     }
 
-  return (ERROR_SUCCESS);
+  return ERROR_SUCCESS;
 }
 
 
-
 /************************************************************************
- *  RegOpenKeyA
+ *  RegDeleteValueW
  *
  * @implemented
  */
 LONG STDCALL
-RegOpenKeyA(HKEY hKey,
-      LPCSTR lpSubKey,
-      PHKEY phkResult)
+RegDeleteValueW (HKEY hKey,
+                LPCWSTR lpValueName)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
-  LONG ErrorCode;
+  UNICODE_STRING ValueName;
   NTSTATUS Status;
+  HANDLE KeyHandle;
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-  }
-  RtlCreateUnicodeStringFromAsciiz(&SubKeyString, (LPSTR)lpSubKey);
-  InitializeObjectAttributes(&ObjectAttributes,
-           &SubKeyString,
-           OBJ_CASE_INSENSITIVE,
-           KeyHandle,
-           NULL);
-  Status = NtOpenKey(phkResult, KEY_ALL_ACCESS, &ObjectAttributes);
-  RtlFreeUnicodeString(&SubKeyString);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-  }
-  return(ERROR_SUCCESS);
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  RtlInitUnicodeString (&ValueName,
+                       (LPWSTR)lpValueName);
+
+  Status = NtDeleteValueKey (KeyHandle,
+                            &ValueName);
+
+  CloseDefaultKey(KeyHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
- *  RegOpenKeyW
- *
- *  19981101 Ariadne
- *  19990525 EA
+ *  RegEnumKeyA
  *
  * @implemented
  */
-LONG
-STDCALL
-RegOpenKeyW(
-  HKEY  hKey,
-  LPCWSTR lpSubKey,
-  PHKEY phkResult)
+LONG STDCALL
+RegEnumKeyA (HKEY hKey,
+            DWORD dwIndex,
+            LPSTR lpName,
+            DWORD cbName)
 {
-  NTSTATUS    errCode;
-  UNICODE_STRING    SubKeyString;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  HKEY      KeyHandle;
-  LONG      ErrorCode;
-
-  errCode = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(errCode)) {
-    ErrorCode = RtlNtStatusToDosError(errCode);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
-  InitializeObjectAttributes(&ObjectAttributes,
-           &SubKeyString,
-           OBJ_CASE_INSENSITIVE,
-           KeyHandle,
-           NULL);
-  errCode = NtOpenKey(phkResult, KEY_ALL_ACCESS, &ObjectAttributes);
-  if (!NT_SUCCESS(errCode)) {
-    ErrorCode = RtlNtStatusToDosError(errCode);
-    SetLastError(ErrorCode);
-    return ErrorCode;
-  }
-  return ERROR_SUCCESS;
+  DWORD dwLength;
+
+  dwLength = cbName;
+  return RegEnumKeyExA (hKey,
+                       dwIndex,
+                       lpName,
+                       &dwLength,
+                       NULL,
+                       NULL,
+                       NULL,
+                       NULL);
 }
 
 
 /************************************************************************
- *  RegOpenKeyExA
+ *  RegEnumKeyW
  *
  * @implemented
  */
 LONG STDCALL
-RegOpenKeyExA(HKEY hKey,
-        LPCSTR lpSubKey,
-        DWORD ulOptions,
-        REGSAM samDesired,
-        PHKEY phkResult)
+RegEnumKeyW (HKEY hKey,
+            DWORD dwIndex,
+            LPWSTR lpName,
+            DWORD cbName)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
-  LONG ErrorCode;
-  NTSTATUS Status;
-
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-  }
-  RtlCreateUnicodeStringFromAsciiz(&SubKeyString, (LPSTR)lpSubKey);
-  InitializeObjectAttributes(&ObjectAttributes,
-           &SubKeyString,
-           OBJ_CASE_INSENSITIVE,
-           KeyHandle,
-           NULL);
-  Status = NtOpenKey(phkResult, samDesired, &ObjectAttributes);
-  RtlFreeUnicodeString(&SubKeyString);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-  }
-  return(ERROR_SUCCESS);
+  DWORD dwLength;
+
+  dwLength = cbName;
+  return RegEnumKeyExW (hKey,
+                       dwIndex,
+                       lpName,
+                       &dwLength,
+                       NULL,
+                       NULL,
+                       NULL,
+                       NULL);
 }
 
 
 /************************************************************************
- *  RegOpenKeyExW
+ *  RegEnumKeyExA
  *
  * @implemented
  */
 LONG STDCALL
-RegOpenKeyExW(HKEY hKey,
-        LPCWSTR lpSubKey,
-        DWORD ulOptions,
-        REGSAM samDesired,
-        PHKEY phkResult)
+RegEnumKeyExA (HKEY hKey,
+              DWORD dwIndex,
+              LPSTR lpName,
+              LPDWORD lpcbName,
+              LPDWORD lpReserved,
+              LPSTR lpClass,
+              LPDWORD lpcbClass,
+              PFILETIME lpftLastWriteTime)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
-  LONG ErrorCode;
-  NTSTATUS Status;
+       union
+       {
+               KEY_NODE_INFORMATION Node;
+               KEY_BASIC_INFORMATION Basic;
+       } *KeyInfo;
+
+       UNICODE_STRING StringU;
+       ANSI_STRING StringA;
+       LONG ErrorCode = ERROR_SUCCESS;
+       DWORD NameLength;
+       DWORD ClassLength = 0;
+       DWORD BufferSize;
+       DWORD ResultSize;
+       HANDLE KeyHandle;
+       NTSTATUS Status;
+
+       TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
+               hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
+
+       if ((lpClass) && (!lpcbClass))
+       {
+               return ERROR_INVALID_PARAMETER;
+       }
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError (ErrorCode);
-      return(ErrorCode);
-  }
-  if (lpSubKey != NULL) {
-      RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
-  } else {
-      RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
-  }
-  InitializeObjectAttributes(&ObjectAttributes,
-           &SubKeyString,
-           OBJ_CASE_INSENSITIVE,
-           KeyHandle,
-           NULL);
-  Status = NtOpenKey(phkResult, samDesired, &ObjectAttributes);
-  if (!NT_SUCCESS(Status)) {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-  }
-  return(ERROR_SUCCESS);
+       Status = MapDefaultKey(&KeyHandle, hKey);
+       if (!NT_SUCCESS(Status))
+       {
+               return RtlNtStatusToDosError (Status);
+       }
+
+       if (*lpcbName > 0)
+       {
+               NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
+       }
+       else
+       {
+               NameLength = 0;
+       }
+
+       if (lpClass)
+       {
+               if (*lpcbClass > 0)
+               {
+                       ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+               }
+               else
+               {
+                       ClassLength = 0;
+               }
+
+               /* The class name should start at a dword boundary */
+               BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
+       }
+       else
+       {
+               BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
+       }
+
+       KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
+       if (KeyInfo == NULL)
+       {
+               ErrorCode = ERROR_OUTOFMEMORY;
+               goto Cleanup;
+       }
+
+       Status = NtEnumerateKey (KeyHandle,
+                                                               (ULONG)dwIndex,
+                                                               lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
+                                                               KeyInfo,
+                                                               BufferSize,
+                                                               &ResultSize);
+       TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
+       if (!NT_SUCCESS(Status))
+       {
+               ErrorCode = RtlNtStatusToDosError (Status);
+       }
+       else
+       {
+               if (lpClass == NULL)
+               {
+                       if (KeyInfo->Basic.NameLength > NameLength)
+                       {
+                               ErrorCode = ERROR_BUFFER_OVERFLOW;
+                       }
+                       else
+                       {
+                               StringU.Buffer = KeyInfo->Basic.Name;
+                               StringU.Length = KeyInfo->Basic.NameLength;
+                               StringU.MaximumLength = KeyInfo->Basic.NameLength;
+                       }
+               }
+               else
+               {
+                       if (KeyInfo->Node.NameLength > NameLength ||
+                               KeyInfo->Node.ClassLength > ClassLength)
+                       {
+                               ErrorCode = ERROR_BUFFER_OVERFLOW;
+                       }
+                       else
+                       {
+                               StringA.Buffer = lpClass;
+                               StringA.Length = 0;
+                               StringA.MaximumLength = *lpcbClass;
+                               StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
+                               StringU.Length = KeyInfo->Node.ClassLength;
+                               StringU.MaximumLength = KeyInfo->Node.ClassLength;
+                               RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
+                               lpClass[StringA.Length] = 0;
+                               *lpcbClass = StringA.Length;
+                               StringU.Buffer = KeyInfo->Node.Name;
+                               StringU.Length = KeyInfo->Node.NameLength;
+                               StringU.MaximumLength = KeyInfo->Node.NameLength;
+                       }
+               }
+
+               if (ErrorCode == ERROR_SUCCESS)
+               {
+                       StringA.Buffer = lpName;
+                       StringA.Length = 0;
+                       StringA.MaximumLength = *lpcbName;
+                       RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
+                       lpName[StringA.Length] = 0;
+                       *lpcbName = StringA.Length;
+                       if (lpftLastWriteTime != NULL)
+                       {
+                               if (lpClass == NULL)
+                               {
+                                       lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
+                                       lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
+                               }
+                               else
+                               {
+                                       lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
+                                       lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
+                               }
+                       }
+               }
+       }
+
+       TRACE("Key Namea0 Length %d\n", StringU.Length);
+       TRACE("Key Namea1 Length %d\n", NameLength);
+       TRACE("Key Namea Length %d\n", *lpcbName);
+       TRACE("Key Namea %s\n", lpName);
+
+       RtlFreeHeap (ProcessHeap,
+               0,
+               KeyInfo);
+
+Cleanup:
+    CloseDefaultKey(KeyHandle);
+
+    return ErrorCode;
 }
 
 
 /************************************************************************
- *  RegQueryInfoKeyW
+ *  RegEnumKeyExW
  *
  * @implemented
  */
-LONG
-STDCALL
-RegQueryInfoKeyW(
-  HKEY    hKey,
-  LPWSTR    lpClass,
-  LPDWORD   lpcbClass,
-  LPDWORD   lpReserved,
-  LPDWORD   lpcSubKeys,
-  LPDWORD   lpcbMaxSubKeyLen,
-  LPDWORD   lpcbMaxClassLen,
-  LPDWORD   lpcValues,
-  LPDWORD   lpcbMaxValueNameLen,
-  LPDWORD   lpcbMaxValueLen,
-  LPDWORD   lpcbSecurityDescriptor,
-  PFILETIME lpftLastWriteTime)
+LONG STDCALL
+RegEnumKeyExW (HKEY hKey,
+              DWORD dwIndex,
+              LPWSTR lpName,
+              LPDWORD lpcbName,
+              LPDWORD lpReserved,
+              LPWSTR lpClass,
+              LPDWORD lpcbClass,
+              PFILETIME lpftLastWriteTime)
 {
-  KEY_FULL_INFORMATION FullInfoBuffer;
-  PKEY_FULL_INFORMATION FullInfo;
-  ULONG FullInfoSize;
-  HKEY KeyHandle;
+  union
+  {
+    KEY_NODE_INFORMATION Node;
+    KEY_BASIC_INFORMATION Basic;
+  } *KeyInfo;
+
+  ULONG BufferSize;
+  ULONG ResultSize;
+  ULONG NameLength;
+  ULONG ClassLength = 0;
+  HANDLE KeyHandle;
+  LONG ErrorCode = ERROR_SUCCESS;
   NTSTATUS Status;
-  LONG ErrorCode;
-  ULONG Length;
 
-  if ((lpClass) && (!lpcbClass))
+  Status = MapDefaultKey(&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (*lpcbName > 0)
+    {
+      NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
+    }
+  else
+    {
+      NameLength = 0;
+    }
+
+  if (lpClass)
+    {
+      if (*lpcbClass > 0)
+       {
+         ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+       }
+      else
+       {
+         ClassLength = 0;
+       }
+
+      BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
+    }
+  else
+    {
+      BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
+    }
+
+  KeyInfo = RtlAllocateHeap (ProcessHeap,
+                            0,
+                            BufferSize);
+  if (KeyInfo == NULL)
+    {
+      ErrorCode = ERROR_OUTOFMEMORY;
+      goto Cleanup;
+    }
+
+  Status = NtEnumerateKey (KeyHandle,
+                          (ULONG)dwIndex,
+                          lpClass ? KeyNodeInformation : KeyBasicInformation,
+                          KeyInfo,
+                          BufferSize,
+                          &ResultSize);
+  TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+    }
+  else
+    {
+      if (lpClass == NULL)
+       {
+         if (KeyInfo->Basic.NameLength > NameLength)
+           {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+           }
+         else
+           {
+             RtlCopyMemory (lpName,
+                            KeyInfo->Basic.Name,
+                            KeyInfo->Basic.NameLength);
+             *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
+             lpName[*lpcbName] = 0;
+           }
+       }
+      else
+       {
+         if (KeyInfo->Node.NameLength > NameLength ||
+             KeyInfo->Node.ClassLength > ClassLength)
+           {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+           }
+         else
+           {
+             RtlCopyMemory (lpName,
+                            KeyInfo->Node.Name,
+                            KeyInfo->Node.NameLength);
+             *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
+             lpName[*lpcbName] = 0;
+             RtlCopyMemory (lpClass,
+                            (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
+                            KeyInfo->Node.ClassLength);
+             *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
+             lpClass[*lpcbClass] = 0;
+           }
+       }
+
+      if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
+       {
+         if (lpClass == NULL)
+           {
+             lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
+             lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
+           }
+         else
+           {
+             lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
+             lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
+           }
+       }
+    }
+
+  RtlFreeHeap (ProcessHeap,
+              0,
+              KeyInfo);
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
+}
+
+/************************************************************************
+ *  RegEnumValueA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
+               LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
+{
+       HANDLE KeyHandle;
+    NTSTATUS status;
+    DWORD total_size;
+    char buffer[256], *buf_ptr = buffer;
+    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
+    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
+
+    //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
+      //    hkey, index, value, val_count, reserved, type, data, count );
+
+    /* NT only checks count, not val_count */
+    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+       status = MapDefaultKey (&KeyHandle, hKey);
+       if (!NT_SUCCESS(status))
+       {
+               return RtlNtStatusToDosError (status);
+       }
+
+    total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
+    if (data) total_size += *count;
+    total_size = min( sizeof(buffer), total_size );
+
+    status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
+                                  buffer, total_size, &total_size );
+    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+
+    /* we need to fetch the contents for a string type even if not requested,
+     * because we need to compute the length of the ASCII string. */
+    if (value || data || is_string(info->Type))
+    {
+        /* retry with a dynamically allocated buffer */
+        while (status == STATUS_BUFFER_OVERFLOW)
+        {
+            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                goto done;
+            }
+            info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
+            status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
+                                          buf_ptr, total_size, &total_size );
+        }
+
+        if (status) goto done;
+
+        if (is_string(info->Type))
+        {
+            DWORD len;
+            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
+                                       total_size - info->DataOffset );
+            if (data && len)
+            {
+                if (len > *count) status = STATUS_BUFFER_OVERFLOW;
+                else
+                {
+                    RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
+                                            total_size - info->DataOffset );
+                    /* if the type is REG_SZ and data is not 0-terminated
+                     * and there is enough space in the buffer NT appends a \0 */
+                    if (len < *count && data[len-1]) data[len] = 0;
+                }
+            }
+            info->DataLength = len;
+        }
+        else if (data)
+        {
+            if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
+            else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
+        }
+
+        if (value && !status)
+        {
+            DWORD len;
+
+            RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
+            if (len >= *val_count)
+            {
+                status = STATUS_BUFFER_OVERFLOW;
+                if (*val_count)
+                {
+                    len = *val_count - 1;
+                    RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
+                    value[len] = 0;
+                }
+            }
+            else
+            {
+                RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
+                value[len] = 0;
+                *val_count = len;
+            }
+        }
+    }
+    else status = STATUS_SUCCESS;
+
+    if (type) *type = info->Type;
+    if (count) *count = info->DataLength;
+
+ done:
+    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+    CloseDefaultKey(KeyHandle);
+    return RtlNtStatusToDosError(status);
+}
+
+/******************************************************************************
+ * RegEnumValueW   [ADVAPI32.@]
+ * @implemented
+ *
+ * PARAMS
+ *  hkey       [I] Handle to key to query
+ *  index      [I] Index of value to query
+ *  value      [O] Value string
+ *  val_count  [I/O] Size of value buffer (in wchars)
+ *  reserved   [I] Reserved
+ *  type       [O] Type code
+ *  data       [O] Value data
+ *  count      [I/O] Size of data buffer (in bytes)
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS
+ *  Failure: nonzero error code from Winerror.h
+ */
+LONG STDCALL
+RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
+               PDWORD reserved, PDWORD type, LPBYTE data, PDWORD count )
+{
+       HANDLE KeyHandle;
+    NTSTATUS status;
+    DWORD total_size;
+    char buffer[256], *buf_ptr = buffer;
+    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
+    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
+
+    //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
+    //      hkey, index, value, val_count, reserved, type, data, count );
+
+    /* NT only checks count, not val_count */
+    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+
+       status = MapDefaultKey (&KeyHandle, hKey);
+       if (!NT_SUCCESS(status))
+       {
+               return RtlNtStatusToDosError (status);
+       }
+
+    total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
+    if (data) total_size += *count;
+    total_size = min( sizeof(buffer), total_size );
+
+    status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
+                                  buffer, total_size, &total_size );
+    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+
+    if (value || data)
+    {
+        /* retry with a dynamically allocated buffer */
+        while (status == STATUS_BUFFER_OVERFLOW)
+        {
+            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
+            {
+                status = ERROR_NOT_ENOUGH_MEMORY;
+                goto done;
+            }
+            info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
+            status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
+                                          buf_ptr, total_size, &total_size );
+        }
+
+        if (status) goto done;
+
+        if (value)
+        {
+            if (info->NameLength/sizeof(WCHAR) >= *val_count)
+            {
+                status = STATUS_BUFFER_OVERFLOW;
+                goto overflow;
+            }
+            memcpy( value, info->Name, info->NameLength );
+            *val_count = info->NameLength / sizeof(WCHAR);
+            value[*val_count] = 0;
+        }
+
+        if (data)
+        {
+            if (total_size - info->DataOffset > *count)
+            {
+                status = STATUS_BUFFER_OVERFLOW;
+                goto overflow;
+            }
+            memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
+            if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
+            {
+                /* if the type is REG_SZ and data is not 0-terminated
+                 * and there is enough space in the buffer NT appends a \0 */
+                WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
+                if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
+            }
+        }
+    }
+    else status = STATUS_SUCCESS;
+
+ overflow:
+    if (type) *type = info->Type;
+    if (count) *count = info->DataLength;
+
+ done:
+    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+    CloseDefaultKey(KeyHandle);
+    return RtlNtStatusToDosError(status);
+}
+
+/************************************************************************
+ *  RegFlushKey
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegFlushKey(HKEY hKey)
+{
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_SUCCESS;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  Status = NtFlushKey (KeyHandle);
+  
+  CloseDefaultKey(KeyHandle);
+  
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ *  RegGetKeySecurity
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegGetKeySecurity(HKEY hKey,
+                 SECURITY_INFORMATION SecurityInformation,
+                 PSECURITY_DESCRIPTOR pSecurityDescriptor,
+                 LPDWORD lpcbSecurityDescriptor)
+{
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey(&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
+      return RtlNtStatusToDosError (Status);
+    }
+
+  Status = NtQuerySecurityObject(KeyHandle,
+                                SecurityInformation,
+                                pSecurityDescriptor,
+                                *lpcbSecurityDescriptor,
+                                lpcbSecurityDescriptor);
+
+  CloseDefaultKey(KeyHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
+      return RtlNtStatusToDosError (Status);
+    }
+
+  return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ *  RegLoadKeyA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegLoadKeyA (HKEY hKey,
+            LPCSTR lpSubKey,
+            LPCSTR lpFile)
+{
+  UNICODE_STRING FileName;
+  UNICODE_STRING KeyName;
+  LONG ErrorCode;
+
+  RtlCreateUnicodeStringFromAsciiz (&KeyName,
+                                   (LPSTR)lpSubKey);
+  RtlCreateUnicodeStringFromAsciiz (&FileName,
+                                   (LPSTR)lpFile);
+
+  ErrorCode = RegLoadKeyW (hKey,
+                          KeyName.Buffer,
+                          FileName.Buffer);
+
+  RtlFreeUnicodeString (&FileName);
+  RtlFreeUnicodeString (&KeyName);
+
+  return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegLoadKeyW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegLoadKeyW (HKEY hKey,
+            LPCWSTR lpSubKey,
+            LPCWSTR lpFile)
+{
+  OBJECT_ATTRIBUTES FileObjectAttributes;
+  OBJECT_ATTRIBUTES KeyObjectAttributes;
+  UNICODE_STRING FileName;
+  UNICODE_STRING KeyName;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      ErrorCode = ERROR_BAD_PATHNAME;
+      goto Cleanup;
+    }
+
+  InitializeObjectAttributes (&FileObjectAttributes,
+                             &FileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  RtlInitUnicodeString (&KeyName,
+                       (LPWSTR)lpSubKey);
+
+  InitializeObjectAttributes (&KeyObjectAttributes,
+                             &KeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             KeyHandle,
+                             NULL);
+
+  Status = NtLoadKey (&KeyObjectAttributes,
+                     &FileObjectAttributes);
+
+  RtlFreeUnicodeString (&FileName);
+
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      goto Cleanup;
+    }
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegNotifyChangeKeyValue
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegNotifyChangeKeyValue (HKEY hKey,
+                        BOOL bWatchSubtree,
+                        DWORD dwNotifyFilter,
+                        HANDLE hEvent,
+                        BOOL fAsynchronous)
+{
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  if (fAsynchronous == TRUE && hEvent == NULL)
     {
-      SetLastError(ERROR_INVALID_PARAMETER);
       return ERROR_INVALID_PARAMETER;
     }
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  /* FIXME: Remote key handles must fail */
+
+  Status = NtNotifyChangeKey (KeyHandle,
+                             hEvent,
+                             0,
+                             0,
+                             &IoStatusBlock,
+                             dwNotifyFilter,
+                             bWatchSubtree,
+                             0,
+                             0,
+                             fAsynchronous);
+  if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+    }
+
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegOpenCurrentUser
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenCurrentUser (IN REGSAM samDesired,
+                    OUT PHKEY phkResult)
+{
+  NTSTATUS Status;
+
+  Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
+                              (PHANDLE)phkResult);
   if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
-    }
-
-  if (lpClass) {
-    FullInfoSize = sizeof(KEY_FULL_INFORMATION) + *lpcbClass;
-    FullInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullInfoSize);
-    if (!FullInfo) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-    FullInfo->ClassLength = *lpcbClass;
-  } else {
-    FullInfoSize = sizeof(KEY_FULL_INFORMATION);
-    FullInfo = &FullInfoBuffer;
-    FullInfo->ClassLength = 1;
-  }
-  FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
-  Status = NtQueryKey(
-    KeyHandle,
-    KeyFullInformation,
-    FullInfo,
-    FullInfoSize,
-    &Length);
-  if (!NT_SUCCESS(Status)) {
-    if (lpClass) {
-      RtlFreeHeap(RtlGetProcessHeap(), 0, FullInfo);
-    }
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError(ErrorCode);
-    return ErrorCode;
-  }
-  if (lpcSubKeys) {
-    *lpcSubKeys = FullInfo->SubKeys;
-  }
-  if (lpcbMaxSubKeyLen) {
-    *lpcbMaxSubKeyLen = FullInfo->MaxNameLen;
+  {
+    /* NOTE - don't set the last error code! just return the error! */
+    return RtlNtStatusToDosError(Status);
   }
-  if (lpcbMaxClassLen) {
-    *lpcbMaxClassLen = FullInfo->MaxClassLen;
+
+  return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ *  RegOpenKeyA
+ *
+ *  20050503 Fireball - imported from WINE
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyA (HKEY hKey,
+            LPCSTR lpSubKey,
+            PHKEY phkResult)
+{
+       TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey, lpSubKey, phkResult);
+
+       if (!lpSubKey || !*lpSubKey)
+       {
+               *phkResult = hKey;
+               return ERROR_SUCCESS;
+       }
+
+       return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
+}
+
+
+/************************************************************************
+ *  RegOpenKeyW
+ *
+ *  19981101 Ariadne
+ *  19990525 EA
+ *  20050503 Fireball - imported from WINE
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyW (HKEY hKey,
+            LPCWSTR lpSubKey,
+            PHKEY phkResult)
+{
+       TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
+
+       if (!lpSubKey || !*lpSubKey)
+       {
+               *phkResult = hKey;
+               return ERROR_SUCCESS;
+       }
+       return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
+}
+
+
+/************************************************************************
+ *  RegOpenKeyExA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyExA (HKEY hKey,
+              LPCSTR lpSubKey,
+              DWORD ulOptions,
+              REGSAM samDesired,
+              PHKEY phkResult)
+{
+       OBJECT_ATTRIBUTES ObjectAttributes;
+       UNICODE_STRING SubKeyString;
+       HANDLE KeyHandle;
+       NTSTATUS Status;
+       LONG ErrorCode = ERROR_SUCCESS;
+
+       TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
+               hKey, lpSubKey, ulOptions, samDesired, phkResult);
+
+       Status = MapDefaultKey (&KeyHandle, hKey);
+       if (!NT_SUCCESS(Status))
+       {
+               return RtlNtStatusToDosError (Status);
+       }
+
+       RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
+       InitializeObjectAttributes (&ObjectAttributes,
+               &SubKeyString,
+               OBJ_CASE_INSENSITIVE,
+               KeyHandle,
+               NULL);
+
+       Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
+       RtlFreeUnicodeString (&SubKeyString);
+       if (!NT_SUCCESS(Status))
+       {
+               ErrorCode = RtlNtStatusToDosError (Status);
+       }
+       
+       CloseDefaultKey(KeyHandle);
+
+       return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegOpenKeyExW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyExW (HKEY hKey,
+              LPCWSTR lpSubKey,
+              DWORD ulOptions,
+              REGSAM samDesired,
+              PHKEY phkResult)
+{
+       OBJECT_ATTRIBUTES ObjectAttributes;
+       UNICODE_STRING SubKeyString;
+       HANDLE KeyHandle;
+       NTSTATUS Status;
+       LONG ErrorCode = ERROR_SUCCESS;
+
+       TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
+               hKey, lpSubKey, ulOptions, samDesired, phkResult);
+
+       Status = MapDefaultKey (&KeyHandle, hKey);
+       if (!NT_SUCCESS(Status))
+       {
+               return RtlNtStatusToDosError (Status);
+       }
+
+       if (lpSubKey != NULL)
+               RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
+       else
+               RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
+
+       InitializeObjectAttributes (&ObjectAttributes,
+               &SubKeyString,
+               OBJ_CASE_INSENSITIVE,
+               KeyHandle,
+               NULL);
+
+       Status = NtOpenKey ((PHANDLE)phkResult, samDesired,     &ObjectAttributes);
+
+       if (!NT_SUCCESS(Status))
+       {
+               ErrorCode = RtlNtStatusToDosError (Status);
+       }
+       
+       CloseDefaultKey(KeyHandle);
+
+       return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegOpenUserClassesRoot
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenUserClassesRoot (IN HANDLE hToken,
+                        IN DWORD dwOptions,
+                        IN REGSAM samDesired,
+                        OUT PHKEY phkResult)
+{
+  const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
+  const WCHAR UserClassesKeySuffix[] = L"_Classes";
+  PTOKEN_USER TokenUserData;
+  ULONG RequiredLength;
+  UNICODE_STRING UserSidString, UserClassesKeyRoot;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+
+  /* check parameters */
+  if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
+  {
+    return ERROR_INVALID_PARAMETER;
   }
-  if (lpcValues) {
-    *lpcValues = FullInfo->Values;
+
+  /*
+   * Get the user sid from the token
+   */
+
+ReadTokenSid:
+  /* determine how much memory we need */
+  Status = NtQueryInformationToken(hToken,
+                                   TokenUser,
+                                   NULL,
+                                   0,
+                                   &RequiredLength);
+  if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
+  {
+    /* NOTE - as opposed to all other registry functions windows does indeed
+              change the last error code in case the caller supplied a invalid
+              handle for example! */
+    return RtlNtStatusToDosError (Status);
   }
-  if (lpcbMaxValueNameLen) {
-    *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen;
+
+  TokenUserData = RtlAllocateHeap(ProcessHeap,
+                                  0,
+                                  RequiredLength);
+  if (TokenUserData == NULL)
+  {
+    return ERROR_NOT_ENOUGH_MEMORY;
   }
-  if (lpcbMaxValueLen) {
-    *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
+
+  /* attempt to read the information */
+  Status = NtQueryInformationToken(hToken,
+                                   TokenUser,
+                                   TokenUserData,
+                                   RequiredLength,
+                                   &RequiredLength);
+  if (!NT_SUCCESS(Status))
+  {
+    RtlFreeHeap(ProcessHeap,
+                0,
+                TokenUserData);
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+      /* the information appears to have changed?! try again */
+      goto ReadTokenSid;
+    }
+
+    /* NOTE - as opposed to all other registry functions windows does indeed
+              change the last error code in case the caller supplied a invalid
+              handle for example! */
+    return RtlNtStatusToDosError (Status);
   }
-  if (lpcbSecurityDescriptor) {
-    *lpcbSecurityDescriptor = 0;
-    /* FIXME */
+
+  /*
+   * Build the absolute path for the user's registry in the form
+   * "\Registry\User\<SID>_Classes"
+   */
+  Status = RtlConvertSidToUnicodeString(&UserSidString,
+                                        TokenUserData->User.Sid,
+                                        TRUE);
+
+  /* we don't need the user data anymore, free it */
+  RtlFreeHeap(ProcessHeap,
+              0,
+              TokenUserData);
+
+  if (!NT_SUCCESS(Status))
+  {
+    return RtlNtStatusToDosError (Status);
   }
-  if (lpftLastWriteTime != NULL) {
-    lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
-    lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
+
+  /* allocate enough memory for the entire key string */
+  UserClassesKeyRoot.Length = 0;
+  UserClassesKeyRoot.MaximumLength = UserSidString.Length +
+                                     sizeof(UserClassesKeyPrefix) +
+                                     sizeof(UserClassesKeySuffix);
+  UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
+                                              0,
+                                              UserClassesKeyRoot.MaximumLength);
+  if (UserClassesKeyRoot.Buffer == NULL)
+  {
+    RtlFreeUnicodeString(&UserSidString);
+    return RtlNtStatusToDosError (Status);
   }
-  if (lpClass) {
-    wcsncpy(lpClass, FullInfo->Class, *lpcbClass);
-    RtlFreeHeap(RtlGetProcessHeap(), 0, FullInfo);
+
+  /* build the string */
+  RtlAppendUnicodeToString(&UserClassesKeyRoot,
+                           UserClassesKeyPrefix);
+  RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
+                                 &UserSidString);
+  RtlAppendUnicodeToString(&UserClassesKeyRoot,
+                           UserClassesKeySuffix);
+
+  TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
+
+  /*
+   * Open the key
+   */
+
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &UserClassesKeyRoot,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  Status = NtOpenKey((PHANDLE)phkResult,
+                     samDesired,
+                     &ObjectAttributes);
+
+  RtlFreeUnicodeString(&UserSidString);
+  RtlFreeUnicodeString(&UserClassesKeyRoot);
+
+  if (!NT_SUCCESS(Status))
+  {
+    return RtlNtStatusToDosError (Status);
   }
-  SetLastError(ERROR_SUCCESS);
+
   return ERROR_SUCCESS;
 }
 
@@ -1525,94 +2610,369 @@ RegQueryInfoKeyW(
  *
  * @implemented
  */
-LONG
-STDCALL
-RegQueryInfoKeyA(
-  HKEY    hKey,
-  LPSTR   lpClass,
-  LPDWORD   lpcbClass,
-  LPDWORD   lpReserved,
-  LPDWORD   lpcSubKeys,
-  LPDWORD   lpcbMaxSubKeyLen,
-  LPDWORD   lpcbMaxClassLen,
-  LPDWORD   lpcValues,
-  LPDWORD   lpcbMaxValueNameLen,
-  LPDWORD   lpcbMaxValueLen,
-  LPDWORD   lpcbSecurityDescriptor,
-  PFILETIME lpftLastWriteTime)
+LONG STDCALL
+RegQueryInfoKeyA (HKEY hKey,
+                 LPSTR lpClass,
+                 LPDWORD lpcbClass,
+                 LPDWORD lpReserved,
+                 LPDWORD lpcSubKeys,
+                 LPDWORD lpcbMaxSubKeyLen,
+                 LPDWORD lpcbMaxClassLen,
+                 LPDWORD lpcValues,
+                 LPDWORD lpcbMaxValueNameLen,
+                 LPDWORD lpcbMaxValueLen,
+                 LPDWORD lpcbSecurityDescriptor,
+                 PFILETIME lpftLastWriteTime)
 {
   WCHAR ClassName[MAX_PATH];
   UNICODE_STRING UnicodeString;
   ANSI_STRING AnsiString;
   LONG ErrorCode;
 
-  RtlInitUnicodeString(&UnicodeString, NULL);
-  if (lpClass) {
-    UnicodeString.Buffer = &ClassName[0];
-    UnicodeString.MaximumLength = sizeof(ClassName);
-  }
-  ErrorCode = RegQueryInfoKeyW(
-    hKey,
-    UnicodeString.Buffer,
-    lpcbClass,
-    lpReserved,
-    lpcSubKeys,
-    lpcbMaxSubKeyLen,
-    lpcbMaxClassLen,
-    lpcValues,
-    lpcbMaxValueNameLen,
-    lpcbMaxValueLen,
-    lpcbSecurityDescriptor,
-    lpftLastWriteTime);
-
-  if ((ErrorCode == ERROR_SUCCESS) && (lpClass)) {
-    RtlInitAnsiString(&AnsiString, NULL);
-    AnsiString.Buffer = lpClass;
-    AnsiString.MaximumLength = *lpcbClass;
-    RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
-    *lpcbClass = AnsiString.Length;
-  }
+  RtlInitUnicodeString (&UnicodeString,
+                       NULL);
+  if (lpClass != NULL)
+    {
+      UnicodeString.Buffer = &ClassName[0];
+      UnicodeString.MaximumLength = sizeof(ClassName);
+      AnsiString.MaximumLength = *lpcbClass;
+    }
+
+  ErrorCode = RegQueryInfoKeyW (hKey,
+                               UnicodeString.Buffer,
+                               lpcbClass,
+                               lpReserved,
+                               lpcSubKeys,
+                               lpcbMaxSubKeyLen,
+                               lpcbMaxClassLen,
+                               lpcValues,
+                               lpcbMaxValueNameLen,
+                               lpcbMaxValueLen,
+                               lpcbSecurityDescriptor,
+                               lpftLastWriteTime);
+  if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
+    {
+      AnsiString.Buffer = lpClass;
+      AnsiString.Length = 0;
+      UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
+      RtlUnicodeStringToAnsiString (&AnsiString,
+                                   &UnicodeString,
+                                   FALSE);
+      *lpcbClass = AnsiString.Length;
+      lpClass[AnsiString.Length] = 0;
+    }
+
+  return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegQueryInfoKeyW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryInfoKeyW (HKEY hKey,
+                 LPWSTR lpClass,
+                 LPDWORD lpcbClass,
+                 LPDWORD lpReserved,
+                 LPDWORD lpcSubKeys,
+                 LPDWORD lpcbMaxSubKeyLen,
+                 LPDWORD lpcbMaxClassLen,
+                 LPDWORD lpcValues,
+                 LPDWORD lpcbMaxValueNameLen,
+                 LPDWORD lpcbMaxValueLen,
+                 LPDWORD lpcbSecurityDescriptor,
+                 PFILETIME lpftLastWriteTime)
+{
+  KEY_FULL_INFORMATION FullInfoBuffer;
+  PKEY_FULL_INFORMATION FullInfo;
+  ULONG FullInfoSize;
+  ULONG ClassLength = 0;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+  ULONG Length;
+  LONG ErrorCode = ERROR_SUCCESS;
+
+  if ((lpClass) && (!lpcbClass))
+    {
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (lpClass != NULL)
+    {
+      if (*lpcbClass > 0)
+       {
+         ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+       }
+      else
+       {
+         ClassLength = 0;
+       }
+
+      FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
+      FullInfo = RtlAllocateHeap (ProcessHeap,
+                                 0,
+                                 FullInfoSize);
+      if (FullInfo == NULL)
+       {
+         ErrorCode = ERROR_OUTOFMEMORY;
+         goto Cleanup;
+       }
+
+      FullInfo->ClassLength = ClassLength;
+    }
+  else
+    {
+      FullInfoSize = sizeof(KEY_FULL_INFORMATION);
+      FullInfo = &FullInfoBuffer;
+      FullInfo->ClassLength = 0;
+    }
+  FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
+
+  Status = NtQueryKey (KeyHandle,
+                      KeyFullInformation,
+                      FullInfo,
+                      FullInfoSize,
+                      &Length);
+  TRACE("NtQueryKey() returned status 0x%X\n", Status);
+  if (!NT_SUCCESS(Status))
+    {
+      if (lpClass != NULL)
+       {
+         RtlFreeHeap (ProcessHeap,
+                      0,
+                      FullInfo);
+       }
+
+      ErrorCode = RtlNtStatusToDosError (Status);
+      goto Cleanup;
+    }
+
+  TRACE("SubKeys %d\n", FullInfo->SubKeys);
+  if (lpcSubKeys != NULL)
+    {
+      *lpcSubKeys = FullInfo->SubKeys;
+    }
+
+  TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
+  if (lpcbMaxSubKeyLen != NULL)
+    {
+      *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
+    }
+
+  TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
+  if (lpcbMaxClassLen != NULL)
+    {
+      *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
+    }
+
+  TRACE("Values %lu\n", FullInfo->Values);
+  if (lpcValues != NULL)
+    {
+      *lpcValues = FullInfo->Values;
+    }
+
+  TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
+  if (lpcbMaxValueNameLen != NULL)
+    {
+      *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
+    }
+
+  TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
+  if (lpcbMaxValueLen != NULL)
+    {
+      *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
+    }
+
+  if (lpcbSecurityDescriptor != NULL)
+    {
+      Status = NtQuerySecurityObject(KeyHandle,
+                                    OWNER_SECURITY_INFORMATION |
+                                    GROUP_SECURITY_INFORMATION |
+                                    DACL_SECURITY_INFORMATION,
+                                    NULL,
+                                    0,
+                                    lpcbSecurityDescriptor);
+      if (!NT_SUCCESS(Status))
+       {
+         if (lpClass != NULL)
+           {
+             RtlFreeHeap(ProcessHeap,
+                         0,
+                         FullInfo);
+           }
+
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
+       }
+    }
+
+  if (lpftLastWriteTime != NULL)
+    {
+      lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
+      lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
+    }
+
+  if (lpClass != NULL)
+    {
+      if (FullInfo->ClassLength > ClassLength)
+       {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+       }
+      else
+       {
+         RtlCopyMemory (lpClass,
+                        FullInfo->Class,
+                        FullInfo->ClassLength);
+         *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
+         lpClass[*lpcbClass] = 0;
+       }
+
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  FullInfo);
+    }
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+  
   return ErrorCode;
 }
 
 
-/************************************************************************
- *  RegQueryMultipleValuesA
- *
- * @unimplemented
- */
-LONG
-STDCALL
-RegQueryMultipleValuesA(
-  HKEY   hKey,
-  PVALENTA val_list,
-  DWORD  num_vals,
-  LPSTR  lpValueBuf,
-  LPDWORD  ldwTotsize)
-{
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+/************************************************************************
+ *  RegQueryMultipleValuesA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryMultipleValuesA (HKEY hKey,
+                        PVALENTA val_list,
+                        DWORD num_vals,
+                        LPSTR lpValueBuf,
+                        LPDWORD ldwTotsize)
+{
+  ULONG i;
+  DWORD maxBytes = *ldwTotsize;
+  LPSTR bufptr = (LPSTR)lpValueBuf;
+  LONG ErrorCode;
+
+  if (maxBytes >= (1024*1024))
+    return ERROR_TRANSFER_TOO_LONG;
+
+  *ldwTotsize = 0;
+
+  TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
+         hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
+
+  for (i = 0; i < num_vals; i++)
+    {
+      val_list[i].ve_valuelen = 0;
+      ErrorCode = RegQueryValueExA (hKey,
+                                   val_list[i].ve_valuename,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &val_list[i].ve_valuelen);
+      if (ErrorCode != ERROR_SUCCESS)
+       {
+         return ErrorCode;
+       }
+
+      if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
+       {
+         ErrorCode = RegQueryValueExA (hKey,
+                                       val_list[i].ve_valuename,
+                                       NULL,
+                                       &val_list[i].ve_type,
+                                       (LPBYTE)bufptr,
+                                       &val_list[i].ve_valuelen);
+         if (ErrorCode != ERROR_SUCCESS)
+           {
+             return ErrorCode;
+           }
+
+         val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
+
+         bufptr += val_list[i].ve_valuelen;
+       }
+
+      *ldwTotsize += val_list[i].ve_valuelen;
+    }
+
+  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
 }
 
 
 /************************************************************************
  *  RegQueryMultipleValuesW
  *
- * @unimplemented
+ * @implemented
  */
-LONG
-STDCALL
-RegQueryMultipleValuesW(
-  HKEY   hKey,
-  PVALENTW val_list,
-  DWORD  num_vals,
-  LPWSTR   lpValueBuf,
-  LPDWORD  ldwTotsize)
+LONG STDCALL
+RegQueryMultipleValuesW (HKEY hKey,
+                        PVALENTW val_list,
+                        DWORD num_vals,
+                        LPWSTR lpValueBuf,
+                        LPDWORD ldwTotsize)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+  ULONG i;
+  DWORD maxBytes = *ldwTotsize;
+  LPSTR bufptr = (LPSTR)lpValueBuf;
+  LONG ErrorCode;
+
+  if (maxBytes >= (1024*1024))
+    return ERROR_TRANSFER_TOO_LONG;
+
+  *ldwTotsize = 0;
+
+  TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
+         hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
+
+  for (i = 0; i < num_vals; i++)
+    {
+      val_list[i].ve_valuelen = 0;
+      ErrorCode = RegQueryValueExW (hKey,
+                                   val_list[i].ve_valuename,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &val_list[i].ve_valuelen);
+      if (ErrorCode != ERROR_SUCCESS)
+       {
+         return ErrorCode;
+       }
+
+      if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
+       {
+         ErrorCode = RegQueryValueExW (hKey,
+                                       val_list[i].ve_valuename,
+                                       NULL,
+                                       &val_list[i].ve_type,
+                                       (LPBYTE)bufptr,
+                                       &val_list[i].ve_valuelen);
+         if (ErrorCode != ERROR_SUCCESS)
+           {
+             return ErrorCode;
+           }
+
+         val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
+
+         bufptr += val_list[i].ve_valuelen;
+       }
+
+      *ldwTotsize += val_list[i].ve_valuelen;
+    }
+
+  return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
 }
 
 
@@ -1621,158 +2981,315 @@ RegQueryMultipleValuesW(
  *
  * @implemented
  */
-LONG
-STDCALL
-RegQueryValueExW(
-  HKEY  hKey,
-  LPCWSTR lpValueName,
-  LPDWORD lpReserved,
-  LPDWORD lpType,
-  LPBYTE  lpData,
-  LPDWORD lpcbData)
+LONG STDCALL
+RegQueryValueExW (HKEY hKey,
+                 LPCWSTR lpValueName,
+                 LPDWORD lpReserved,
+                 LPDWORD lpType,
+                 LPBYTE lpData,
+                 LPDWORD lpcbData)
 {
   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
   UNICODE_STRING ValueName;
   NTSTATUS Status;
-  DWORD dwError = ERROR_SUCCESS;
   ULONG BufferSize;
   ULONG ResultSize;
-  HKEY KeyHandle;
-
-  DPRINT("hKey 0x%X  lpValueName %S  lpData 0x%X  lpcbData %d\n",
-    hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-      dwError = RtlNtStatusToDosError(Status);
-      SetLastError(dwError);
-      return(dwError);
-  }
-  if ((lpData) && (!lpcbData)) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
-  }
-  RtlInitUnicodeString (&ValueName, lpValueName);
-  BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + *lpcbData;
-  ValueInfo = RtlAllocateHeap (RtlGetProcessHeap(),
-             0,
-             BufferSize);
-  if (ValueInfo == NULL) {
-    SetLastError(ERROR_OUTOFMEMORY);
-    return ERROR_OUTOFMEMORY;
-  }
-  Status = NtQueryValueKey (hKey,
-          &ValueName,
-          KeyValuePartialInformation,
-          ValueInfo,
-          BufferSize,
-          &ResultSize);
-  DPRINT("Status 0x%X\n", Status);
-  if (Status == STATUS_BUFFER_TOO_SMALL) {
-    /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
-    dwError = ERROR_SUCCESS;
-  }
-  else if (!NT_SUCCESS(Status)) {
-    dwError = RtlNtStatusToDosError(Status);
-    SetLastError(dwError);
-  }
-  else {
-    if (lpType) {
+  HANDLE KeyHandle;
+  LONG ErrorCode = ERROR_SUCCESS;
+  ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
+
+  TRACE("hKey 0x%X  lpValueName %S  lpData 0x%X  lpcbData %d\n",
+        hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
+
+  Status = MapDefaultKey (&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (lpData != NULL && lpcbData == NULL)
+    {
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
+    }
+
+  RtlInitUnicodeString (&ValueName,
+                       lpValueName);
+  BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
+  ValueInfo = RtlAllocateHeap (ProcessHeap,
+                              0,
+                              BufferSize);
+  if (ValueInfo == NULL)
+    {
+      ErrorCode = ERROR_OUTOFMEMORY;
+      goto Cleanup;
+    }
+
+  Status = NtQueryValueKey (KeyHandle,
+                           &ValueName,
+                           KeyValuePartialInformation,
+                           ValueInfo,
+                           BufferSize,
+                           &ResultSize);
+  TRACE("Status 0x%X\n", Status);
+  if (Status == STATUS_BUFFER_OVERFLOW)
+    {
+      /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
+      MaxCopy = 0;
+      ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
+    }
+  else if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      MaxCopy = 0;
+      if (lpcbData != NULL)
+       {
+         ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
+       }
+    }
+
+  if (lpType != NULL)
+    {
       *lpType = ValueInfo->Type;
     }
-    RtlMoveMemory(lpData, ValueInfo->Data, ValueInfo->DataLength);
-    if ((ValueInfo->Type == REG_SZ) ||
-        (ValueInfo->Type == REG_MULTI_SZ) ||
-        (ValueInfo->Type == REG_EXPAND_SZ)) {
-      ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
+
+  if (NT_SUCCESS(Status) && lpData != NULL)
+    {
+      RtlMoveMemory (lpData,
+                    ValueInfo->Data,
+                    min(ValueInfo->DataLength, MaxCopy));
+    }
+
+  if ((ValueInfo->Type == REG_SZ) ||
+      (ValueInfo->Type == REG_MULTI_SZ) ||
+      (ValueInfo->Type == REG_EXPAND_SZ))
+    {
+      if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
+       {
+         ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
+       }
+
+      if (lpcbData != NULL)
+       {
+         *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
+         TRACE("(string) Returning Size: %lu\n", *lpcbData);
+       }
+    }
+  else
+    {
+      if (lpcbData != NULL)
+       {
+         *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
+         TRACE("(other) Returning Size: %lu\n", *lpcbData);
+       }
     }
-  }
-  DPRINT("Type %d  Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
-  if (NULL != lpcbData) {
-    *lpcbData = (DWORD)ValueInfo->DataLength;
-  }
-  RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
-  return dwError;
+
+  TRACE("Type %d  Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
+
+  RtlFreeHeap (ProcessHeap,
+              0,
+              ValueInfo);
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
 }
 
 
 /************************************************************************
  *  RegQueryValueExA
  *
- * @unimplemented
+ * @implemented
  */
-LONG
-STDCALL
-RegQueryValueExA(
-  HKEY  hKey,
-  LPCSTR  lpValueName,
-  LPDWORD lpReserved,
-  LPDWORD lpType,
-  LPBYTE  lpData,
-  LPDWORD lpcbData)
-{
-  WCHAR ValueNameBuffer[MAX_PATH+1];
+LONG STDCALL
+RegQueryValueExA (HKEY hKey,
+                 LPCSTR lpValueName,
+                 LPDWORD lpReserved,
+                 LPDWORD lpType,
+                 LPBYTE  lpData,
+                 LPDWORD lpcbData)
+{
   UNICODE_STRING ValueName;
   UNICODE_STRING ValueData;
   ANSI_STRING AnsiString;
   LONG ErrorCode;
-  DWORD ResultSize;
+  DWORD Length;
   DWORD Type;
 
-  /* FIXME: HKEY_PERFORMANCE_DATA is special, see MS SDK */
+  TRACE("hKey 0x%X  lpValueName %s  lpData 0x%X  lpcbData %d\n",
+        hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
 
-  if ((lpData) && (!lpcbData)) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
-  }
-  RtlInitUnicodeString(&ValueData, NULL);
-  if (lpData) {
-    ValueData.MaximumLength = *lpcbData * sizeof(WCHAR);
-    ValueData.Buffer = RtlAllocateHeap(
-      RtlGetProcessHeap(),
-      0,
-      ValueData.MaximumLength);
-    if (!ValueData.Buffer) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
+  if (lpData != NULL && lpcbData == NULL)
+    {
+      return ERROR_INVALID_PARAMETER;
     }
-  }
-  RtlInitAnsiString(&AnsiString, (LPSTR)lpValueName);
-  RtlInitUnicodeString(&ValueName, NULL);
-  ValueName.Buffer = &ValueNameBuffer[0];
-  ValueName.MaximumLength = sizeof(ValueNameBuffer);
-  RtlAnsiStringToUnicodeString(&ValueName, &AnsiString, FALSE);
-  if (lpcbData) {
-    ResultSize = *lpcbData;
-  } else {
-    ResultSize = 0;
-  }
-  ErrorCode = RegQueryValueExW(
-    hKey,
-    ValueName.Buffer,
-    lpReserved,
-    &Type,
-    (LPBYTE)ValueData.Buffer,
-    &ResultSize);
-  if ((ErrorCode == ERROR_SUCCESS) && (ValueData.Buffer != NULL)) {
-    if (lpType) {
-      *lpType = Type;
-    }
-    if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ)) {
-      ValueData.Length = ResultSize;
-      RtlInitAnsiString(&AnsiString, NULL);
-      AnsiString.Buffer = lpData;
-      AnsiString.MaximumLength = *lpcbData;
-      RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
-    } else {
-      RtlMoveMemory(lpData, ValueData.Buffer, ResultSize);
+
+  if (lpData)
+    {
+      ValueData.Length = 0;
+      ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
+      ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
+                                         0,
+                                         ValueData.MaximumLength);
+      if (!ValueData.Buffer)
+       {
+         return ERROR_OUTOFMEMORY;
+       }
     }
-  }
-  if (lpcbData) {
-    *lpcbData = ResultSize;
-  }
-  if (ValueData.Buffer) {
-    RtlFreeHeap(RtlGetProcessHeap(), 0, ValueData.Buffer);
-  }
+  else
+    {
+      ValueData.Buffer = NULL;
+      ValueData.Length = 0;
+      ValueData.MaximumLength = 0;
+    }
+
+  RtlCreateUnicodeStringFromAsciiz (&ValueName,
+                                   (LPSTR)lpValueName);
+
+  Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
+  ErrorCode = RegQueryValueExW (hKey,
+                               ValueName.Buffer,
+                               lpReserved,
+                               &Type,
+                               (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
+                               &Length);
+  TRACE("ErrorCode %lu\n", ErrorCode);
+  RtlFreeUnicodeString(&ValueName);
+
+  if (ErrorCode == ERROR_SUCCESS ||
+      ErrorCode == ERROR_MORE_DATA)
+    {
+      if (lpType != NULL)
+       {
+         *lpType = Type;
+       }
+
+      if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
+       {
+         if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
+           {
+             RtlInitAnsiString(&AnsiString, NULL);
+             AnsiString.Buffer = (LPSTR)lpData;
+             AnsiString.MaximumLength = *lpcbData;
+             ValueData.Length = Length;
+             ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
+             RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
+           }
+         Length = Length / sizeof(WCHAR);
+       }
+      else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
+       {
+          if (*lpcbData < Length)
+            {
+              ErrorCode = ERROR_MORE_DATA;
+            }
+          else
+            {
+              RtlMoveMemory(lpData, ValueData.Buffer, Length);
+            }
+       }
+
+      if (lpcbData != NULL)
+       {
+         *lpcbData = Length;
+       }
+    }
+
+  if (ValueData.Buffer != NULL)
+    {
+      RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
+    }
+
+  return ErrorCode;
+}
+
+
+/************************************************************************
+ *  RegQueryValueA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryValueA (HKEY hKey,
+               LPCSTR lpSubKey,
+               LPSTR lpValue,
+               PLONG lpcbValue)
+{
+  WCHAR SubKeyNameBuffer[MAX_PATH+1];
+  UNICODE_STRING SubKeyName;
+  UNICODE_STRING Value;
+  ANSI_STRING AnsiString;
+  LONG ValueSize;
+  LONG ErrorCode;
+
+  TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
+        hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
+
+  if (lpValue != NULL &&
+      lpcbValue == NULL)
+    {
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  RtlInitUnicodeString (&SubKeyName,
+                       NULL);
+  RtlInitUnicodeString (&Value,
+                       NULL);
+  if (lpSubKey != NULL &&
+      strlen(lpSubKey) != 0)
+    {
+      RtlInitAnsiString (&AnsiString,
+                        (LPSTR)lpSubKey);
+      SubKeyName.Buffer = &SubKeyNameBuffer[0];
+      SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
+      RtlAnsiStringToUnicodeString (&SubKeyName,
+                                   &AnsiString,
+                                   FALSE);
+    }
+
+  if (lpValue != NULL)
+    {
+      ValueSize = *lpcbValue * sizeof(WCHAR);
+      Value.MaximumLength = ValueSize;
+      Value.Buffer = RtlAllocateHeap (ProcessHeap,
+                                     0,
+                                     ValueSize);
+      if (Value.Buffer == NULL)
+       {
+         return ERROR_OUTOFMEMORY;
+       }
+    }
+  else
+    {
+      ValueSize = 0;
+    }
+
+  ErrorCode = RegQueryValueW (hKey,
+                             (LPCWSTR)SubKeyName.Buffer,
+                             Value.Buffer,
+                             &ValueSize);
+  if (ErrorCode == ERROR_SUCCESS)
+    {
+      Value.Length = ValueSize;
+      RtlInitAnsiString (&AnsiString,
+                        NULL);
+      AnsiString.Buffer = lpValue;
+      AnsiString.MaximumLength = *lpcbValue;
+      RtlUnicodeStringToAnsiString (&AnsiString,
+                                   &Value,
+                                   FALSE);
+    }
+
+  *lpcbValue = ValueSize;
+  if (Value.Buffer != NULL)
+    {
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  Value.Buffer);
+    }
+
   return ErrorCode;
 }
 
@@ -1782,217 +3299,356 @@ RegQueryValueExA(
  *
  * @implemented
  */
-LONG
-STDCALL
-RegQueryValueW(
-  HKEY  hKey,
-  LPCWSTR lpSubKey,
-  LPWSTR  lpValue,
-  PLONG lpcbValue)
+LONG STDCALL
+RegQueryValueW (HKEY hKey,
+               LPCWSTR lpSubKey,
+               LPWSTR lpValue,
+               PLONG lpcbValue)
 {
-  NTSTATUS    errCode;
-  UNICODE_STRING    SubKeyString;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  HKEY      KeyHandle;
-  HANDLE      RealKey;
-  LONG        ErrorCode;
-  BOOL        CloseRealKey;
-
-  errCode = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(errCode)) {
-    ErrorCode = RtlNtStatusToDosError(errCode);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  if ((lpSubKey) && (wcslen(lpSubKey) != 0)) {
-    RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-             &SubKeyString,
-             OBJ_CASE_INSENSITIVE,
-             KeyHandle,
-             NULL);
-    errCode = NtOpenKey(
-        &RealKey,
-        KEY_ALL_ACCESS,
-        & ObjectAttributes);
-    if (!NT_SUCCESS(errCode)) {
-      ErrorCode = RtlNtStatusToDosError(errCode);
-      SetLastError(ErrorCode);
-      return ErrorCode;
-    }
-    CloseRealKey = TRUE;
-  } else {
-    RealKey = hKey;
-    CloseRealKey = FALSE;
-  }
-  ErrorCode = RegQueryValueExW(
-    RealKey,
-    NULL,
-    NULL,
-    NULL,
-    (LPBYTE)lpValue,
-    (LPDWORD)lpcbValue);
-  if (CloseRealKey) {
-    NtClose(RealKey);
-  }
+  UNICODE_STRING SubKeyString;
+  HANDLE KeyHandle;
+  HANDLE RealKey;
+  LONG ErrorCode;
+  BOOL CloseRealKey;
+  NTSTATUS Status;
+
+  TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
+        hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (lpSubKey != NULL &&
+      wcslen(lpSubKey) != 0)
+    {
+      RtlInitUnicodeString (&SubKeyString,
+                           (LPWSTR)lpSubKey);
+      InitializeObjectAttributes (&ObjectAttributes,
+                                 &SubKeyString,
+                                 OBJ_CASE_INSENSITIVE,
+                                 KeyHandle,
+                                 NULL);
+      Status = NtOpenKey (&RealKey,
+                         KEY_QUERY_VALUE,
+                         &ObjectAttributes);
+      if (!NT_SUCCESS(Status))
+       {
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
+       }
+      CloseRealKey = TRUE;
+    }
+  else
+    {
+      RealKey = hKey;
+      CloseRealKey = FALSE;
+    }
+
+  ErrorCode = RegQueryValueExW (RealKey,
+                               NULL,
+                               NULL,
+                               NULL,
+                               (LPBYTE)lpValue,
+                               (LPDWORD)lpcbValue);
+  if (CloseRealKey)
+    {
+      NtClose (RealKey);
+    }
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
 
 /************************************************************************
- *  RegQueryValueA
+ *  RegReplaceKeyA
  *
  * @implemented
  */
-LONG
-STDCALL
-RegQueryValueA(
-  HKEY  hKey,
-  LPCSTR  lpSubKey,
-  LPSTR lpValue,
-  PLONG lpcbValue)
+LONG STDCALL
+RegReplaceKeyA (HKEY hKey,
+               LPCSTR lpSubKey,
+               LPCSTR lpNewFile,
+               LPCSTR lpOldFile)
 {
-  WCHAR SubKeyNameBuffer[MAX_PATH+1];
-  UNICODE_STRING SubKeyName;
-  UNICODE_STRING Value;
-  ANSI_STRING AnsiString;
-  LONG ValueSize;
+  UNICODE_STRING SubKey;
+  UNICODE_STRING NewFile;
+  UNICODE_STRING OldFile;
   LONG ErrorCode;
 
-  if ((lpValue) && (!lpcbValue)) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
-  }
-  RtlInitUnicodeString(&SubKeyName, NULL);
-  RtlInitUnicodeString(&Value, NULL);
-  if ((lpSubKey) && (strlen(lpSubKey) != 0)) {
-    RtlInitAnsiString(&AnsiString, (LPSTR)lpSubKey);
-    SubKeyName.Buffer = &SubKeyNameBuffer[0];
-    SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
-    RtlAnsiStringToUnicodeString(&SubKeyName, &AnsiString, FALSE);
-  }
-  if (lpValue) {
-    ValueSize = *lpcbValue * sizeof(WCHAR);
-    Value.MaximumLength = ValueSize;
-    Value.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueSize);
-    if (!Value.Buffer) {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-  } else {
-    ValueSize = 0;
-  }
-  ErrorCode = RegQueryValueW(
-    hKey,
-    (LPCWSTR)SubKeyName.Buffer,
-    Value.Buffer,
-    &ValueSize);
-  if (ErrorCode == ERROR_SUCCESS) {
-    Value.Length = ValueSize;
-    RtlInitAnsiString(&AnsiString, NULL);
-    AnsiString.Buffer = lpValue;
-    AnsiString.MaximumLength = *lpcbValue;
-    RtlUnicodeStringToAnsiString(&AnsiString, &Value, FALSE);
-  }
-  *lpcbValue = ValueSize; 
-  if (Value.Buffer) {
-    RtlFreeHeap(RtlGetProcessHeap(), 0, Value.Buffer);
-  }
+  RtlCreateUnicodeStringFromAsciiz (&SubKey,
+                                   (PCSZ)lpSubKey);
+  RtlCreateUnicodeStringFromAsciiz (&OldFile,
+                                   (PCSZ)lpOldFile);
+  RtlCreateUnicodeStringFromAsciiz (&NewFile,
+                                   (PCSZ)lpNewFile);
+
+  ErrorCode = RegReplaceKeyW (hKey,
+                             SubKey.Buffer,
+                             NewFile.Buffer,
+                             OldFile.Buffer);
+
+  RtlFreeUnicodeString (&OldFile);
+  RtlFreeUnicodeString (&NewFile);
+  RtlFreeUnicodeString (&SubKey);
+
   return ErrorCode;
 }
 
 
 /************************************************************************
- *  RegReplaceKeyA
+ *  RegReplaceKeyW
  *
  * @unimplemented
  */
-LONG
-STDCALL
-RegReplaceKeyA(
-  HKEY  hKey,
-  LPCSTR  lpSubKey,
-  LPCSTR  lpNewFile,
-  LPCSTR  lpOldFile)
+LONG STDCALL
+RegReplaceKeyW (HKEY hKey,
+               LPCWSTR lpSubKey,
+               LPCWSTR lpNewFile,
+               LPCWSTR lpOldFile)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
-}
+  OBJECT_ATTRIBUTES KeyObjectAttributes;
+  OBJECT_ATTRIBUTES NewObjectAttributes;
+  OBJECT_ATTRIBUTES OldObjectAttributes;
+  UNICODE_STRING SubKeyName;
+  UNICODE_STRING NewFileName;
+  UNICODE_STRING OldFileName;
+  BOOLEAN CloseRealKey;
+  HANDLE RealKeyHandle;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  /* Open the real key */
+  if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
+    {
+      RtlInitUnicodeString (&SubKeyName,
+                           (PWSTR)lpSubKey);
+      InitializeObjectAttributes (&KeyObjectAttributes,
+                                 &SubKeyName,
+                                 OBJ_CASE_INSENSITIVE,
+                                 KeyHandle,
+                                 NULL);
+      Status = NtOpenKey (&RealKeyHandle,
+                         MAXIMUM_ALLOWED,
+                         &KeyObjectAttributes);
+      if (!NT_SUCCESS(Status))
+       {
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
+       }
+      CloseRealKey = TRUE;
+    }
+  else
+    {
+      RealKeyHandle = KeyHandle;
+      CloseRealKey = FALSE;
+    }
+
+  /* Convert new file name */
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
+                                    &NewFileName,
+                                    NULL,
+                                    NULL))
+    {
+      if (CloseRealKey)
+       {
+         NtClose (RealKeyHandle);
+       }
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
+    }
+
+  InitializeObjectAttributes (&NewObjectAttributes,
+                             &NewFileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  /* Convert old file name */
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
+                                    &OldFileName,
+                                    NULL,
+                                    NULL))
+    {
+      RtlFreeUnicodeString (&NewFileName);
+      if (CloseRealKey)
+       {
+         NtClose (RealKeyHandle);
+       }
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
+    }
+
+  InitializeObjectAttributes (&OldObjectAttributes,
+                             &OldFileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  Status = NtReplaceKey (&NewObjectAttributes,
+                        RealKeyHandle,
+                        &OldObjectAttributes);
+
+  RtlFreeUnicodeString (&OldFileName);
+  RtlFreeUnicodeString (&NewFileName);
+
+  if (CloseRealKey)
+    {
+      NtClose (RealKeyHandle);
+    }
+
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
 
-/************************************************************************
- *  RegReplaceKeyW
- *
- * @unimplemented
- */
-LONG
-STDCALL
-RegReplaceKeyW(
-  HKEY  hKey,
-  LPCWSTR lpSubKey,
-  LPCWSTR lpNewFile,
-  LPCWSTR lpOldFile)
-{
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+  return ErrorCode;
 }
 
 
 /************************************************************************
  *  RegRestoreKeyA
  *
- * @unimplemented
+ * @implemented
  */
-LONG
-STDCALL
-RegRestoreKeyA(
-  HKEY  hKey,
-  LPCSTR  lpFile,
-  DWORD dwFlags)
+LONG STDCALL
+RegRestoreKeyA (HKEY hKey,
+               LPCSTR lpFile,
+               DWORD dwFlags)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+  UNICODE_STRING FileName;
+  LONG ErrorCode;
+
+  RtlCreateUnicodeStringFromAsciiz (&FileName,
+                                   (PCSZ)lpFile);
+
+  ErrorCode = RegRestoreKeyW (hKey,
+                             FileName.Buffer,
+                             dwFlags);
+
+  RtlFreeUnicodeString (&FileName);
+
+  return ErrorCode;
 }
 
 
 /************************************************************************
  *  RegRestoreKeyW
  *
- * @unimplemented
+ * @implemented
  */
-LONG
-STDCALL
-RegRestoreKeyW(
-  HKEY  hKey,
-  LPCWSTR lpFile,
-  DWORD dwFlags)
+LONG STDCALL
+RegRestoreKeyW (HKEY hKey,
+               LPCWSTR lpFile,
+               DWORD dwFlags)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING FileName;
+  HANDLE FileHandle;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      Status = STATUS_INVALID_PARAMETER;
+      goto Cleanup;
+    }
+
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &FileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  Status = NtOpenFile (&FileHandle,
+                      FILE_GENERIC_READ,
+                      &ObjectAttributes,
+                      &IoStatusBlock,
+                      FILE_SHARE_READ,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
+  RtlFreeUnicodeString (&FileName);
+  if (!NT_SUCCESS(Status))
+    {
+      goto Cleanup;
+    }
+
+  Status = NtRestoreKey (KeyHandle,
+                        FileHandle,
+                        (ULONG)dwFlags);
+  NtClose (FileHandle);
+  
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
  *  RegSaveKeyA
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
-RegSaveKeyA(HKEY hKey,
-           LPCSTR lpFile,
-           LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+RegSaveKeyA (HKEY hKey,
+            LPCSTR lpFile,
+            LPSECURITY_ATTRIBUTES lpSecurityAttributes)
 {
   UNICODE_STRING FileName;
   LONG ErrorCode;
 
-  RtlCreateUnicodeStringFromAsciiz(&FileName, (LPSTR)lpFile);
-  ErrorCode = RegSaveKeyW(hKey, FileName.Buffer, lpSecurityAttributes);
-  RtlFreeUnicodeString(&FileName);
-  return(ErrorCode);
+  RtlCreateUnicodeStringFromAsciiz (&FileName,
+                                   (LPSTR)lpFile);
+  ErrorCode = RegSaveKeyW (hKey,
+                          FileName.Buffer,
+                          lpSecurityAttributes);
+  RtlFreeUnicodeString (&FileName);
+
+  return ErrorCode;
 }
 
 
@@ -2002,35 +3658,32 @@ RegSaveKeyA(HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegSaveKeyW(HKEY hKey,
-      LPCWSTR lpFile,
-      LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+RegSaveKeyW (HKEY hKey,
+            LPCWSTR lpFile,
+            LPSECURITY_ATTRIBUTES lpSecurityAttributes)
 {
   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING NtName;
+  UNICODE_STRING FileName;
   IO_STATUS_BLOCK IoStatusBlock;
   HANDLE FileHandle;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   NTSTATUS Status;
-  LONG ErrorCode;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+      return RtlNtStatusToDosError (Status);
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
-                                    &NtName,
+  if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
+                                    &FileName,
                                     NULL,
                                     NULL))
     {
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return(ERROR_INVALID_PARAMETER);
+      Status = STATUS_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   if (lpSecurityAttributes != NULL)
@@ -2039,7 +3692,7 @@ RegSaveKeyW(HKEY hKey,
     }
 
   InitializeObjectAttributes (&ObjectAttributes,
-                             &NtName,
+                             &FileName,
                              OBJ_CASE_INSENSITIVE,
                              NULL,
                              SecurityDescriptor);
@@ -2054,89 +3707,64 @@ RegSaveKeyW(HKEY hKey,
                         FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                         NULL,
                         0);
-  RtlFreeUnicodeString(&NtName);
+  RtlFreeUnicodeString (&FileName);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+      goto Cleanup;
     }
 
-  Status = NtSaveKey(KeyHandle,
-                    FileHandle);
-  NtClose(FileHandle);
+  Status = NtSaveKey (KeyHandle,
+                     FileHandle);
+  NtClose (FileHandle);
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError(Status);
-      SetLastError(ErrorCode);
-      return(ErrorCode);
+      return RtlNtStatusToDosError (Status);
     }
 
-  return(ERROR_SUCCESS);
+  return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
  *  RegSetKeySecurity
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
-RegSetKeySecurity(HKEY hKey,
-                 SECURITY_INFORMATION SecurityInformation,
-                 PSECURITY_DESCRIPTOR pSecurityDescriptor)
+RegSetKeySecurity (HKEY hKey,
+                  SECURITY_INFORMATION SecurityInformation,
+                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
-}
+  HANDLE KeyHandle;
+  NTSTATUS Status;
 
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
 
-/************************************************************************
- *  RegSetValueExW
- *
- * @implemented
- */
-LONG
-STDCALL
-RegSetValueExW(
-  HKEY    hKey,
-  LPCWSTR lpValueName,
-  DWORD   Reserved,
-  DWORD   dwType,
-  CONST BYTE* lpData,
-  DWORD   cbData)
-{
-  UNICODE_STRING ValueName;
-  PUNICODE_STRING pValueName;
-  HKEY KeyHandle;
-  NTSTATUS Status;
-  LONG ErrorCode;
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  Status = NtSetSecurityObject (KeyHandle,
+                               SecurityInformation,
+                               pSecurityDescriptor);
+
+  CloseDefaultKey(KeyHandle);
+  
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
 
-  Status = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(Status)) {
-    ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError(ErrorCode);
-    return ErrorCode;
-  }
-  if (lpValueName) {
-    RtlInitUnicodeString(&ValueName, lpValueName);
-    pValueName = &ValueName;
-  } else {
-    pValueName = NULL;
-  }
-  Status = NtSetValueKey(
-    KeyHandle,
-    pValueName,
-    0,
-    dwType,
-    (PVOID)lpData,
-    (ULONG)cbData);
-  if (!NT_SUCCESS(Status)) {
-    LONG ErrorCode = RtlNtStatusToDosError(Status);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
   return ERROR_SUCCESS;
 }
 
@@ -2146,15 +3774,13 @@ RegSetValueExW(
  *
  * @implemented
  */
-LONG
-STDCALL
-RegSetValueExA(
-  HKEY    hKey,
-  LPCSTR  lpValueName,
-  DWORD   Reserved,
-  DWORD   dwType,
-  CONST BYTE* lpData,
-  DWORD   cbData)
+LONG STDCALL
+RegSetValueExA (HKEY hKey,
+               LPCSTR lpValueName,
+               DWORD Reserved,
+               DWORD dwType,
+               CONST BYTE* lpData,
+               DWORD cbData)
 {
   UNICODE_STRING ValueName;
   LPWSTR pValueName;
@@ -2164,103 +3790,132 @@ RegSetValueExA(
   LPBYTE pData;
   DWORD DataSize;
 
-  if (!lpData) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
-  }
-  if ((lpValueName) && (strlen(lpValueName) != 0)) {
-    RtlCreateUnicodeStringFromAsciiz(&ValueName, (LPSTR)lpValueName);
-    pValueName = (LPWSTR)ValueName.Buffer;
-  } else {
-    pValueName = NULL;
-  }
-  if ((dwType == REG_SZ) || (dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ)) {
-    RtlInitAnsiString(&AnsiString, NULL);
-    AnsiString.Buffer = (LPSTR)lpData;
-    AnsiString.Length = cbData;
-    AnsiString.MaximumLength = cbData;
-    RtlAnsiStringToUnicodeString(&Data, &AnsiString, TRUE);
-    pData = (LPBYTE)Data.Buffer;
-    DataSize = cbData * sizeof(WCHAR);
-  } else {
-    RtlInitUnicodeString(&Data, NULL);
-    pData = (LPBYTE)lpData;
-    DataSize = cbData;
-  }
-  ErrorCode = RegSetValueExW(
-    hKey,
-    pValueName,
-    Reserved,
-    dwType,
-    pData,
-    DataSize);
-  if (pValueName) {
-    RtlFreeHeap(RtlGetProcessHeap(), 0, ValueName.Buffer);
-  }
-  if (Data.Buffer) {
-    RtlFreeHeap(RtlGetProcessHeap(), 0, Data.Buffer);
-  }
+  if (lpValueName != NULL &&
+      strlen(lpValueName) != 0)
+    {
+      RtlCreateUnicodeStringFromAsciiz (&ValueName,
+                                       (PSTR)lpValueName);
+      pValueName = (LPWSTR)ValueName.Buffer;
+    }
+  else
+    {
+      pValueName = NULL;
+    }
+
+  if (((dwType == REG_SZ) ||
+       (dwType == REG_MULTI_SZ) ||
+       (dwType == REG_EXPAND_SZ)) &&
+      (cbData != 0))
+    {
+      /* NT adds one if the caller forgot the NULL-termination character */
+      if (lpData[cbData - 1] != '\0')
+      {
+         cbData++;
+      }
+
+      RtlInitAnsiString (&AnsiString,
+                        NULL);
+      AnsiString.Buffer = (PSTR)lpData;
+      AnsiString.Length = cbData - 1;
+      AnsiString.MaximumLength = cbData;
+      RtlAnsiStringToUnicodeString (&Data,
+                                   &AnsiString,
+                                   TRUE);
+      pData = (LPBYTE)Data.Buffer;
+      DataSize = cbData * sizeof(WCHAR);
+    }
+  else
+    {
+      RtlInitUnicodeString (&Data,
+                           NULL);
+      pData = (LPBYTE)lpData;
+      DataSize = cbData;
+    }
+
+  ErrorCode = RegSetValueExW (hKey,
+                             pValueName,
+                             Reserved,
+                             dwType,
+                             pData,
+                             DataSize);
+  if (pValueName != NULL)
+    {
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  ValueName.Buffer);
+    }
+
+  if (Data.Buffer != NULL)
+    {
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  Data.Buffer);
+    }
+
   return ErrorCode;
 }
 
 
 /************************************************************************
- *  RegSetValueW
+ *  RegSetValueExW
  *
  * @implemented
  */
-LONG
-STDCALL
-RegSetValueW(
-  HKEY  hKey,
-  LPCWSTR lpSubKey,
-  DWORD dwType,
-  LPCWSTR lpData,
-  DWORD cbData)
-{
-  NTSTATUS    errCode;
-  UNICODE_STRING    SubKeyString;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  HKEY        KeyHandle;
-  HANDLE      RealKey;
-  LONG        ErrorCode;
-  BOOL        CloseRealKey;
-
-  errCode = MapDefaultKey(&KeyHandle, hKey);
-  if (!NT_SUCCESS(errCode)) {
-    ErrorCode = RtlNtStatusToDosError(errCode);
-    SetLastError (ErrorCode);
-    return ErrorCode;
-  }
-  if ((lpSubKey) && (wcslen(lpSubKey) != 0)) {
-    RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-             &SubKeyString,
-             OBJ_CASE_INSENSITIVE,
-             KeyHandle,
-             NULL);
-    errCode = NtOpenKey(&RealKey, KEY_ALL_ACCESS, &ObjectAttributes);
-    if (!NT_SUCCESS(errCode)) {
-      ErrorCode = RtlNtStatusToDosError(errCode);
-      SetLastError(ErrorCode);
-      return ErrorCode;
-    }
-    CloseRealKey = TRUE;
-  } else {
-    RealKey = hKey;
-    CloseRealKey = FALSE;
-  }
-  ErrorCode = RegSetValueExW(
-    RealKey,
-    NULL,
-    0,
-    dwType,
-    (LPBYTE)lpData,
-    cbData);
-  if (CloseRealKey) {
-    NtClose(RealKey);
-  }
-  return ErrorCode;
+LONG STDCALL
+RegSetValueExW (HKEY hKey,
+               LPCWSTR lpValueName,
+               DWORD Reserved,
+               DWORD dwType,
+               CONST BYTE* lpData,
+               DWORD cbData)
+{
+  UNICODE_STRING ValueName;
+  PUNICODE_STRING pValueName;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if (lpValueName != NULL)
+    {
+      RtlInitUnicodeString (&ValueName,
+                           lpValueName);
+    }
+  else
+    {
+      RtlInitUnicodeString (&ValueName, L"");
+    }
+  pValueName = &ValueName;
+
+  if (((dwType == REG_SZ) ||
+       (dwType == REG_MULTI_SZ) ||
+       (dwType == REG_EXPAND_SZ)) &&
+      (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
+    {
+      /* NT adds one if the caller forgot the NULL-termination character */
+      cbData += sizeof(WCHAR);
+    }
+
+  Status = NtSetValueKey (KeyHandle,
+                         pValueName,
+                         0,
+                         dwType,
+                         (PVOID)lpData,
+                         (ULONG)cbData);
+
+  CloseDefaultKey(KeyHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  return ERROR_SUCCESS;
 }
 
 
@@ -2270,45 +3925,116 @@ RegSetValueW(
  * @implemented
  */
 LONG STDCALL
-RegSetValueA(HKEY  hKey,
-            LPCSTR  lpSubKey,
-            DWORD dwType,
-            LPCSTR  lpData,
-            DWORD cbData)
+RegSetValueA (HKEY hKey,
+             LPCSTR lpSubKey,
+             DWORD dwType,
+             LPCSTR lpData,
+             DWORD cbData)
 {
-  WCHAR SubKeyNameBuffer[MAX_PATH+1];
-  UNICODE_STRING SubKeyName;
-  UNICODE_STRING Data;
-  ANSI_STRING AnsiString;
-  LONG DataSize;
-  LONG ErrorCode;
+  LONG ret;
+  HKEY hSubKey;
 
-  if (!lpData) {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return ERROR_INVALID_PARAMETER;
+  if (dwType != REG_SZ)
+  {
+     return ERROR_INVALID_PARAMETER;
   }
-  RtlInitUnicodeString(&SubKeyName, NULL);
-  RtlInitUnicodeString(&Data, NULL);
-  if ((lpSubKey) && (strlen(lpSubKey) != 0)) {
-    RtlInitAnsiString(&AnsiString, (LPSTR)lpSubKey);
-    SubKeyName.Buffer = &SubKeyNameBuffer[0];
-    SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
-    RtlAnsiStringToUnicodeString(&SubKeyName, &AnsiString, FALSE);
+
+  if (lpSubKey != NULL && lpSubKey[0] != '\0')
+  {
+     ret = RegCreateKeyA(hKey,
+                         lpSubKey,
+                         &hSubKey);
+
+     if (ret != ERROR_SUCCESS)
+     {
+        return ret;
+     }
   }
-  DataSize = cbData * sizeof(WCHAR);
-  Data.MaximumLength = DataSize;
-  Data.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DataSize);
-  if (!Data.Buffer) {
-    SetLastError(ERROR_OUTOFMEMORY);
-    return ERROR_OUTOFMEMORY;
+  else
+     hSubKey = hKey;
+
+  ret = RegSetValueExA(hSubKey,
+                       NULL,
+                       0,
+                       REG_SZ,
+                       (CONST BYTE*)lpData,
+                       strlen(lpData) + 1);
+
+  if (hSubKey != hKey)
+  {
+     RegCloseKey(hSubKey);
   }
-  ErrorCode = RegSetValueW(
-    hKey,
-    (LPCWSTR)SubKeyName.Buffer,
-    dwType,
-    Data.Buffer,
-    DataSize);
-  RtlFreeHeap(RtlGetProcessHeap(), 0, Data.Buffer);
+
+  return ret;
+}
+
+
+/************************************************************************
+ *  RegSetValueW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegSetValueW (HKEY hKey,
+             LPCWSTR lpSubKey,
+             DWORD dwType,
+             LPCWSTR lpData,
+             DWORD cbData)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING SubKeyString;
+  HANDLE KeyHandle;
+  HANDLE RealKey;
+  BOOL CloseRealKey;
+  NTSTATUS Status;
+  LONG ErrorCode;
+
+  Status = MapDefaultKey (&KeyHandle,
+                          hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      return RtlNtStatusToDosError (Status);
+    }
+
+  if ((lpSubKey) && (wcslen(lpSubKey) != 0))
+    {
+      RtlInitUnicodeString (&SubKeyString,
+                           (LPWSTR)lpSubKey);
+      InitializeObjectAttributes (&ObjectAttributes,
+                                 &SubKeyString,
+                                 OBJ_CASE_INSENSITIVE,
+                                 KeyHandle,
+                                 NULL);
+      Status = NtOpenKey (&RealKey,
+                         KEY_SET_VALUE,
+                         &ObjectAttributes);
+      if (!NT_SUCCESS(Status))
+       {
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
+       }
+      CloseRealKey = TRUE;
+    }
+  else
+    {
+      RealKey = hKey;
+      CloseRealKey = FALSE;
+    }
+
+  ErrorCode = RegSetValueExW (RealKey,
+                             NULL,
+                             0,
+                             dwType,
+                             (LPBYTE)lpData,
+                             cbData);
+  if (CloseRealKey == TRUE)
+    {
+      NtClose (RealKey);
+    }
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
@@ -2343,24 +4069,23 @@ RegUnLoadKeyA (HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegUnLoadKeyW (HKEY  hKey,
+RegUnLoadKeyW (HKEY hKey,
               LPCWSTR lpSubKey)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING KeyName;
   HANDLE KeyHandle;
-  DWORD ErrorCode;
   NTSTATUS Status;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
-    return ERROR_INVALID_HANDLE;
+    {
+      return ERROR_INVALID_HANDLE;
+    }
 
   Status = MapDefaultKey (&KeyHandle, hKey);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
+      return RtlNtStatusToDosError (Status);
     }
 
   RtlInitUnicodeString (&KeyName,
@@ -2373,15 +4098,54 @@ RegUnLoadKeyW (HKEY  hKey,
                              NULL);
 
   Status = NtUnloadKey (&ObjectAttributes);
+  
+  CloseDefaultKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
+      return RtlNtStatusToDosError (Status);
     }
 
   return ERROR_SUCCESS;
 }
 
+
+/************************************************************************
+ *  RegLoadMUIStringW
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegLoadMUIStringW(IN HKEY hKey,
+                  IN LPCWSTR pszValue  OPTIONAL,
+                  OUT LPWSTR pszOutBuf,
+                  IN ULONG cbOutBuf,
+                  IN ULONG Reserved,
+                  IN LPCWSTR pszDirectory  OPTIONAL)
+{
+    DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
+            hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/************************************************************************
+ *  RegLoadMUIStringA
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegLoadMUIStringA(IN HKEY hKey,
+                  IN LPCSTR pszValue  OPTIONAL,
+                  OUT LPSTR pszOutBuf,
+                  IN ULONG cbOutBuf,
+                  IN ULONG Reserved,
+                  IN LPCSTR pszDirectory  OPTIONAL)
+{
+    DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
+            hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* EOF */