- Fix a typo in RegGetKeySecurity().
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
index c1d8d23..6712214 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: reg.c,v 1.26 2003/07/12 00:03:42 ekohl Exp $
+/* $Id: reg.c,v 1.56 2004/09/13 11:41:26 ekohl Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
 
 /* 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>
 
-
-/* GLOBALS ******************************************************************/
+/* DEFINES ******************************************************************/
 
 #define MAX_DEFAULT_HANDLES   6
+#define REG_MAX_NAME_SIZE     256
+#define REG_MAX_DATA_SIZE     2048
+
+/* GLOBALS ******************************************************************/
 
 static CRITICAL_SECTION HandleTableCS;
 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
-
+static HANDLE ProcessHeap;
 
 /* PROTOTYPES ***************************************************************/
 
-static NTSTATUS MapDefaultKey (PHKEY ParentKey, HKEY Key);
+static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
 static VOID CloseDefaultKeys(VOID);
 
 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
@@ -52,6 +49,7 @@ RegInitialize (VOID)
 {
   DPRINT("RegInitialize()\n");
 
+  ProcessHeap = RtlGetProcessHeap();
   RtlZeroMemory (DefaultHandleTable,
                 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
   RtlInitializeCriticalSection (&HandleTableCS);
@@ -76,7 +74,7 @@ RegCleanup (VOID)
 
 
 static NTSTATUS
-MapDefaultKey (PHKEY RealKey,
+MapDefaultKey (PHANDLE RealKey,
               HKEY Key)
 {
   PHANDLE Handle;
@@ -87,7 +85,7 @@ MapDefaultKey (PHKEY RealKey,
 
   if (((ULONG)Key & 0xF0000000) != 0x80000000)
     {
-      *RealKey = Key;
+      *RealKey = (HANDLE)Key;
       return STATUS_SUCCESS;
     }
 
@@ -110,7 +108,7 @@ MapDefaultKey (PHKEY RealKey,
            break;
 
          case 1: /* HKEY_CURRENT_USER */
-           Status = RtlOpenCurrentUser (KEY_ALL_ACCESS,
+           Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
                                         Handle);
            break;
 
@@ -143,7 +141,7 @@ MapDefaultKey (PHKEY RealKey,
 
   if (NT_SUCCESS(Status))
     {
-      *RealKey = (HKEY)*Handle;
+      *RealKey = *Handle;
     }
 
    return Status;
@@ -172,7 +170,7 @@ static NTSTATUS
 OpenClassesRootKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\Software\\CLASSES");
+  UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\Machine\\Software\\CLASSES");
 
   DPRINT("OpenClassesRootKey()\n");
 
@@ -182,7 +180,7 @@ OpenClassesRootKey (PHANDLE KeyHandle)
                              NULL,
                              NULL);
   return NtOpenKey (KeyHandle,
-                   KEY_ALL_ACCESS,
+                   MAXIMUM_ALLOWED,
                    &Attributes);
 }
 
@@ -191,7 +189,8 @@ static NTSTATUS
 OpenLocalMachineKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine");
+  UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\Machine");
+  NTSTATUS Status;
 
   DPRINT("OpenLocalMachineKey()\n");
 
@@ -200,9 +199,12 @@ OpenLocalMachineKey (PHANDLE KeyHandle)
                              OBJ_CASE_INSENSITIVE,
                              NULL,
                              NULL);
-  return NtOpenKey (KeyHandle,
-                   KEY_ALL_ACCESS,
-                   &Attributes);
+  Status = NtOpenKey (KeyHandle,
+                     MAXIMUM_ALLOWED,
+                     &Attributes);
+
+  DPRINT("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
+  return Status;
 }
 
 
@@ -210,7 +212,7 @@ static NTSTATUS
 OpenUsersKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
-  UNICODE_STRING KeyName = UNICODE_STRING_INITIALIZER(L"\\Registry\\User");
+  UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\User");
 
   DPRINT("OpenUsersKey()\n");
 
@@ -230,7 +232,7 @@ OpenCurrentConfigKey (PHANDLE KeyHandle)
 {
   OBJECT_ATTRIBUTES Attributes;
   UNICODE_STRING KeyName =
-  UNICODE_STRING_INITIALIZER(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
+  ROS_STRING_INITIALIZER(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
 
   DPRINT("OpenCurrentConfigKey()\n");
 
@@ -240,7 +242,7 @@ OpenCurrentConfigKey (PHANDLE KeyHandle)
                              NULL,
                              NULL);
   return NtOpenKey (KeyHandle,
-                   KEY_ALL_ACCESS,
+                   MAXIMUM_ALLOWED,
                    &Attributes);
 }
 
@@ -304,6 +306,115 @@ RegConnectRegistryW (LPCWSTR lpMachineName,
 }
 
 
+/************************************************************************
+ *  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);
+  DPRINT("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);
+      DPRINT("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_ALL_ACCESS,
+                           &LocalObjectAttributes,
+                           0,
+                           NULL,
+                           0,
+                           &Disposition);
+      DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
+      if (!NT_SUCCESS(Status))
+       break;
+    }
+
+  RtlFreeUnicodeString (&LocalKeyName);
+
+  return Status;
+}
+
+
 /************************************************************************
  *  RegCreateKeyExA
  *
@@ -323,11 +434,11 @@ RegCreateKeyExA (HKEY hKey,
   UNICODE_STRING SubKeyString;
   UNICODE_STRING ClassString;
   OBJECT_ATTRIBUTES Attributes;
-  HKEY ParentKey;
+  HANDLE ParentKey;
   LONG ErrorCode;
   NTSTATUS Status;
 
-  DPRINT("RegCreateKeyExW() called\n");
+  DPRINT("RegCreateKeyExA() called\n");
 
   /* get the real parent key */
   Status = MapDefaultKey (&ParentKey,
@@ -352,13 +463,12 @@ RegCreateKeyExA (HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              (HANDLE)ParentKey,
                              (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
-  Status = NtCreateKey (phkResult,
-                       samDesired,
-                       &Attributes,
-                       0,
-                       (lpClass == NULL)? NULL : &ClassString,
-                       dwOptions,
-                       (PULONG)lpdwDisposition);
+  Status = CreateNestedKey(phkResult,
+                          &Attributes,
+                           (lpClass == NULL)? NULL : &ClassString,
+                           dwOptions,
+                           samDesired,
+                           lpdwDisposition);
   RtlFreeUnicodeString (&SubKeyString);
   if (lpClass != NULL)
     {
@@ -382,20 +492,20 @@ 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;
-  HKEY ParentKey;
+  HANDLE ParentKey;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -421,13 +531,12 @@ RegCreateKeyExW(HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              (HANDLE)ParentKey,
                              (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
-  Status = NtCreateKey (phkResult,
-                       samDesired,
-                       &Attributes,
-                       0,
-                       (lpClass == NULL)? NULL : &ClassString,
-                       dwOptions,
-                       (PULONG)lpdwDisposition);
+  Status = CreateNestedKey(phkResult,
+                          &Attributes,
+                           (lpClass == NULL)? NULL : &ClassString,
+                           dwOptions,
+                           samDesired,
+                           lpdwDisposition);
   DPRINT("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
     {
@@ -495,7 +604,7 @@ RegDeleteKeyA (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyName;
-  HKEY ParentKey;
+  HANDLE ParentKey;
   HANDLE TargetKey;
   NTSTATUS Status;
   LONG ErrorCode;
@@ -552,7 +661,7 @@ RegDeleteKeyW (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyName;
-  HKEY ParentKey;
+  HANDLE ParentKey;
   HANDLE TargetKey;
   NTSTATUS Status;
   LONG ErrorCode;
@@ -606,7 +715,7 @@ RegDeleteValueA (HKEY hKey,
                 LPCSTR lpValueName)
 {
   UNICODE_STRING ValueName;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -647,7 +756,7 @@ RegDeleteValueW (HKEY hKey,
   UNICODE_STRING ValueName;
   NTSTATUS Status;
   LONG ErrorCode;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
 
   Status = MapDefaultKey (&KeyHandle,
                          hKey);
@@ -739,17 +848,24 @@ RegEnumKeyExA (HKEY hKey,
               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;
+  union
+  {
+    KEY_NODE_INFORMATION Node;
+    KEY_BASIC_INFORMATION Basic;
+  } *KeyInfo;
+
+  UNICODE_STRING StringU;
+  ANSI_STRING StringA;
+  LONG ErrorCode = ERROR_SUCCESS;
   DWORD NameLength;
-  DWORD ClassLength;
+  DWORD ClassLength = 0;
+  DWORD BufferSize;
+  DWORD ResultSize;
+  HANDLE KeyHandle;
+  NTSTATUS Status;
 
-  DPRINT("hKey 0x%x  dwIndex %d  lpName 0x%x  *lpcbName %d  lpClass 0x%x  lpcbClass %d\n",
-        hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass);
+  DPRINT("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))
     {
@@ -757,66 +873,141 @@ RegEnumKeyExA (HKEY hKey,
       return ERROR_INVALID_PARAMETER;
     }
 
-  RtlInitUnicodeString (&UnicodeStringName,
-                       NULL);
-  UnicodeStringName.Buffer = &Name[0];
-  UnicodeStringName.MaximumLength = sizeof(Name);
-  RtlInitUnicodeString (&UnicodeStringClass,
-                       NULL);
-  if (lpClass != NULL)
+  Status = MapDefaultKey(&KeyHandle,
+                        hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  if (*lpcbName > 0)
     {
-      UnicodeStringClass.Buffer = &Class[0];
-      UnicodeStringClass.MaximumLength = sizeof(Class);
-      ClassLength = *lpcbClass;
+      NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
     }
   else
     {
-      ClassLength = 0;
+      NameLength = 0;
     }
-  NameLength = *lpcbName;
 
-  ErrorCode = RegEnumKeyExW (hKey,
-                            dwIndex,
-                            UnicodeStringName.Buffer,
-                            &NameLength,
-                            lpReserved,
-                            UnicodeStringClass.Buffer,
-                            &ClassLength,
-                            lpftLastWriteTime);
-  if (ErrorCode != ERROR_SUCCESS)
+  if (lpClass)
     {
-      return ErrorCode;
+      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)
+    {
+      SetLastError (ERROR_OUTOFMEMORY);
+      return ERROR_OUTOFMEMORY;
+    }
+
+  Status = NtEnumerateKey (KeyHandle,
+                          (ULONG)dwIndex,
+                          lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
+                          KeyInfo,
+                          BufferSize,
+                          &ResultSize);
+  DPRINT("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;
+           }
+       }
 
-  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;
+      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;
+               }
+           }
+       }
+    }
 
-  DPRINT("Key Namea0 Length %d\n", UnicodeStringName.Length);
+  DPRINT("Key Namea0 Length %d\n", StringU.Length);
   DPRINT("Key Namea1 Length %d\n", NameLength);
   DPRINT("Key Namea Length %d\n", *lpcbName);
   DPRINT("Key Namea %s\n", lpName);
 
-  if (lpClass != NULL)
+  RtlFreeHeap (ProcessHeap,
+              0,
+              KeyInfo);
+
+  if (ErrorCode != ERROR_SUCCESS)
     {
-      RtlInitAnsiString (&AnsiString,
-                        NULL);
-      AnsiString.Buffer = lpClass;
-      AnsiString.MaximumLength = *lpcbClass;
-      RtlUnicodeStringToAnsiString (&AnsiString,
-                                   &UnicodeStringClass,
-                                   FALSE);
-      *lpcbClass = AnsiString.Length;
+      SetLastError(ErrorCode);
     }
 
-  return ERROR_SUCCESS;
+  return ErrorCode;
 }
 
 
@@ -835,11 +1026,18 @@ RegEnumKeyExW (HKEY hKey,
               LPDWORD lpcbClass,
               PFILETIME lpftLastWriteTime)
 {
-  PKEY_NODE_INFORMATION KeyInfo;
+  union
+  {
+    KEY_NODE_INFORMATION Node;
+    KEY_BASIC_INFORMATION Basic;
+  } *KeyInfo;
+
   ULONG BufferSize;
   ULONG ResultSize;
-  HKEY KeyHandle;
-  LONG ErrorCode;
+  ULONG NameLength;
+  ULONG ClassLength = 0;
+  HANDLE KeyHandle;
+  LONG ErrorCode = ERROR_SUCCESS;
   NTSTATUS Status;
 
   Status = MapDefaultKey(&KeyHandle,
@@ -851,13 +1049,34 @@ RegEnumKeyExW (HKEY hKey,
       return ErrorCode;
     }
 
-  BufferSize = sizeof (KEY_NODE_INFORMATION) + *lpcbName * sizeof(WCHAR);
-  if (lpClass != NULL)
+  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 += *lpcbClass;
+      BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
     }
 
-  KeyInfo = RtlAllocateHeap (RtlGetProcessHeap (),
+  KeyInfo = RtlAllocateHeap (ProcessHeap,
                             0,
                             BufferSize);
   if (KeyInfo == NULL)
@@ -866,64 +1085,80 @@ RegEnumKeyExW (HKEY hKey,
       return ERROR_OUTOFMEMORY;
     }
 
-  /* 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)
+  Status = NtEnumerateKey (KeyHandle,
+                          (ULONG)dwIndex,
+                          lpClass ? KeyNodeInformation : KeyBasicInformation,
+                          KeyInfo,
+                          BufferSize,
+                          &ResultSize);
+  DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
+  if (!NT_SUCCESS(Status))
     {
-      Status = NtEnumerateKey (KeyHandle,
-                              (ULONG)dwIndex,
-                              KeyNodeInformation,
-                              KeyInfo,
-                              BufferSize,
-                              &ResultSize);
-      DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
-      if (Status == STATUS_BUFFER_OVERFLOW)
-       {
-         BufferSize = ResultSize;
-         continue;
-       }
-      if (!NT_SUCCESS(Status))
+      ErrorCode = RtlNtStatusToDosError (Status);
+    }
+  else
+    {
+      if (lpClass == NULL)
        {
-         ErrorCode = RtlNtStatusToDosError (Status);
-         SetLastError (ErrorCode);
-         break;
+         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 ((lpClass != NULL) &&
-             (*lpcbClass != 0) &&
-             (KeyInfo->ClassLength > *lpcbClass))
+         if (KeyInfo->Node.NameLength > NameLength ||
+             KeyInfo->Node.ClassLength > ClassLength)
            {
-             ErrorCode = ERROR_MORE_DATA;
-             SetLastError (ErrorCode);
-             break;
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
            }
-         RtlMoveMemory (lpName,
-                        KeyInfo->Name,
-                        KeyInfo->NameLength);
-         *lpcbName = (DWORD)(KeyInfo->NameLength / sizeof(WCHAR));
-         lpName[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
-         if (lpClass)
+         else
            {
-             RtlMoveMemory (lpClass,
-                            (PVOID)((ULONG_PTR)KeyInfo->Name + KeyInfo->ClassOffset),
-                            KeyInfo->ClassLength);
-             *lpcbClass = (DWORD)(KeyInfo->ClassLength / sizeof(WCHAR));
+             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 (lpftLastWriteTime != NULL)
+       }
+
+      if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
+       {
+         if (lpClass == NULL)
            {
-             /* FIXME: Fill lpftLastWriteTime */
+             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;
            }
-         break;
        }
     }
 
-  RtlFreeHeap (RtlGetProcessHeap (),
+  RtlFreeHeap (ProcessHeap,
               0,
               KeyInfo);
 
+  if (ErrorCode != ERROR_SUCCESS)
+    {
+      SetLastError(ErrorCode);
+    }
+
   return ErrorCode;
 }
 
@@ -943,101 +1178,155 @@ RegEnumValueA (HKEY hKey,
               LPBYTE lpData,
               LPDWORD lpcbData)
 {
-  WCHAR ValueName[MAX_PATH+1];
-  UNICODE_STRING UnicodeString;
-  ANSI_STRING AnsiString;
+  union
+  {
+    KEY_VALUE_FULL_INFORMATION Full;
+    KEY_VALUE_BASIC_INFORMATION Basic;
+  } *ValueInfo;
+
+  ULONG NameLength;
+  ULONG BufferSize;
+  ULONG DataLength = 0;
+  ULONG ResultSize;
+  HANDLE KeyHandle;
   LONG ErrorCode;
-  DWORD ValueNameLength;
-  BYTE* lpDataBuffer = NULL;
-  DWORD cbData = 0;
-  DWORD Type;
-  ANSI_STRING AnsiDataString;
-  UNICODE_STRING UnicodeDataString;
+  NTSTATUS Status;
+  UNICODE_STRING StringU;
+  ANSI_STRING StringA;
+  BOOL IsStringType;
 
   ErrorCode = ERROR_SUCCESS;
-  if (lpData != NULL /*&& lpcbData != NULL*/)
+
+  Status = MapDefaultKey (&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
     {
-      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;
-       }
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
     }
-  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)
+
+  if (*lpcbValueName > 0)
     {
-      if (lpDataBuffer != NULL)
-       {
-         RtlFreeHeap (RtlGetProcessHeap (),
-                      0,
-                      lpDataBuffer);
-       }
+      NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+    }
+  else
+    {
+      NameLength = 0;
+    }
 
-      return ErrorCode;
+  if (lpData)
+    {
+      DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
+      BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
+    }
+  else
+    {
+      BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
     }
 
-  UnicodeString.Length = ValueNameLength * sizeof(WCHAR);
-  RtlInitAnsiString (&AnsiString,
-                    NULL);
-  AnsiString.Buffer = lpValueName;
-  AnsiString.MaximumLength = *lpcbValueName;
-  RtlUnicodeStringToAnsiString (&AnsiString,
-                               &UnicodeString,
-                               FALSE);
-  *lpcbValueName = AnsiString.Length;
-  if (lpDataBuffer != NULL)
+  ValueInfo = RtlAllocateHeap (ProcessHeap,
+                              0,
+                              BufferSize);
+  if (ValueInfo == NULL)
     {
-      /* 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;
+      SetLastError(ERROR_OUTOFMEMORY);
+      return ERROR_OUTOFMEMORY;
+    }
+
+  Status = NtEnumerateValueKey (KeyHandle,
+                               (ULONG)dwIndex,
+                               lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+                               ValueInfo,
+                               BufferSize,
+                               &ResultSize);
+
+  DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+    }
+  else
+    {
+      if (lpData)
+        {
+         IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
+                        (ValueInfo->Full.Type == REG_MULTI_SZ) ||
+                        (ValueInfo->Full.Type == REG_EXPAND_SZ);
+         if (ValueInfo->Full.NameLength > NameLength ||
+             (!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
+             ValueInfo->Full.DataLength > DataLength)
+           {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+           }
+         else
+           {
+             if (IsStringType)
+               {
+                 StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
+                 StringU.Length = ValueInfo->Full.DataLength;
+                 StringU.MaximumLength = DataLength;
+                 StringA.Buffer = (PCHAR)lpData;
+                 StringA.Length = 0;
+                 StringA.MaximumLength = *lpcbData;
+                 RtlUnicodeStringToAnsiString (&StringA,
+                                               &StringU,
+                                               FALSE);
+                 *lpcbData = StringA.Length;
+               }
+             else
+               {
+                 RtlCopyMemory (lpData,
+                                (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
+                                ValueInfo->Full.DataLength);
+                 *lpcbData = ValueInfo->Full.DataLength;
+               }
+
+             StringU.Buffer = ValueInfo->Full.Name;
+             StringU.Length = ValueInfo->Full.NameLength;
+             StringU.MaximumLength = NameLength;
+           }
        }
       else
        {
-         RtlCopyMemory (lpData,
-                        lpDataBuffer,
-                        min(*lpcbData, cbData));
-         *lpcbData = cbData;
+         if (ValueInfo->Basic.NameLength > NameLength)
+           {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+           }
+         else
+           {
+             StringU.Buffer = ValueInfo->Basic.Name;
+             StringU.Length = ValueInfo->Basic.NameLength;
+             StringU.MaximumLength = NameLength;
+           }
+       }
+
+      if (ErrorCode == ERROR_SUCCESS)
+        {
+         StringA.Buffer = (PCHAR)lpValueName;
+         StringA.Length = 0;
+         StringA.MaximumLength = *lpcbValueName;
+         RtlUnicodeStringToAnsiString (&StringA,
+                                       &StringU,
+                                       FALSE);
+         StringA.Buffer[StringA.Length] = 0;
+         *lpcbValueName = StringA.Length;
+         if (lpType)
+           {
+             *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
+           }
        }
-      RtlFreeHeap (RtlGetProcessHeap (),
-                  0,
-                  lpDataBuffer);
     }
 
-  if (lpType != NULL)
+  RtlFreeHeap (ProcessHeap,
+              0,
+              ValueInfo);
+  if (ErrorCode != ERROR_SUCCESS)
     {
-      *lpType = Type;
+      SetLastError(ErrorCode);
     }
 
-  return ERROR_SUCCESS;
+  return ErrorCode;
 }
 
 
@@ -1056,14 +1345,22 @@ RegEnumValueW (HKEY hKey,
               LPBYTE lpData,
               LPDWORD lpcbData)
 {
-  PKEY_VALUE_FULL_INFORMATION ValueInfo;
+  union
+  {
+    KEY_VALUE_FULL_INFORMATION Full;
+    KEY_VALUE_BASIC_INFORMATION Basic;
+  } *ValueInfo;
+
+  ULONG NameLength;
   ULONG BufferSize;
+  ULONG DataLength = 0;
   ULONG ResultSize;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
   ErrorCode = ERROR_SUCCESS;
+
   Status = MapDefaultKey (&KeyHandle,
                          hKey);
   if (!NT_SUCCESS(Status))
@@ -1073,79 +1370,98 @@ RegEnumValueW (HKEY hKey,
       return ErrorCode;
     }
 
-  BufferSize = sizeof (KEY_VALUE_FULL_INFORMATION) + *lpcbValueName * sizeof(WCHAR);
-  if (lpcbData)
+  if (*lpcbValueName > 0)
     {
-      BufferSize += *lpcbData;
+      NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+    }
+  else
+    {
+      NameLength = 0;
     }
 
-  /* 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 */
-  ValueInfo = RtlAllocateHeap (RtlGetProcessHeap (),
-                              0,
+  if (lpData)
+    {
+      DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
+      BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
+    }
+  else
+    {
+      BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
+    }
+  ValueInfo = RtlAllocateHeap (ProcessHeap,
+                              0,
                               BufferSize);
   if (ValueInfo == NULL)
     {
       SetLastError (ERROR_OUTOFMEMORY);
       return ERROR_OUTOFMEMORY;
     }
+  Status = NtEnumerateValueKey (KeyHandle,
+                               (ULONG)dwIndex,
+                               lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+                               ValueInfo,
+                               BufferSize,
+                               &ResultSize);
 
-  while (TRUE)
+  DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
+  if (!NT_SUCCESS(Status))
     {
-      Status = NtEnumerateValueKey (KeyHandle,
-                                   (ULONG)dwIndex,
-                                   KeyValueFullInformation,
-                                   ValueInfo,
-                                   BufferSize,
-                                   &ResultSize);
-      DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
-      if (Status == STATUS_BUFFER_OVERFLOW)
-       {
-         BufferSize = ResultSize;
-         continue;
-       }
-      if (!NT_SUCCESS(Status))
+      ErrorCode = RtlNtStatusToDosError (Status);
+    }
+  else
+    {
+      if (lpData)
        {
-         ErrorCode = RtlNtStatusToDosError (Status);
-         SetLastError (ErrorCode);
-         break;
+         if (ValueInfo->Full.DataLength > DataLength ||
+             ValueInfo->Full.NameLength > NameLength)
+           {
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
+           }
+         else
+           {
+             RtlCopyMemory (lpValueName,
+                            ValueInfo->Full.Name,
+                            ValueInfo->Full.NameLength);
+             *lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
+             lpValueName[*lpcbValueName] = 0;
+             RtlCopyMemory (lpData,
+                            (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
+                            ValueInfo->Full.DataLength);
+             *lpcbData = (DWORD)ValueInfo->Full.DataLength;
+           }
        }
       else
        {
-         if ((lpData != NULL) &&
-             (*lpcbData != 0) &&
-             (ValueInfo->DataLength > *lpcbData))
+         if (ValueInfo->Basic.NameLength > NameLength)
            {
-             ErrorCode = ERROR_MORE_DATA;
-             SetLastError (ErrorCode);
-             break;
+             ErrorCode = ERROR_BUFFER_OVERFLOW;
            }
-         RtlCopyMemory (lpValueName,
-                        ValueInfo->Name,
-                        ValueInfo->NameLength);
-         *lpcbValueName = (DWORD)(ValueInfo->NameLength / sizeof(WCHAR));
-         lpValueName[ValueInfo->NameLength / sizeof(WCHAR)] = 0;
-         if (lpType != NULL)
+         else
            {
-             *lpType = ValueInfo->Type;
+             RtlCopyMemory (lpValueName,
+                            ValueInfo->Basic.Name,
+                            ValueInfo->Basic.NameLength);
+             *lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
+             lpValueName[*lpcbValueName] = 0;
            }
-         if (lpData != NULL)
-           {
-             RtlCopyMemory (lpData,
-                            (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset),
-                            ValueInfo->DataLength);
-                           *lpcbData = (DWORD)ValueInfo->DataLength;
-           }
-         break;
+          *lpcbData = (DWORD)ValueInfo->Full.DataLength;
+       }
+
+      if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
+       {
+         *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
        }
     }
 
-  RtlFreeHeap (RtlGetProcessHeap (),
+  RtlFreeHeap (ProcessHeap,
               0,
               ValueInfo);
 
+  if (ErrorCode != ERROR_SUCCESS)
+    {
+      SetLastError (ErrorCode);
+    }
+
   return ErrorCode;
 }
 
@@ -1158,7 +1474,7 @@ RegEnumValueW (HKEY hKey,
 LONG STDCALL
 RegFlushKey(HKEY hKey)
 {
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -1191,47 +1507,48 @@ RegFlushKey(HKEY hKey)
 /************************************************************************
  *  RegGetKeySecurity
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
-RegGetKeySecurity (HKEY hKey,
-                  SECURITY_INFORMATION SecurityInformation,
-                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
-                  LPDWORD lpcbSecurityDescriptor)
+RegGetKeySecurity(HKEY hKey,
+                 SECURITY_INFORMATION SecurityInformation,
+                 PSECURITY_DESCRIPTOR pSecurityDescriptor,
+                 LPDWORD lpcbSecurityDescriptor)
 {
-#if 0
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
-  if (hKey = HKEY_PERFORMANCE_DATA)
+  if (hKey == HKEY_PERFORMANCE_DATA)
     {
+      SetLastError(ERROR_INVALID_HANDLE);
       return ERROR_INVALID_HANDLE;
     }
 
-  Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+  Status = MapDefaultKey(&KeyHandle,
+                        hKey);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
+      DPRINT("MapDefaultKey() failed (Status %lx)\n", Status);
+      ErrorCode = RtlNtStatusToDosError(Status);
+      SetLastError(ErrorCode);
       return ErrorCode;
     }
 
-  Status = NtQuerySecurityObject ()
+  Status = NtQuerySecurityObject(KeyHandle,
+                                SecurityInformation,
+                                pSecurityDescriptor,
+                                *lpcbSecurityDescriptor,
+                                lpcbSecurityDescriptor);
   if (!NT_SUCCESS(Status))
     {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
+      DPRINT("NtQuerySecurityObject() failed (Status %lx)\n", Status);
+      ErrorCode = RtlNtStatusToDosError(Status);
+      SetLastError(ErrorCode);
       return ErrorCode;
     }
 
   return ERROR_SUCCESS;
-#endif
-
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
@@ -1247,7 +1564,7 @@ RegLoadKeyA (HKEY hKey,
 {
   UNICODE_STRING FileName;
   UNICODE_STRING KeyName;
-  DWORD ErrorCode;
+  LONG ErrorCode;
 
   RtlCreateUnicodeStringFromAsciiz (&KeyName,
                                    (LPSTR)lpSubKey);
@@ -1280,11 +1597,12 @@ RegLoadKeyW (HKEY hKey,
   UNICODE_STRING FileName;
   UNICODE_STRING KeyName;
   HANDLE KeyHandle;
-  DWORD ErrorCode;
+  LONG ErrorCode;
   NTSTATUS Status;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
     {
+      SetLastError(ERROR_INVALID_HANDLE);
       return ERROR_INVALID_HANDLE;
     }
 
@@ -1391,7 +1709,6 @@ RegNotifyChangeKeyValue (HKEY hKey,
 }
 
 
-
 /************************************************************************
  *  RegOpenKeyA
  *
@@ -1404,7 +1721,7 @@ RegOpenKeyA (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -1424,8 +1741,8 @@ RegOpenKeyA (HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              KeyHandle,
                              NULL);
-  Status = NtOpenKey (phkResult,
-                     KEY_ALL_ACCESS,
+  Status = NtOpenKey ((PHANDLE)phkResult,
+                     MAXIMUM_ALLOWED,
                      &ObjectAttributes);
   RtlFreeUnicodeString (&SubKeyString);
   if (!NT_SUCCESS(Status))
@@ -1454,7 +1771,7 @@ RegOpenKeyW (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -1474,8 +1791,8 @@ RegOpenKeyW (HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              KeyHandle,
                              NULL);
-  Status = NtOpenKey (phkResult,
-                     KEY_ALL_ACCESS,
+  Status = NtOpenKey ((PHANDLE)phkResult,
+                     MAXIMUM_ALLOWED,
                      &ObjectAttributes);
   if (!NT_SUCCESS(Status))
     {
@@ -1502,7 +1819,7 @@ RegOpenKeyExA (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -1522,7 +1839,7 @@ RegOpenKeyExA (HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              KeyHandle,
                              NULL);
-  Status = NtOpenKey (phkResult,
+  Status = NtOpenKey ((PHANDLE)phkResult,
                      samDesired,
                      &ObjectAttributes);
   RtlFreeUnicodeString (&SubKeyString);
@@ -1551,7 +1868,7 @@ RegOpenKeyExW (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   LONG ErrorCode;
   NTSTATUS Status;
 
@@ -1579,7 +1896,7 @@ RegOpenKeyExW (HKEY hKey,
                              OBJ_CASE_INSENSITIVE,
                              KeyHandle,
                              NULL);
-  Status = NtOpenKey (phkResult,
+  Status = NtOpenKey ((PHANDLE)phkResult,
                      samDesired,
                      &ObjectAttributes);
   if (!NT_SUCCESS(Status))
@@ -1623,6 +1940,7 @@ RegQueryInfoKeyA (HKEY hKey,
     {
       UnicodeString.Buffer = &ClassName[0];
       UnicodeString.MaximumLength = sizeof(ClassName);
+      AnsiString.MaximumLength = *lpcbClass;
     }
 
   ErrorCode = RegQueryInfoKeyW (hKey,
@@ -1639,14 +1957,14 @@ RegQueryInfoKeyA (HKEY hKey,
                                lpftLastWriteTime);
   if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
     {
-      RtlInitAnsiString (&AnsiString,
-                        NULL);
       AnsiString.Buffer = lpClass;
-      AnsiString.MaximumLength = *lpcbClass;
+      AnsiString.Length = 0;
+      UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
       RtlUnicodeStringToAnsiString (&AnsiString,
                                    &UnicodeString,
                                    FALSE);
       *lpcbClass = AnsiString.Length;
+      lpClass[AnsiString.Length] = 0;
     }
 
   return ErrorCode;
@@ -1675,9 +1993,10 @@ RegQueryInfoKeyW (HKEY hKey,
   KEY_FULL_INFORMATION FullInfoBuffer;
   PKEY_FULL_INFORMATION FullInfo;
   ULONG FullInfoSize;
-  HKEY KeyHandle;
+  ULONG ClassLength = 0;
+  HANDLE KeyHandle;
   NTSTATUS Status;
-  LONG ErrorCode;
+  LONG ErrorCode = ERROR_SUCCESS;
   ULONG Length;
 
   if ((lpClass) && (!lpcbClass))
@@ -1697,8 +2016,17 @@ RegQueryInfoKeyW (HKEY hKey,
 
   if (lpClass != NULL)
     {
-      FullInfoSize = sizeof(KEY_FULL_INFORMATION) + *lpcbClass;
-      FullInfo = RtlAllocateHeap (RtlGetProcessHeap (),
+      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)
@@ -1706,13 +2034,14 @@ RegQueryInfoKeyW (HKEY hKey,
          SetLastError (ERROR_OUTOFMEMORY);
          return ERROR_OUTOFMEMORY;
        }
-      FullInfo->ClassLength = *lpcbClass;
+
+      FullInfo->ClassLength = ClassLength;
     }
   else
     {
       FullInfoSize = sizeof(KEY_FULL_INFORMATION);
       FullInfo = &FullInfoBuffer;
-      FullInfo->ClassLength = 1;
+      FullInfo->ClassLength = 0;
     }
   FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
 
@@ -1721,53 +2050,61 @@ RegQueryInfoKeyW (HKEY hKey,
                       FullInfo,
                       FullInfoSize,
                       &Length);
+  DPRINT("NtQueryKey() returned status 0x%X\n", Status);
   if (!NT_SUCCESS(Status))
     {
       if (lpClass != NULL)
        {
-         RtlFreeHeap (RtlGetProcessHeap (),
+         RtlFreeHeap (ProcessHeap,
                       0,
                       FullInfo);
        }
+
       ErrorCode = RtlNtStatusToDosError (Status);
       SetLastError (ErrorCode);
       return ErrorCode;
     }
 
+  DPRINT("SubKeys %d\n", FullInfo->SubKeys);
   if (lpcSubKeys != NULL)
     {
       *lpcSubKeys = FullInfo->SubKeys;
     }
 
+  DPRINT("MaxNameLen %lu\n", FullInfo->MaxNameLen);
   if (lpcbMaxSubKeyLen != NULL)
     {
-      *lpcbMaxSubKeyLen = FullInfo->MaxNameLen;
+      *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
     }
 
+  DPRINT("MaxClassLen %lu\n", FullInfo->MaxClassLen);
   if (lpcbMaxClassLen != NULL)
     {
-      *lpcbMaxClassLen = FullInfo->MaxClassLen;
+      *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
     }
 
-  if (lpcValues)
+  DPRINT("Values %lu\n", FullInfo->Values);
+  if (lpcValues != NULL)
     {
       *lpcValues = FullInfo->Values;
     }
 
-  if (lpcbMaxValueNameLen)
+  DPRINT("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
+  if (lpcbMaxValueNameLen != NULL)
     {
-      *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen;
+      *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
     }
 
-  if (lpcbMaxValueLen)
+  DPRINT("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
+  if (lpcbMaxValueLen != NULL)
     {
       *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
     }
 
-  if (lpcbSecurityDescriptor)
+  if (lpcbSecurityDescriptor != NULL)
     {
-      *lpcbSecurityDescriptor = 0;
       /* FIXME */
+      *lpcbSecurityDescriptor = 0;
     }
 
   if (lpftLastWriteTime != NULL)
@@ -1778,15 +2115,30 @@ RegQueryInfoKeyW (HKEY hKey,
 
   if (lpClass != NULL)
     {
-      wcsncpy (lpClass,
-              FullInfo->Class,
-              *lpcbClass);
-      RtlFreeHeap (RtlGetProcessHeap (),
+      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);
     }
 
-  return ERROR_SUCCESS;
+  if (ErrorCode != ERROR_SUCCESS)
+    {
+      SetLastError (ErrorCode);
+    }
+
+  return ErrorCode;
 }
 
 
@@ -1811,7 +2163,7 @@ RegQueryMultipleValuesA (HKEY hKey,
 /************************************************************************
  *  RegQueryMultipleValuesW
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
 RegQueryMultipleValuesW (HKEY hKey,
@@ -1820,9 +2172,55 @@ RegQueryMultipleValuesW (HKEY hKey,
                         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;
+
+  DPRINT ("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,
+                                       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;
 }
 
 
@@ -1845,7 +2243,8 @@ RegQueryValueExW (HKEY hKey,
   LONG ErrorCode = ERROR_SUCCESS;
   ULONG BufferSize;
   ULONG ResultSize;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
+  ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
 
   DPRINT("hKey 0x%X  lpValueName %S  lpData 0x%X  lpcbData %d\n",
         hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
@@ -1867,8 +2266,8 @@ RegQueryValueExW (HKEY hKey,
 
   RtlInitUnicodeString (&ValueName,
                        lpValueName);
-  BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + *lpcbData;
-  ValueInfo = RtlAllocateHeap (RtlGetProcessHeap (),
+  BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + MaxCopy;
+  ValueInfo = RtlAllocateHeap (ProcessHeap,
                               0,
                               BufferSize);
   if (ValueInfo == NULL)
@@ -1887,36 +2286,59 @@ RegQueryValueExW (HKEY hKey,
   if (Status == STATUS_BUFFER_TOO_SMALL)
     {
       /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
-      ErrorCode = ERROR_SUCCESS;
+      MaxCopy = 0;
+      ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
     }
   else if (!NT_SUCCESS(Status))
     {
       ErrorCode = RtlNtStatusToDosError (Status);
       SetLastError (ErrorCode);
-    }
-  else
-    {
-      if (lpType != NULL)
+      MaxCopy = 0;
+      if (lpcbData != NULL)
        {
-         *lpType = ValueInfo->Type;
+         ResultSize = sizeof(*ValueInfo) + *lpcbData;
        }
+    }
+
+  if (lpType != NULL)
+    {
+      *lpType = ValueInfo->Type;
+    }
+
+  if (NT_SUCCESS(Status) && lpData != NULL)
+    {
       RtlMoveMemory (lpData,
                     ValueInfo->Data,
-                    ValueInfo->DataLength);
-      if ((ValueInfo->Type == REG_SZ) ||
-         (ValueInfo->Type == REG_MULTI_SZ) ||
-         (ValueInfo->Type == REG_EXPAND_SZ))
+                    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;
        }
-    }
-  DPRINT("Type %d  Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
 
-  if (NULL != lpcbData)
+      if (lpcbData != NULL)
+       {
+         *lpcbData = (ResultSize - sizeof(*ValueInfo));
+         DPRINT("(string) Returning Size: %lu\n", *lpcbData);
+       }
+    }
+  else
     {
-      *lpcbData = (DWORD)ValueInfo->DataLength;
+      if (lpcbData != NULL)
+       {
+         *lpcbData = ResultSize - sizeof(*ValueInfo);
+         DPRINT("(other) Returning Size: %lu\n", *lpcbData);
+       }
     }
-  RtlFreeHeap (RtlGetProcessHeap (),
+
+  DPRINT("Type %d  Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
+
+  RtlFreeHeap (ProcessHeap,
               0,
               ValueInfo);
 
@@ -1927,81 +2349,105 @@ RegQueryValueExW (HKEY hKey,
 /************************************************************************
  *  RegQueryValueExA
  *
- * @unimplemented
+ * @implemented
  */
-LONG
-STDCALL
-RegQueryValueExA(
-  HKEY  hKey,
-  LPCSTR  lpValueName,
-  LPDWORD lpReserved,
-  LPDWORD lpType,
-  LPBYTE  lpData,
-  LPDWORD lpcbData)
+LONG STDCALL
+RegQueryValueExA (HKEY hKey,
+                 LPCSTR lpValueName,
+                 LPDWORD lpReserved,
+                 LPDWORD lpType,
+                 LPBYTE  lpData,
+                 LPDWORD lpcbData)
 {
-  WCHAR ValueNameBuffer[MAX_PATH+1];
   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 */
-
-  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)
+    {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  if (lpData)
+    {
+      ValueData.Length = *lpcbData * sizeof(WCHAR);
+      ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
+      ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
+                                         0,
+                                         ValueData.MaximumLength);
+      if (!ValueData.Buffer)
+       {
+         SetLastError(ERROR_OUTOFMEMORY);
+         return ERROR_OUTOFMEMORY;
+       }
+    }
+  else
+    {
+      ValueData.Buffer = NULL;
+      ValueData.Length = 0;
+      ValueData.MaximumLength = 0;
+    }
+
+  RtlCreateUnicodeStringFromAsciiz (&ValueName,
+                                   (LPSTR)lpValueName);
+
+  if (NULL != lpcbData)
+    {
+      Length = *lpcbData * sizeof(WCHAR);
+    }
+  ErrorCode = RegQueryValueExW (hKey,
+                               ValueName.Buffer,
+                               lpReserved,
+                               &Type,
+                               (LPBYTE)ValueData.Buffer,
+                               NULL == lpcbData ? NULL : &Length);
+  DPRINT("ErrorCode %lu\n", ErrorCode);
+
+  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 = lpData;
+             AnsiString.MaximumLength = *lpcbData;
+             ValueData.Length = Length;
+             ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
+             RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
+           }
+         Length = Length / sizeof(WCHAR);
+       }
+      else if (lpcbData != NULL)
+       {
+         Length = min(*lpcbData, Length);
+         if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
+           {
+             RtlMoveMemory(lpData, ValueData.Buffer, Length);
+           }
+       }
+
+      if (lpcbData != NULL)
+       {
+         *lpcbData = Length;
+       }
+    }
+
+  if (ValueData.Buffer != NULL)
+    {
+      RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
     }
-  }
-  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 (lpcbData) {
-    *lpcbData = ResultSize;
-  }
-  if (ValueData.Buffer) {
-    RtlFreeHeap(RtlGetProcessHeap(), 0, ValueData.Buffer);
-  }
+
   return ErrorCode;
 }
 
@@ -2051,7 +2497,7 @@ RegQueryValueA (HKEY hKey,
     {
       ValueSize = *lpcbValue * sizeof(WCHAR);
       Value.MaximumLength = ValueSize;
-      Value.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
+      Value.Buffer = RtlAllocateHeap (ProcessHeap,
                                      0,
                                      ValueSize);
       if (Value.Buffer == NULL)
@@ -2084,7 +2530,7 @@ RegQueryValueA (HKEY hKey,
   *lpcbValue = ValueSize;
   if (Value.Buffer != NULL)
     {
-      RtlFreeHeap (RtlGetProcessHeap (),
+      RtlFreeHeap (ProcessHeap,
                   0,
                   Value.Buffer);
     }
@@ -2106,7 +2552,7 @@ RegQueryValueW (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   HANDLE RealKey;
   LONG ErrorCode;
   BOOL CloseRealKey;
@@ -2166,7 +2612,7 @@ RegQueryValueW (HKEY hKey,
 /************************************************************************
  *  RegReplaceKeyA
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
 RegReplaceKeyA (HKEY hKey,
@@ -2174,9 +2620,28 @@ RegReplaceKeyA (HKEY hKey,
                LPCSTR lpNewFile,
                LPCSTR lpOldFile)
 {
-  UNIMPLEMENTED;
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+  UNICODE_STRING SubKey;
+  UNICODE_STRING NewFile;
+  UNICODE_STRING OldFile;
+  LONG ErrorCode;
+
+  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;
 }
 
 
@@ -2191,53 +2656,234 @@ RegReplaceKeyW (HKEY hKey,
                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;
+  LONG ErrorCode;
+  NTSTATUS Status;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  /* 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,
+                         KEY_ALL_ACCESS,
+                         &KeyObjectAttributes);
+      if (!NT_SUCCESS(Status))
+       {
+         ErrorCode = RtlNtStatusToDosError (Status);
+         SetLastError (ErrorCode);
+         return ErrorCode;
+       }
+      CloseRealKey = TRUE;
+    }
+  else
+    {
+      RealKeyHandle = KeyHandle;
+      CloseRealKey = FALSE;
+    }
+
+  /* Convert new file name */
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
+                                    &NewFileName,
+                                    NULL,
+                                    NULL))
+    {
+      if (CloseRealKey)
+       {
+         NtClose (RealKeyHandle);
+       }
+      SetLastError (ERROR_INVALID_PARAMETER);
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  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);
+       }
+      SetLastError (ERROR_INVALID_PARAMETER);
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  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))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  return ERROR_SUCCESS;
 }
 
 
 /************************************************************************
  *  RegRestoreKeyA
  *
- * @unimplemented
+ * @implemented
  */
 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)
 {
-  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;
+  LONG ErrorCode;
+  NTSTATUS Status;
+
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      return ERROR_INVALID_HANDLE;
+    }
+
+  Status = MapDefaultKey (&KeyHandle,
+                         hKey);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      SetLastError (ERROR_INVALID_PARAMETER);
+      return ERROR_INVALID_PARAMETER;
+    }
+
+  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))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  Status = NtRestoreKey (KeyHandle,
+                        FileHandle,
+                        (ULONG)dwFlags);
+  NtClose (FileHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      ErrorCode = RtlNtStatusToDosError (Status);
+      SetLastError (ErrorCode);
+      return ErrorCode;
+    }
+
+  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;
@@ -2265,10 +2911,10 @@ RegSaveKeyW (HKEY hKey,
 {
   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;
 
@@ -2281,8 +2927,8 @@ RegSaveKeyW (HKEY hKey,
       return ErrorCode;
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
-                                    &NtName,
+  if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
+                                    &FileName,
                                     NULL,
                                     NULL))
     {
@@ -2296,7 +2942,7 @@ RegSaveKeyW (HKEY hKey,
     }
 
   InitializeObjectAttributes (&ObjectAttributes,
-                             &NtName,
+                             &FileName,
                              OBJ_CASE_INSENSITIVE,
                              NULL,
                              SecurityDescriptor);
@@ -2311,7 +2957,7 @@ 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);
@@ -2343,12 +2989,15 @@ RegSetKeySecurity (HKEY hKey,
                   SECURITY_INFORMATION SecurityInformation,
                   PSECURITY_DESCRIPTOR pSecurityDescriptor)
 {
-  HKEY KeyHandle;
-  NTSTATUS Status;
+  HANDLE KeyHandle;
   LONG ErrorCode;
+  NTSTATUS Status;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
-    return ERROR_INVALID_HANDLE;
+    {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return ERROR_INVALID_HANDLE;
+    }
 
   Status = MapDefaultKey (&KeyHandle,
                          hKey);
@@ -2404,7 +3053,7 @@ RegSetValueExA (HKEY hKey,
       strlen(lpValueName) != 0)
     {
       RtlCreateUnicodeStringFromAsciiz (&ValueName,
-                                       (LPSTR)lpValueName);
+                                       (PSTR)lpValueName);
       pValueName = (LPWSTR)ValueName.Buffer;
     }
   else
@@ -2418,7 +3067,7 @@ RegSetValueExA (HKEY hKey,
     {
       RtlInitAnsiString (&AnsiString,
                         NULL);
-      AnsiString.Buffer = (LPSTR)lpData;
+      AnsiString.Buffer = (PSTR)lpData;
       AnsiString.Length = cbData;
       AnsiString.MaximumLength = cbData;
       RtlAnsiStringToUnicodeString (&Data,
@@ -2443,14 +3092,14 @@ RegSetValueExA (HKEY hKey,
                              DataSize);
   if (pValueName != NULL)
     {
-      RtlFreeHeap (RtlGetProcessHeap (),
+      RtlFreeHeap (ProcessHeap,
                   0,
                   ValueName.Buffer);
     }
 
   if (Data.Buffer != NULL)
     {
-      RtlFreeHeap (RtlGetProcessHeap (),
+      RtlFreeHeap (ProcessHeap,
                   0,
                   Data.Buffer);
     }
@@ -2474,7 +3123,7 @@ RegSetValueExW (HKEY hKey,
 {
   UNICODE_STRING ValueName;
   PUNICODE_STRING pValueName;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   NTSTATUS Status;
   LONG ErrorCode;
 
@@ -2491,12 +3140,12 @@ RegSetValueExW (HKEY hKey,
     {
       RtlInitUnicodeString (&ValueName,
                            lpValueName);
-      pValueName = &ValueName;
     }
   else
     {
-      pValueName = NULL;
+      RtlInitUnicodeString (&ValueName, L"");
     }
+  pValueName = &ValueName;
 
   Status = NtSetValueKey (KeyHandle,
                          pValueName,
@@ -2552,7 +3201,7 @@ RegSetValueA (HKEY hKey,
 
   DataSize = cbData * sizeof(WCHAR);
   Data.MaximumLength = DataSize;
-  Data.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
+  Data.Buffer = RtlAllocateHeap (ProcessHeap,
                                 0,
                                 DataSize);
   if (Data.Buffer == NULL)
@@ -2566,7 +3215,8 @@ RegSetValueA (HKEY hKey,
                            dwType,
                            Data.Buffer,
                            DataSize);
-  RtlFreeHeap (RtlGetProcessHeap (),
+
+  RtlFreeHeap (ProcessHeap,
               0,
               Data.Buffer);
 
@@ -2588,7 +3238,7 @@ RegSetValueW (HKEY hKey,
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING SubKeyString;
-  HKEY KeyHandle;
+  HANDLE KeyHandle;
   HANDLE RealKey;
   LONG ErrorCode;
   BOOL CloseRealKey;
@@ -2674,7 +3324,7 @@ RegUnLoadKeyA (HKEY hKey,
  * @implemented
  */
 LONG STDCALL
-RegUnLoadKeyW (HKEY  hKey,
+RegUnLoadKeyW (HKEY hKey,
               LPCWSTR lpSubKey)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
@@ -2684,7 +3334,10 @@ RegUnLoadKeyW (HKEY  hKey,
   NTSTATUS Status;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
-    return ERROR_INVALID_HANDLE;
+    {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return ERROR_INVALID_HANDLE;
+    }
 
   Status = MapDefaultKey (&KeyHandle, hKey);
   if (!NT_SUCCESS(Status))