[ADVAPI32]
[reactos.git] / reactos / dll / win32 / advapi32 / reg / reg.c
index bd9ae62..4d8f071 100644 (file)
@@ -18,6 +18,8 @@
 #include <ndk/cmfuncs.h>
 #include <pseh/pseh2.h>
 
+#include "reg.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 
 /* DEFINES ******************************************************************/
@@ -231,10 +233,11 @@ CloseDefaultKeys(VOID)
 
 
 static NTSTATUS
-OpenClassesRootKey(PHANDLE KeyHandle)
+OpenClassesRootKey(_Out_ PHANDLE KeyHandle)
 {
     OBJECT_ATTRIBUTES Attributes;
     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
+    NTSTATUS Status;
 
     TRACE("OpenClassesRootKey()\n");
 
@@ -243,9 +246,17 @@ OpenClassesRootKey(PHANDLE KeyHandle)
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL);
-    return NtOpenKey(KeyHandle,
-                     MAXIMUM_ALLOWED,
-                     &Attributes);
+    Status = NtOpenKey(KeyHandle,
+                       MAXIMUM_ALLOWED,
+                       &Attributes);
+
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Mark it as HKCR */
+    MakeHKCRKey((HKEY*)KeyHandle);
+
+    return Status;
 }
 
 
@@ -1013,75 +1024,58 @@ CreateNestedKey(PHKEY KeyHandle,
  * @implemented
  */
 LONG WINAPI
-RegCreateKeyExA(HKEY hKey,
-                LPCSTR lpSubKey,
-                DWORD Reserved,
-                LPSTR lpClass,
-                DWORD dwOptions,
-                REGSAM samDesired,
-                LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-                PHKEY phkResult,
-                LPDWORD lpdwDisposition)
+RegCreateKeyExA(
+    _In_ HKEY hKey,
+    _In_ LPCSTR lpSubKey,
+    _In_ DWORD Reserved,
+    _In_ LPSTR lpClass,
+    _In_ DWORD dwOptions,
+    _In_ REGSAM samDesired,
+    _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+    _Out_ PHKEY phkResult,
+    _Out_ LPDWORD lpdwDisposition)
 {
     UNICODE_STRING SubKeyString;
     UNICODE_STRING ClassString;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    HANDLE ParentKey;
-    ULONG Attributes = OBJ_CASE_INSENSITIVE;
-    NTSTATUS Status;
-
-    TRACE("RegCreateKeyExA() called\n");
+    DWORD ErrorCode;
 
-    if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
-        return ERROR_INVALID_USER_BUFFER;
+    RtlInitEmptyUnicodeString(&ClassString, NULL, 0);
+    RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
 
-    /* get the real parent key */
-    Status = MapDefaultKey(&ParentKey,
-                           hKey);
-    if (!NT_SUCCESS(Status))
+    if (lpClass)
     {
-        return RtlNtStatusToDosError(Status);
+        if (!RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
     }
 
-    TRACE("ParentKey %p\n", ParentKey);
-
-    if (lpClass != NULL)
+    if (lpSubKey)
     {
-        RtlCreateUnicodeStringFromAsciiz(&ClassString,
-                                         lpClass);
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
     }
 
-    if (dwOptions & REG_OPTION_OPEN_LINK)
-        Attributes |= OBJ_OPENLINK;
+    ErrorCode = RegCreateKeyExW(
+        hKey,
+        SubKeyString.Buffer,
+        Reserved,
+        ClassString.Buffer,
+        dwOptions,
+        samDesired,
+        lpSecurityAttributes,
+        phkResult,
+        lpdwDisposition);
 
-    RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
-                                     (LPSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyString,
-                               Attributes,
-                               (HANDLE)ParentKey,
-                               lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
-    Status = CreateNestedKey(phkResult,
-                             &ObjectAttributes,
-                             (lpClass == NULL)? NULL : &ClassString,
-                             dwOptions,
-                             samDesired,
-                             lpdwDisposition);
+Exit:
     RtlFreeUnicodeString(&SubKeyString);
-    if (lpClass != NULL)
-    {
-        RtlFreeUnicodeString(&ClassString);
-    }
+    RtlFreeUnicodeString(&ClassString);
 
-    ClosePredefKey(ParentKey);
-
-    TRACE("Status %x\n", Status);
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    return ERROR_SUCCESS;
+    return ErrorCode;
 }
 
 
@@ -1090,16 +1084,18 @@ RegCreateKeyExA(HKEY hKey,
  *
  * @implemented
  */
-LONG WINAPI
-RegCreateKeyExW(HKEY hKey,
-                LPCWSTR lpSubKey,
-                DWORD Reserved,
-                LPWSTR lpClass,
-                DWORD dwOptions,
-                REGSAM samDesired,
-                LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-                PHKEY phkResult,
-                LPDWORD lpdwDisposition)
+LONG
+WINAPI
+RegCreateKeyExW(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey,
+    _In_ DWORD Reserved,
+    _In_opt_ LPWSTR lpClass,
+    _In_ DWORD dwOptions,
+    _In_ REGSAM samDesired,
+    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+    _Out_ PHKEY phkResult,
+    _Out_opt_ LPDWORD lpdwDisposition)
 {
     UNICODE_STRING SubKeyString;
     UNICODE_STRING ClassString;
@@ -1123,6 +1119,22 @@ RegCreateKeyExW(HKEY hKey,
 
     TRACE("ParentKey %p\n", ParentKey);
 
+    if (IsHKCRKey(ParentKey))
+    {
+        LONG ErrorCode = CreateHKCRKey(
+            ParentKey,
+            lpSubKey,
+            Reserved,
+            lpClass,
+            dwOptions,
+            samDesired,
+            lpSecurityAttributes,
+            phkResult,
+            lpdwDisposition);
+        ClosePredefKey(ParentKey);
+        return ErrorCode;
+    }
+
     if (dwOptions & REG_OPTION_OPEN_LINK)
         Attributes |= OBJ_OPENLINK;
 
@@ -1203,59 +1215,13 @@ RegCreateKeyW(HKEY hKey,
  *
  * @implemented
  */
-LONG WINAPI
-RegDeleteKeyA(HKEY hKey,
-              LPCSTR lpSubKey)
+LONG
+WINAPI
+RegDeleteKeyA(
+    _In_ HKEY hKey,
+    _In_ LPCSTR lpSubKey)
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING SubKeyName;
-    HANDLE ParentKey;
-    HANDLE TargetKey;
-    NTSTATUS Status;
-
-    /* Make sure we got a subkey */
-    if (!lpSubKey)
-    {
-        /* Fail */
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    Status = MapDefaultKey(&ParentKey,
-                           hKey);
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
-                                     (LPSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               ParentKey,
-                               NULL);
-
-    Status = NtOpenKey(&TargetKey,
-                       DELETE,
-                       &ObjectAttributes);
-    RtlFreeUnicodeString(&SubKeyName);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    Status = NtDeleteKey(TargetKey);
-    NtClose (TargetKey);
-
-Cleanup:
-    ClosePredefKey(ParentKey);
-
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    return ERROR_SUCCESS;
+    return RegDeleteKeyExA(hKey, lpSubKey, 0, 0);
 }
 
 
@@ -1264,57 +1230,13 @@ Cleanup:
  *
  * @implemented
  */
-LONG WINAPI
-RegDeleteKeyW(HKEY hKey,
-              LPCWSTR lpSubKey)
+LONG
+WINAPI
+RegDeleteKeyW(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey)
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING SubKeyName;
-    HANDLE ParentKey;
-    HANDLE TargetKey;
-    NTSTATUS Status;
-
-    /* Make sure we got a subkey */
-    if (!lpSubKey)
-    {
-        /* Fail */
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    Status = MapDefaultKey(&ParentKey,
-                           hKey);
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    RtlInitUnicodeString(&SubKeyName,
-                         (LPWSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               ParentKey,
-                               NULL);
-    Status = NtOpenKey(&TargetKey,
-                       DELETE,
-                       &ObjectAttributes);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    Status = NtDeleteKey(TargetKey);
-    NtClose(TargetKey);
-
-Cleanup:
-    ClosePredefKey(ParentKey);
-
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    return ERROR_SUCCESS;
+    return RegDeleteKeyExW(hKey, lpSubKey, 0, 0);
 }
 
 
@@ -1325,66 +1247,28 @@ Cleanup:
  */
 LONG
 WINAPI
-RegDeleteKeyExA(HKEY hKey,
-                LPCSTR lpSubKey,
-                REGSAM samDesired,
-                DWORD Reserved)
+RegDeleteKeyExA(
+    _In_ HKEY hKey,
+    _In_ LPCSTR lpSubKey,
+    _In_ REGSAM samDesired,
+    _In_ DWORD Reserved)
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
+    LONG ErrorCode;
     UNICODE_STRING SubKeyName;
-    HANDLE ParentKey;
-    HANDLE TargetKey;
-    NTSTATUS Status;
-
-    /* Make sure we got a subkey */
-    if (!lpSubKey)
-    {
-        /* Fail */
-        return ERROR_INVALID_PARAMETER;
-    }
 
-    Status = MapDefaultKey(&ParentKey,
-                           hKey);
-    if (!NT_SUCCESS(Status))
+    if (lpSubKey)
     {
-        return RtlNtStatusToDosError(Status);
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
+            return ERROR_NOT_ENOUGH_MEMORY;
     }
+    else
+        RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0);
 
-    if (samDesired & KEY_WOW64_32KEY)
-        ERR("Wow64 not yet supported!\n");
-
-    if (samDesired & KEY_WOW64_64KEY)
-        ERR("Wow64 not yet supported!\n");
+    ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved);
 
-    RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
-                                     (LPSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               ParentKey,
-                               NULL);
-
-    Status = NtOpenKey(&TargetKey,
-                       DELETE,
-                       &ObjectAttributes);
     RtlFreeUnicodeString(&SubKeyName);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
 
-    Status = NtDeleteKey(TargetKey);
-    NtClose (TargetKey);
-
-Cleanup:
-    ClosePredefKey(ParentKey);
-
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
-    return ERROR_SUCCESS;
+    return ErrorCode;
 }
 
 
@@ -1395,10 +1279,11 @@ Cleanup:
  */
 LONG
 WINAPI
-RegDeleteKeyExW(HKEY hKey,
-                LPCWSTR lpSubKey,
-                REGSAM samDesired,
-                DWORD Reserved)
+RegDeleteKeyExW(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey,
+    _In_ REGSAM samDesired,
+    _In_ DWORD Reserved)
 {
     OBJECT_ATTRIBUTES ObjectAttributes;
     UNICODE_STRING SubKeyName;
@@ -1420,6 +1305,9 @@ RegDeleteKeyExW(HKEY hKey,
         return RtlNtStatusToDosError(Status);
     }
 
+    if (IsHKCRKey(ParentKey))
+        return DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
+
     if (samDesired & KEY_WOW64_32KEY)
         ERR("Wow64 not yet supported!\n");
 
@@ -3200,15 +3088,32 @@ RegLoadKeyA(HKEY hKey,
     UNICODE_STRING KeyName;
     LONG ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&KeyName,
-                                     (LPSTR)lpSubKey);
-    RtlCreateUnicodeStringFromAsciiz(&FileName,
-                                     (LPSTR)lpFile);
+    RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
+    RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
+    if (lpSubKey)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
+    }
+
+    if (lpFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
+    }
 
     ErrorCode = RegLoadKeyW(hKey,
                             KeyName.Buffer,
                             FileName.Buffer);
 
+Exit:
     RtlFreeUnicodeString(&FileName);
     RtlFreeUnicodeString(&KeyName);
 
@@ -3452,54 +3357,30 @@ RegOpenKeyW(HKEY hKey,
  * @implemented
  */
 LONG WINAPI
-RegOpenKeyExA(HKEY hKey,
-              LPCSTR lpSubKey,
-              DWORD ulOptions,
-              REGSAM samDesired,
-              PHKEY phkResult)
+RegOpenKeyExA(
+    _In_ HKEY hKey,
+    _In_ LPCSTR lpSubKey,
+    _In_ DWORD ulOptions,
+    _In_ REGSAM samDesired,
+    _Out_ PHKEY phkResult)
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
     UNICODE_STRING SubKeyString;
-    HANDLE KeyHandle;
-    NTSTATUS Status;
-    ULONG Attributes = OBJ_CASE_INSENSITIVE;
-    LONG ErrorCode = ERROR_SUCCESS;
+    LONG ErrorCode;
 
     TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
           hKey, lpSubKey, ulOptions, samDesired, phkResult);
-    if (!phkResult)
-    {
-        return ERROR_INVALID_PARAMETER;
-    }
 
-    Status = MapDefaultKey(&KeyHandle,
-                           hKey);
-    if (!NT_SUCCESS(Status))
+    if (lpSubKey)
     {
-        return RtlNtStatusToDosError(Status);
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
+            return ERROR_NOT_ENOUGH_MEMORY;
     }
+    else
+        RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
 
-    if (ulOptions & REG_OPTION_OPEN_LINK)
-        Attributes |= OBJ_OPENLINK;
+    ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
 
-    RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
-                                     (LPSTR)lpSubKey);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyString,
-                               Attributes,
-                               KeyHandle,
-                               NULL);
-
-    Status = NtOpenKey((PHANDLE)phkResult,
-                       samDesired,
-                       &ObjectAttributes);
     RtlFreeUnicodeString(&SubKeyString);
-    if (!NT_SUCCESS(Status))
-    {
-        ErrorCode = RtlNtStatusToDosError(Status);
-    }
-
-    ClosePredefKey(KeyHandle);
 
     return ErrorCode;
 }
@@ -3537,6 +3418,9 @@ RegOpenKeyExW(HKEY hKey,
         return RtlNtStatusToDosError(Status);
     }
 
+    if (IsHKCRKey(KeyHandle))
+        return OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
+
     if (ulOptions & REG_OPTION_OPEN_LINK)
         Attributes |= OBJ_OPENLINK;
 
@@ -3554,11 +3438,13 @@ RegOpenKeyExW(HKEY hKey,
     Status = NtOpenKey((PHANDLE)phkResult,
                        samDesired,
                        &ObjectAttributes);
+
     if (!NT_SUCCESS(Status))
     {
         ErrorCode = RtlNtStatusToDosError(Status);
     }
 
+
     ClosePredefKey(KeyHandle);
 
     return ErrorCode;
@@ -4118,102 +4004,89 @@ RegQueryReflectionKey(IN HKEY hBase,
  */
 LONG
 WINAPI
-RegQueryValueExA(HKEY hkeyorg,
-                 LPCSTR name,
-                 LPDWORD reserved,
-                 LPDWORD type,
-                 LPBYTE data,
-                 LPDWORD count)
+RegQueryValueExA(
+    _In_ HKEY hkeyorg,
+    _In_ LPCSTR name,
+    _In_ LPDWORD reserved,
+    _Out_opt_ LPDWORD type,
+    _Out_opt_ LPBYTE data,
+    _Inout_opt_ LPDWORD count)
 {
-    HANDLE hkey;
-    NTSTATUS status;
-    ANSI_STRING nameA;
     UNICODE_STRING nameW;
-    DWORD total_size, datalen = 0;
-    char buffer[256], *buf_ptr = buffer;
-    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
-    static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
+    DWORD DataLength;
+    DWORD ErrorCode;
+    DWORD BufferSize = 0;
+    WCHAR* Buffer;
+    CHAR* DataStr = (CHAR*)data;
+    DWORD LocalType;
 
-    TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
-          hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
+    /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
+    if ((data && !count) || reserved)
+        return ERROR_INVALID_PARAMETER;
 
-    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
-    status = MapDefaultKey(&hkey, hkeyorg);
-    if (!NT_SUCCESS(status))
+    if (name)
     {
-        return RtlNtStatusToDosError(status);
+        if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
+            return ERROR_NOT_ENOUGH_MEMORY;
     }
+    else
+        RtlInitEmptyUnicodeString(&nameW, NULL, 0);
 
-    if (count) datalen = *count;
-    if (!data && count) *count = 0;
+    ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
+    if (ErrorCode != ERROR_SUCCESS)
+    {
+        if (!data)
+            *count = 0;
+        RtlFreeUnicodeString(&nameW);
+        return ErrorCode;
+    }
 
-    RtlInitAnsiString( &nameA, name );
-    if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
+    /* See if we can directly handle the call without caring for conversion */
+    if (!is_string(LocalType) || !count)
     {
-        ClosePredefKey(hkey);
-        return RtlNtStatusToDosError(status);
+        ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
+        RtlFreeUnicodeString(&nameW);
+        return ErrorCode;
     }
 
-    status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
-                              buffer, sizeof(buffer), &total_size );
-    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+    /* Allocate a unicode string to get the data */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
+    if (!Buffer)
+    {
+        RtlFreeUnicodeString(&nameW);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
 
-    /* we need to fetch the contents for a string type even if not requested,
-     * because we need to compute the length of the ASCII string. */
-    if (data || is_string(info->Type))
+    ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize);
+    if (ErrorCode != ERROR_SUCCESS)
     {
-        /* retry with a dynamically allocated buffer */
-        while (status == STATUS_BUFFER_OVERFLOW)
-        {
-            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
-            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
-            {
-                status = STATUS_NO_MEMORY;
-                goto done;
-            }
-            info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
-            status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
-                                      buf_ptr, total_size, &total_size );
-        }
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+        RtlFreeUnicodeString(&nameW);
+        return ErrorCode;
+    }
 
-        if (status) goto done;
+    /* We don't need this anymore */
+    RtlFreeUnicodeString(&nameW);
 
-        if (is_string(info->Type))
-        {
-            DWORD len;
+    DataLength = *count;
+    RtlUnicodeToMultiByteSize(count, Buffer, BufferSize);
 
-            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
-                                       total_size - info_size );
-            if (data && len)
-            {
-                if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
-                else
-                {
-                    RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
-                                            total_size - info_size );
-                    /* if the type is REG_SZ and data is not 0-terminated
-                     * and there is enough space in the buffer NT appends a \0 */
-                    if (len < datalen && data[len-1]) data[len] = 0;
-                }
-            }
-            total_size = len + info_size;
-        }
-        else if (data)
-        {
-            if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
-            else memcpy( data, buf_ptr + info_size, total_size - info_size );
-        }
+    if ((!data) || (DataLength < *count))
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+        return  data ? ERROR_MORE_DATA : ERROR_SUCCESS;
     }
