- don't close handles of keys in RegDeleteTree() that were deleted
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
index a0b04f5..e0a0b82 100644 (file)
 static RTL_CRITICAL_SECTION HandleTableCS;
 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
 static HANDLE ProcessHeap;
+static BOOLEAN DefaultHandlesDisabled = FALSE;
 
 /* PROTOTYPES ***************************************************************/
 
 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);
@@ -83,18 +88,19 @@ RegCleanup (VOID)
 
 
 static NTSTATUS
-MapDefaultKey (PHANDLE RealKey,
-              HKEY Key)
+MapDefaultKey (OUT PHANDLE RealKey,
+               IN HKEY Key)
 {
   PHANDLE Handle;
   ULONG Index;
+  BOOLEAN DoOpen;
   NTSTATUS Status = STATUS_SUCCESS;
 
   TRACE("MapDefaultKey (Key %x)\n", Key);
 
   if (((ULONG)Key & 0xF0000000) != 0x80000000)
     {
-      *RealKey = (HANDLE)Key;
+      *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
       return STATUS_SUCCESS;
     }
 
@@ -106,8 +112,19 @@ MapDefaultKey (PHANDLE RealKey,
     }
 
   RtlEnterCriticalSection (&HandleTableCS);
-  Handle = &DefaultHandleTable[Index];
-  if (*Handle == NULL)
+  
+  if (!DefaultHandlesDisabled)
+    {
+      Handle = &DefaultHandleTable[Index];
+      DoOpen = (*Handle == NULL);
+    }
+  else
+    {
+      Handle = RealKey;
+      DoOpen = TRUE;
+    }
+  
+  if (DoOpen)
     {
       /* create/open the default handle */
       switch (Index)
@@ -144,14 +161,19 @@ MapDefaultKey (PHANDLE RealKey,
          default:
            WARN("MapDefaultHandle() no handle creator\n");
            Status = STATUS_INVALID_PARAMETER;
+           break;
        }
     }
-  RtlLeaveCriticalSection (&HandleTableCS);
 
-  if (NT_SUCCESS(Status))
-    {
-      *RealKey = *Handle;
-    }
+   if (NT_SUCCESS(Status))
+     {
+       if (!DefaultHandlesDisabled)
+          *RealKey = *Handle;
+       else
+          *(PULONG_PTR)Handle |= 0x1;
+     }
+  
+   RtlLeaveCriticalSection (&HandleTableCS);
 
    return Status;
 }
@@ -256,6 +278,21 @@ OpenCurrentConfigKey (PHANDLE KeyHandle)
 }
 
 
+/************************************************************************
+ *  RegDisablePredefinedCacheEx
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegDisablePredefinedCacheEx(VOID)
+{
+    RtlEnterCriticalSection (&HandleTableCS);
+    DefaultHandlesDisabled = TRUE;
+    RtlLeaveCriticalSection (&HandleTableCS);
+    return ERROR_SUCCESS;
+}
+
+
 /************************************************************************
  *  RegCloseKey
  *
@@ -283,17 +320,148 @@ RegCloseKey (HKEY hKey)
 
 
 /************************************************************************
- *  RegConnectRegistryA
+ *  RegCopyTreeW
  *
  * @unimplemented
  */
 LONG STDCALL