-    else status = STATUS_SUCCESS;
 
-    if (type) *type = info->Type;
-    if (count) *count = total_size - info_size;
+    /* We can finally do the conversion */
+    RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize);
 
- done:
-    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
-    RtlFreeUnicodeString( &nameW );
-    ClosePredefKey(hkey);
-    return RtlNtStatusToDosError(status);
+    /* NULL-terminate if there is enough room */
+    if ((DataLength > *count) && (DataStr[*count - 1] != '\0'))
+        DataStr[*count] = '\0';
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+
+    return ERROR_SUCCESS;
 }
 
 
@@ -4224,12 +4097,13 @@ RegQueryValueExA(HKEY hkeyorg,
  */
 LONG
 WINAPI
-RegQueryValueExW(HKEY hkeyorg,
-                 LPCWSTR name,
-                 LPDWORD reserved,
-                 LPDWORD type,
-                 LPBYTE data,
-                 LPDWORD count)
+RegQueryValueExW(
+    _In_ HKEY hkeyorg,
+    _In_ LPCWSTR name,
+    _In_ LPDWORD reserved,
+    _In_ LPDWORD type,
+    _In_ LPBYTE data,
+    _In_ LPDWORD count)
 {
     HANDLE hkey;
     NTSTATUS status;
@@ -4251,6 +4125,13 @@ RegQueryValueExW(HKEY hkeyorg,
         return RtlNtStatusToDosError(status);
     }
 
+    if (IsHKCRKey(hkey))
+    {
+        LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count);
+        ClosePredefKey(hkey);
+        return ErrorCode;
+    }
+
     RtlInitUnicodeString( &name_str, name );
 
     if (data) total_size = min( sizeof(buffer), *count + info_size );
@@ -4397,18 +4278,43 @@ RegReplaceKeyA(HKEY hKey,
     UNICODE_STRING OldFile;
     LONG ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&SubKey,
-                                     (PCSZ)lpSubKey);
-    RtlCreateUnicodeStringFromAsciiz(&OldFile,
-                                     (PCSZ)lpOldFile);
-    RtlCreateUnicodeStringFromAsciiz(&NewFile,
-                                     (PCSZ)lpNewFile);
+    RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
+    RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
+    RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
+
+    if (lpSubKey)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
+    }
+
+    if (lpOldFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
+    }
+
+    if (lpNewFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
+        {
+            ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            goto Exit;
+        }
+    }
 
     ErrorCode = RegReplaceKeyW(hKey,
                                SubKey.Buffer,
                                NewFile.Buffer,
                                OldFile.Buffer);
 
+Exit:
     RtlFreeUnicodeString(&OldFile);
     RtlFreeUnicodeString(&NewFile);
     RtlFreeUnicodeString(&SubKey);
@@ -4565,8 +4471,13 @@ RegRestoreKeyA(HKEY hKey,
     UNICODE_STRING FileName;
     LONG ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&FileName,
-                                     (PCSZ)lpFile);
+    if (lpFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+            return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    else
+        RtlInitEmptyUnicodeString(&FileName, NULL, 0);
 
     ErrorCode = RegRestoreKeyW(hKey,
                                FileName.Buffer,
@@ -4666,8 +4577,14 @@ RegSaveKeyA(HKEY hKey,
     UNICODE_STRING FileName;
     LONG ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&FileName,
-                                     (LPSTR)lpFile);
+    if (lpFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+            return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    else
+        RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
     ErrorCode = RegSaveKeyW(hKey,
                             FileName.Buffer,
                             lpSecurityAttributes);
@@ -4771,8 +4688,14 @@ RegSaveKeyExA(HKEY hKey,
     UNICODE_STRING FileName;
     LONG ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&FileName,
-                                     (LPSTR)lpFile);
+    if (lpFile)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+            return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    else
+        RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
     ErrorCode = RegSaveKeyExW(hKey,
                               FileName.Buffer,
                               lpSecurityAttributes,
@@ -4943,18 +4866,34 @@ RegSetValueExA(HKEY hKey,
  *
  * @implemented
  */
-LONG WINAPI
-RegSetValueExW(HKEY hKey,
-               LPCWSTR lpValueName,
-               DWORD Reserved,
-               DWORD dwType,
-               CONST BYTE* lpData,
-               DWORD cbData)
+LONG
+WINAPI
+RegSetValueExW(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpValueName,
+    _In_ DWORD Reserved,
+    _In_ DWORD dwType,
+    _In_ CONST BYTE* lpData,
+    _In_ DWORD cbData)
 {
     UNICODE_STRING ValueName;
     HANDLE KeyHandle;
     NTSTATUS Status;
 
+    Status = MapDefaultKey(&KeyHandle,
+                           hKey);
+    if (!NT_SUCCESS(Status))
+    {
+        return RtlNtStatusToDosError(Status);
+    }
+
+    if (IsHKCRKey(KeyHandle))
+    {
+        LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
+        ClosePredefKey(KeyHandle);
+        return ErrorCode;
+    }
+
     if (is_string(dwType) && (cbData != 0))
     {
         PWSTR pwsData = (PWSTR)lpData;
@@ -4970,18 +4909,12 @@ RegSetValueExW(HKEY hKey,
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            _SEH2_YIELD(return ERROR_NOACCESS);
+            ClosePredefKey(KeyHandle);
+            return ERROR_NOACCESS;
         }
         _SEH2_END;
     }
 
-    Status = MapDefaultKey(&KeyHandle,
-                           hKey);
-    if (!NT_SUCCESS(Status))
-    {
-        return RtlNtStatusToDosError(Status);
-    }
-
     RtlInitUnicodeString(&ValueName, lpValueName);
 
     Status = NtSetValueKey(KeyHandle,
@@ -5109,8 +5042,13 @@ RegUnLoadKeyA(HKEY hKey,
     UNICODE_STRING KeyName;
     DWORD ErrorCode;
 
-    RtlCreateUnicodeStringFromAsciiz(&KeyName,
-                                     (LPSTR)lpSubKey);
+    if (lpSubKey)
+    {
+        if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
+            return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    else
+        RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
 
     ErrorCode = RegUnLoadKeyW(hKey,
                               KeyName.Buffer);