-RegConnectRegistryA (LPCSTR lpMachineName,
-                    HKEY hKey,
-                    PHKEY phkResult)
+RegCopyTreeW(IN HKEY hKeySrc,
+             IN LPCWSTR lpSubKey  OPTIONAL,
+             IN HKEY hKeyDest)
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return ERROR_CALL_NOT_IMPLEMENTED;
+    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;
+}
+
+
+/************************************************************************
+ *  RegConnectRegistryA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegConnectRegistryA (IN LPCSTR lpMachineName,
+                     IN HKEY hKey,
+                     OUT PHKEY phkResult)
+{
+    UNICODE_STRING MachineName;
+    LONG Ret;
+    
+    if (lpMachineName != NULL)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&MachineName,
+                                              (LPSTR)lpMachineName))
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+    else
+        RtlInitUnicodeString(&MachineName,
+                             NULL);
+
+    Ret = RegConnectRegistryW(MachineName.Buffer,
+                              hKey,
+                              phkResult);
+
+    RtlFreeUnicodeString(&MachineName);
+    
+    return Ret;
 }
 
 
@@ -447,7 +615,7 @@ RegCreateKeyExA (HKEY hKey,
 
   /* get the real parent key */
   Status = MapDefaultKey (&ParentKey,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -479,6 +647,8 @@ RegCreateKeyExA (HKEY hKey,
       RtlFreeUnicodeString (&ClassString);
     }
 
+  CloseDefaultKey(ParentKey);
+
   TRACE("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
     {
@@ -515,7 +685,7 @@ RegCreateKeyExW (HKEY hKey,
 
   /* get the real parent key */
   Status = MapDefaultKey (&ParentKey,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError(Status);
@@ -537,6 +707,9 @@ RegCreateKeyExW (HKEY hKey,
                            dwOptions,
                            samDesired,
                            lpdwDisposition);
+
+  CloseDefaultKey(ParentKey);
+
   TRACE("Status %x\n", Status);
   if (!NT_SUCCESS(Status))
     {
@@ -607,7 +780,7 @@ RegDeleteKeyA (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey (&ParentKey,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -627,11 +800,15 @@ RegDeleteKeyA (HKEY hKey,
   RtlFreeUnicodeString (&SubKeyName);
   if (!NT_SUCCESS(Status))
     {
-      return RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
   Status = NtDeleteKey (TargetKey);
   NtClose (TargetKey);
+  
+Cleanup:
+  CloseDefaultKey(ParentKey);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError(Status);
@@ -657,7 +834,7 @@ RegDeleteKeyW (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey (&ParentKey,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -675,11 +852,15 @@ RegDeleteKeyW (HKEY hKey,
                      &ObjectAttributes);
   if (!NT_SUCCESS(Status))
     {
-      return RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
   Status = NtDeleteKey (TargetKey);
   NtClose (TargetKey);
+  
+Cleanup:
+  CloseDefaultKey(ParentKey);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -700,7 +881,7 @@ RegDeleteKeyValueW(IN HKEY hKey,
                    IN LPCWSTR lpValueName  OPTIONAL)
 {
     UNICODE_STRING ValueName;
-    HANDLE KeyHandle, SubKeyHandle = NULL;
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
     NTSTATUS Status;
 
     Status = MapDefaultKey(&KeyHandle,
@@ -729,20 +910,27 @@ RegDeleteKeyValueW(IN HKEY hKey,
                            &ObjectAttributes);
         if (!NT_SUCCESS(Status))
         {
-            return RtlNtStatusToDosError(Status);
+            goto Cleanup;
         }
+        
+        CurKey = SubKeyHandle;
     }
+    else
+        CurKey = KeyHandle;
 
     RtlInitUnicodeString(&ValueName,
                          (LPWSTR)lpValueName);
 
-    Status = NtDeleteValueKey((SubKeyHandle != NULL) ? SubKeyHandle : KeyHandle,
+    Status = NtDeleteValueKey(CurKey,
                               &ValueName);
 
     if (SubKeyHandle != NULL)
     {
         NtClose(SubKeyHandle);
     }
+    
+Cleanup:
+    CloseDefaultKey(KeyHandle);
 
     if (!NT_SUCCESS(Status))
     {
@@ -802,6 +990,439 @@ RegDeleteKeyValueA(IN HKEY hKey,
 }
 
 
+static NTSTATUS
+RegpDeleteTree(IN HKEY hKey,
+               OUT PBOOLEAN KeysDeleted)
+{
+    typedef struct
+    {
+        LIST_ENTRY ListEntry;
+        HANDLE KeyHandle;
+    } REGP_DEL_KEYS, *PREG_DEL_KEYS;
+
+    LIST_ENTRY delQueueHead;
+    PREG_DEL_KEYS delKeys, newDelKeys;
+    HANDLE ProcessHeap;
+    ULONG BufferSize;
+    PKEY_BASIC_INFORMATION BasicInfo;
+    PREG_DEL_KEYS KeyDelRoot;
+    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status2 = STATUS_SUCCESS;
+    
+    *KeysDeleted = FALSE;
+    
+    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:
+                ASSERT(newDelKeys != NULL);
+                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));
+        
+        *KeysDeleted = TRUE;
+    }
+    else
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    
+    return Status;
+}
+
+
+/************************************************************************
+ *  RegDeleteTreeW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegDeleteTreeW(IN HKEY hKey,
+               IN LPCWSTR lpSubKey  OPTIONAL)
+{
+    BOOLEAN KeysDeleted;
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+
+    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,
+                           DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                           &ObjectAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
+
+    Status = RegpDeleteTree(CurKey,
+                            &KeysDeleted);
+
+    if (!KeysDeleted)
+    {
+        /* only close handles of keys that weren't deleted! */
+        if (SubKeyHandle != NULL)
+        {
+            NtClose(SubKeyHandle);
+        }
+
+Cleanup:
+        CloseDefaultKey(KeyHandle);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+
+    return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ *  RegDeleteTreeA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegDeleteTreeA(IN HKEY hKey,
+               IN LPCSTR lpSubKey  OPTIONAL)
+{
+    UNICODE_STRING SubKeyName;
+    LONG Ret;
+
+    if (lpSubKey != NULL)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+                                              (LPSTR)lpSubKey))
+        {
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+    else
+        RtlInitUnicodeString(&SubKeyName,
+                             NULL);
+
+    Ret = RegDeleteTreeW(hKey,
+                         SubKeyName.Buffer);
+
+    RtlFreeUnicodeString(&SubKeyName);
+
+    return Ret;
+}
+
+
+/************************************************************************
+ *  RegSetKeyValueW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegSetKeyValueW(IN HKEY hKey,
+                IN LPCWSTR lpSubKey  OPTIONAL,
+                IN LPCWSTR lpValueName  OPTIONAL,
+                IN DWORD dwType,
+                IN LPCVOID lpData  OPTIONAL,
+                IN DWORD cbData)
+{
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+    LONG Ret;
+
+    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 Ret;
+}
+
+
+/************************************************************************
+ *  RegSetKeyValueA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegSetKeyValueA(IN HKEY hKey,
+                IN LPCSTR lpSubKey  OPTIONAL,
+                IN LPCSTR lpValueName  OPTIONAL,
+                IN DWORD dwType,
+                IN LPCVOID lpData  OPTIONAL,
+                IN DWORD cbData)
+{
+    HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
+    NTSTATUS Status;
+    LONG Ret;
+
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+
+    if (lpSubKey != NULL)
+    {
+        OBJECT_ATTRIBUTES ObjectAttributes;
+        UNICODE_STRING SubKeyName;
+
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+                                              (LPSTR)lpSubKey))
+        {
+            Ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto Cleanup;
+        }
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &SubKeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   KeyHandle,
+                                   NULL);
+
+        Status = NtOpenKey(&SubKeyHandle,
+                           KEY_SET_VALUE,
+                           &ObjectAttributes);
+
+        RtlFreeUnicodeString(&SubKeyName);
+
+        if (!NT_SUCCESS(Status))
+        {
+            Ret = RtlNtStatusToDosError(Status);
+            goto Cleanup;
+        }
+        
+        CurKey = SubKeyHandle;
+    }
+    else
+        CurKey = KeyHandle;
+
+    Ret = RegSetValueExA(CurKey,
+                         lpValueName,
+                         0,
+                         dwType,
+                         lpData,
+                         cbData);
+
+    if (SubKeyHandle != NULL)
+    {
+        NtClose(SubKeyHandle);
+    }
+    
+Cleanup:
+    CloseDefaultKey(KeyHandle);
+
+    return Ret;
+}
+
+
 /************************************************************************
  *  RegDeleteValueA
  *
@@ -816,7 +1437,7 @@ RegDeleteValueA (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -827,6 +1448,9 @@ RegDeleteValueA (HKEY hKey,
   Status = NtDeleteValueKey (KeyHandle,
                             &ValueName);
   RtlFreeUnicodeString (&ValueName);
+  
+  CloseDefaultKey(KeyHandle);
+  
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -850,7 +1474,7 @@ RegDeleteValueW (HKEY hKey,
   HANDLE KeyHandle;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -861,6 +1485,9 @@ RegDeleteValueW (HKEY hKey,
 
   Status = NtDeleteValueKey (KeyHandle,
                             &ValueName);
+
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -996,7 +1623,8 @@ RegEnumKeyExA (HKEY hKey,
        KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
        if (KeyInfo == NULL)
        {
-               return ERROR_OUTOFMEMORY;
+               ErrorCode = ERROR_OUTOFMEMORY;
+               goto Cleanup;
        }
 
        Status = NtEnumerateKey (KeyHandle,
@@ -1082,7 +1710,10 @@ RegEnumKeyExA (HKEY hKey,
                0,
                KeyInfo);
 
-       return ErrorCode;
+Cleanup:
+    CloseDefaultKey(KeyHandle);
+
+    return ErrorCode;
 }
 
 
@@ -1116,7 +1747,7 @@ RegEnumKeyExW (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey(&KeyHandle,
-                        hKey);
+                         hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -1154,7 +1785,8 @@ RegEnumKeyExW (HKEY hKey,
                             BufferSize);
   if (KeyInfo == NULL)
     {
-      return ERROR_OUTOFMEMORY;
+      ErrorCode = ERROR_OUTOFMEMORY;
+      goto Cleanup;
     }
 
   Status = NtEnumerateKey (KeyHandle,
@@ -1226,6 +1858,9 @@ RegEnumKeyExW (HKEY hKey,
               0,
               KeyInfo);
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
@@ -1273,7 +1908,10 @@ RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
         {
             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
-                return ERROR_NOT_ENOUGH_MEMORY;
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                goto done;
+            }
             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
             status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
                                           buf_ptr, total_size, &total_size );
@@ -1336,6 +1974,7 @@ RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
 
  done:
     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+    CloseDefaultKey(KeyHandle);
     return RtlNtStatusToDosError(status);
 }
 
@@ -1395,7 +2034,10 @@ RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
         {
             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
-                return ERROR_NOT_ENOUGH_MEMORY;
+            {
+                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 );
@@ -1440,6 +2082,7 @@ RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
 
  done:
     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+    CloseDefaultKey(KeyHandle);
     return RtlNtStatusToDosError(status);
 }
 
@@ -1460,13 +2103,16 @@ RegFlushKey(HKEY hKey)
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
     }
 
   Status = NtFlushKey (KeyHandle);
+  
+  CloseDefaultKey(KeyHandle);
+  
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -1496,7 +2142,7 @@ RegGetKeySecurity(HKEY hKey,
     }
 
   Status = MapDefaultKey(&KeyHandle,
-                        hKey);
+                         hKey);
   if (!NT_SUCCESS(Status))
     {
       TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
@@ -1508,6 +2154,9 @@ RegGetKeySecurity(HKEY hKey,
                                 pSecurityDescriptor,
                                 *lpcbSecurityDescriptor,
                                 lpcbSecurityDescriptor);
+
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
       WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
@@ -1564,6 +2213,7 @@ RegLoadKeyW (HKEY hKey,
   UNICODE_STRING KeyName;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
     {
@@ -1571,7 +2221,7 @@ RegLoadKeyW (HKEY hKey,
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -1582,7 +2232,8 @@ RegLoadKeyW (HKEY hKey,
                                     NULL,
                                     NULL))
     {
-      return ERROR_BAD_PATHNAME;
+      ErrorCode = ERROR_BAD_PATHNAME;
+      goto Cleanup;
     }
 
   InitializeObjectAttributes (&FileObjectAttributes,
@@ -1607,10 +2258,14 @@ RegLoadKeyW (HKEY hKey,
 
   if (!NT_SUCCESS(Status))
     {
-      return RtlNtStatusToDosError (Status);
+      ErrorCode = RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
-  return ERROR_SUCCESS;
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
 }
 
 
@@ -1629,6 +2284,7 @@ RegNotifyChangeKeyValue (HKEY hKey,
   IO_STATUS_BLOCK IoStatusBlock;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
     {
@@ -1641,7 +2297,7 @@ RegNotifyChangeKeyValue (HKEY hKey,
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -1661,10 +2317,12 @@ RegNotifyChangeKeyValue (HKEY hKey,
                              fAsynchronous);
   if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
     {
-      return RtlNtStatusToDosError (Status);
+      ErrorCode = RtlNtStatusToDosError (Status);
     }
 
-  return ERROR_SUCCESS;
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
 }
 
 
@@ -1756,6 +2414,7 @@ RegOpenKeyExA (HKEY hKey,
        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);
@@ -1777,10 +2436,12 @@ RegOpenKeyExA (HKEY hKey,
        RtlFreeUnicodeString (&SubKeyString);
        if (!NT_SUCCESS(Status))
        {
-               return RtlNtStatusToDosError (Status);
+               ErrorCode = RtlNtStatusToDosError (Status);
        }
+       
+       CloseDefaultKey(KeyHandle);
 
-       return ERROR_SUCCESS;
+       return ErrorCode;
 }
 
 
@@ -1800,6 +2461,7 @@ RegOpenKeyExW (HKEY hKey,
        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);
@@ -1825,10 +2487,12 @@ RegOpenKeyExW (HKEY hKey,
 
        if (!NT_SUCCESS(Status))
        {
-               return RtlNtStatusToDosError (Status);
+               ErrorCode = RtlNtStatusToDosError (Status);
        }
+       
+       CloseDefaultKey(KeyHandle);
 
-       return ERROR_SUCCESS;
+       return ErrorCode;
 }
 
 
@@ -1849,7 +2513,6 @@ RegOpenUserClassesRoot (IN HANDLE hToken,
   ULONG RequiredLength;
   UNICODE_STRING UserSidString, UserClassesKeyRoot;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  LONG ErrorCode;
   NTSTATUS Status;
 
   /* check parameters */
@@ -1874,8 +2537,7 @@ 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! */
-    ErrorCode = RtlNtStatusToDosError (Status);
-    return ErrorCode;
+    return RtlNtStatusToDosError (Status);
   }
 
   TokenUserData = RtlAllocateHeap(ProcessHeap,
@@ -1906,8 +2568,7 @@ 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! */
-    ErrorCode = RtlNtStatusToDosError (Status);
-    return ErrorCode;
+    return RtlNtStatusToDosError (Status);
   }
 
   /*
@@ -2096,7 +2757,8 @@ RegQueryInfoKeyW (HKEY hKey,
                                  FullInfoSize);
       if (FullInfo == NULL)
        {
-         return ERROR_OUTOFMEMORY;
+         ErrorCode = ERROR_OUTOFMEMORY;
+         goto Cleanup;
        }
 
       FullInfo->ClassLength = ClassLength;
@@ -2124,7 +2786,8 @@ RegQueryInfoKeyW (HKEY hKey,
                       FullInfo);
        }
 
-      return RtlNtStatusToDosError (Status);
+      ErrorCode = RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
   TRACE("SubKeys %d\n", FullInfo->SubKeys);
@@ -2181,7 +2844,8 @@ RegQueryInfoKeyW (HKEY hKey,
                          FullInfo);
            }
 
-         return RtlNtStatusToDosError (Status);
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
        }
     }
 
@@ -2211,6 +2875,9 @@ RegQueryInfoKeyW (HKEY hKey,
                   FullInfo);
     }
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+  
   return ErrorCode;
 }
 
@@ -2377,7 +3044,8 @@ RegQueryValueExW (HKEY hKey,
 
   if (lpData != NULL && lpcbData == NULL)
     {
-      return ERROR_INVALID_PARAMETER;
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   RtlInitUnicodeString (&ValueName,
@@ -2388,7 +3056,8 @@ RegQueryValueExW (HKEY hKey,
                               BufferSize);
   if (ValueInfo == NULL)
     {
-      return ERROR_OUTOFMEMORY;
+      ErrorCode = ERROR_OUTOFMEMORY;
+      goto Cleanup;
     }
 
   Status = NtQueryValueKey (KeyHandle,
@@ -2456,6 +3125,9 @@ RegQueryValueExW (HKEY hKey,
               0,
               ValueInfo);
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
@@ -2679,7 +3351,7 @@ RegQueryValueW (HKEY hKey,
         hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -2700,7 +3372,8 @@ RegQueryValueW (HKEY hKey,
                          &ObjectAttributes);
       if (!NT_SUCCESS(Status))
        {
-         return RtlNtStatusToDosError (Status);
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
        }
       CloseRealKey = TRUE;
     }
@@ -2721,6 +3394,9 @@ RegQueryValueW (HKEY hKey,
       NtClose (RealKey);
     }
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
@@ -2782,6 +3458,7 @@ RegReplaceKeyW (HKEY hKey,
   HANDLE RealKeyHandle;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  LONG ErrorCode = ERROR_SUCCESS;
 
   if (hKey == HKEY_PERFORMANCE_DATA)
     {
@@ -2789,7 +3466,7 @@ RegReplaceKeyW (HKEY hKey,
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -2810,7 +3487,8 @@ RegReplaceKeyW (HKEY hKey,
                          &KeyObjectAttributes);
       if (!NT_SUCCESS(Status))
        {
-         return RtlNtStatusToDosError (Status);
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
        }
       CloseRealKey = TRUE;
     }
@@ -2830,7 +3508,8 @@ RegReplaceKeyW (HKEY hKey,
        {
          NtClose (RealKeyHandle);
        }
-      return ERROR_INVALID_PARAMETER;
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   InitializeObjectAttributes (&NewObjectAttributes,
@@ -2850,7 +3529,8 @@ RegReplaceKeyW (HKEY hKey,
        {
          NtClose (RealKeyHandle);
        }
-      return ERROR_INVALID_PARAMETER;
+      ErrorCode = ERROR_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   InitializeObjectAttributes (&OldObjectAttributes,
@@ -2876,7 +3556,10 @@ RegReplaceKeyW (HKEY hKey,
       return RtlNtStatusToDosError (Status);
     }
 
-  return ERROR_SUCCESS;
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
+  return ErrorCode;
 }
 
 
@@ -2929,7 +3612,7 @@ RegRestoreKeyW (HKEY hKey,
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -2940,7 +3623,8 @@ RegRestoreKeyW (HKEY hKey,
                                     NULL,
                                     NULL))
     {
-      return ERROR_INVALID_PARAMETER;
+      Status = STATUS_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   InitializeObjectAttributes (&ObjectAttributes,
@@ -2958,13 +3642,17 @@ RegRestoreKeyW (HKEY hKey,
   RtlFreeUnicodeString (&FileName);
   if (!NT_SUCCESS(Status))
     {
-      return RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
   Status = NtRestoreKey (KeyHandle,
                         FileHandle,
                         (ULONG)dwFlags);
   NtClose (FileHandle);
+  
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3017,7 +3705,7 @@ RegSaveKeyW (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3028,7 +3716,8 @@ RegSaveKeyW (HKEY hKey,
                                     NULL,
                                     NULL))
     {
-      return ERROR_INVALID_PARAMETER;
+      Status = STATUS_INVALID_PARAMETER;
+      goto Cleanup;
     }
 
   if (lpSecurityAttributes != NULL)
@@ -3055,12 +3744,16 @@ RegSaveKeyW (HKEY hKey,
   RtlFreeUnicodeString (&FileName);
   if (!NT_SUCCESS(Status))
     {
-      return RtlNtStatusToDosError (Status);
+      goto Cleanup;
     }
 
   Status = NtSaveKey (KeyHandle,
                      FileHandle);
   NtClose (FileHandle);
+
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3089,7 +3782,7 @@ RegSetKeySecurity (HKEY hKey,
     }
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3098,6 +3791,9 @@ RegSetKeySecurity (HKEY hKey,
   Status = NtSetSecurityObject (KeyHandle,
                                SecurityInformation,
                                pSecurityDescriptor);
+
+  CloseDefaultKey(KeyHandle);
+  
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3213,7 +3909,7 @@ RegSetValueExW (HKEY hKey,
   NTSTATUS Status;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3245,6 +3941,9 @@ RegSetValueExW (HKEY hKey,
                          dwType,
                          (PVOID)lpData,
                          (ULONG)cbData);
+
+  CloseDefaultKey(KeyHandle);
+
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3325,7 +4024,7 @@ RegSetValueW (HKEY hKey,
   LONG ErrorCode;
 
   Status = MapDefaultKey (&KeyHandle,
-                         hKey);
+                          hKey);
   if (!NT_SUCCESS(Status))
     {
       return RtlNtStatusToDosError (Status);
@@ -3345,7 +4044,8 @@ RegSetValueW (HKEY hKey,
                          &ObjectAttributes);
       if (!NT_SUCCESS(Status))
        {
-         return RtlNtStatusToDosError (Status);
+         ErrorCode = RtlNtStatusToDosError (Status);
+         goto Cleanup;
        }
       CloseRealKey = TRUE;
     }
@@ -3366,6 +4066,9 @@ RegSetValueW (HKEY hKey,
       NtClose (RealKey);
     }
 
+Cleanup:
+  CloseDefaultKey(KeyHandle);
+
   return ErrorCode;
 }
 
@@ -3429,6 +4132,8 @@ RegUnLoadKeyW (HKEY hKey,
                              NULL);
 
   Status = NtUnloadKey (&ObjectAttributes);
+  
+  CloseDefaultKey(KeyHandle);
 
   if (!NT_SUCCESS(Status))
     {
@@ -3438,4 +4143,43 @@ RegUnLoadKeyW (HKEY hKey,
   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 */