[ADVAPI32]
authorJérôme Gardou <jerome.gardou@reactos.org>
Tue, 30 Sep 2014 20:00:23 +0000 (20:00 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Tue, 30 Sep 2014 20:00:23 +0000 (20:00 +0000)
 - Implement RegOpenKeyEx for HKEY_CLASSES_ROOT subkeys
CORE-8582

svn path=/trunk/; revision=64418

reactos/dll/win32/advapi32/CMakeLists.txt
reactos/dll/win32/advapi32/reg/hkcr.c [new file with mode: 0644]
reactos/dll/win32/advapi32/reg/reg.c
reactos/dll/win32/advapi32/reg/reg.h

index 2457498..71dc694 100644 (file)
@@ -28,6 +28,7 @@ list(APPEND SOURCE
     misc/msi.c
     misc/shutdown.c
     misc/sysfunc.c
+    reg/hkcr.c
     reg/reg.c
     sec/ac.c
     sec/audit.c
diff --git a/reactos/dll/win32/advapi32/reg/hkcr.c b/reactos/dll/win32/advapi32/reg/hkcr.c
new file mode 100644 (file)
index 0000000..b7a13e8
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
+ * FILE:            lib/advapi32/reg/hkcr.c
+ * PURPOSE:         Registry functions - HKEY_CLASSES_ROOT abstraction
+ * PROGRAMMER:      Jerôme Gardou (jerome.gardou@reactos.org)
+ */
+
+#include <advapi32.h>
+
+#include <ndk/cmfuncs.h>
+#include <pseh/pseh2.h>
+
+#include "reg.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(reg);
+
+static const UNICODE_STRING HKLM_ClassesPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
+
+static
+LONG
+GetKeyName(HKEY hKey, PUNICODE_STRING KeyName)
+{
+    UNICODE_STRING InfoName;
+    PKEY_NAME_INFORMATION NameInformation;
+    ULONG InfoLength;
+    NTSTATUS Status;
+
+    /* Get info length */
+    InfoLength = 0;
+    Status = NtQueryKey(hKey, KeyNameInformation, NULL, 0, &InfoLength);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        ERR("NtQueryKey returned unexpected Status: 0x%08x\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    /* Get it for real */
+    NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength);
+    if (NameInformation == NULL)
+    {
+        ERR("Failed to allocate %lu bytes", InfoLength);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    Status = NtQueryKey(hKey, KeyNameInformation, NameInformation, InfoLength, &InfoLength);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("NtQueryKey failed: 0x%08x\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    /* Make it a proper UNICODE_STRING */
+    InfoName.Length = NameInformation->NameLength;
+    InfoName.MaximumLength = NameInformation->NameLength;
+    InfoName.Buffer = NameInformation->Name;
+
+    Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &InfoName, KeyName);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("RtlDuplicateUnicodeString failed: 0x%08x\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
+
+    return ERROR_SUCCESS;
+}
+
+static
+LONG
+GetKeySam(
+    _In_ HKEY hKey,
+    _Out_ REGSAM* RegSam)
+{
+    NTSTATUS Status;
+    OBJECT_BASIC_INFORMATION ObjectInfo;
+
+    Status = NtQueryObject(hKey, ObjectBasicInformation, &ObjectInfo, sizeof(ObjectInfo), NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("NtQueryObject failed, Status %x08x\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    *RegSam = ObjectInfo.GrantedAccess;
+    return ERROR_SUCCESS;
+}
+
+/*
+ * Gets a HKLM key from an HKCU key.
+ */
+static
+LONG
+GetFallbackHKCRKey(
+    _In_ HKEY hKey,
+    _Out_ HKEY* MachineKey)
+{
+    UNICODE_STRING KeyName;
+    LPWSTR SubKeyName;
+    LONG ErrorCode;
+    REGSAM SamDesired;
+
+    /* Get the key name */
+    ErrorCode = GetKeyName(hKey, &KeyName);
+    if (ErrorCode != ERROR_SUCCESS)
+        return ErrorCode;
+
+    /* See if we really need a conversion */
+    if (RtlPrefixUnicodeString(&HKLM_ClassesPath, &KeyName, TRUE))
+    {
+        RtlFreeUnicodeString(&KeyName);
+        *MachineKey = hKey;
+        return ERROR_SUCCESS;
+    }
+
+    SubKeyName = KeyName.Buffer + 15; /* 15 == wcslen(L"\\Registry\\User\\") */
+    /* Skip the user token */
+    while (*SubKeyName++ != L'\\')
+    {
+        if (!*SubKeyName)
+        {
+            ERR("Key name %S is invalid!\n", KeyName.Buffer);
+            return ERROR_INTERNAL_ERROR;
+        }
+    }
+
+    /* Use the same access mask than the original key */
+    ErrorCode = GetKeySam(hKey, &SamDesired);
+    if (ErrorCode != ERROR_SUCCESS)
+    {
+        RtlFreeUnicodeString(&KeyName);
+        return ErrorCode;
+    }
+
+    /* Open the key. */
+    ErrorCode = RegOpenKeyExW(
+        HKEY_LOCAL_MACHINE,
+        SubKeyName,
+        0,
+        SamDesired,
+        MachineKey);
+
+    RtlFreeUnicodeString(&KeyName);
+
+    return ErrorCode;
+}
+
+/* Get the HKCU key (if it exists) from an HKCR key */
+static
+LONG
+GetPreferredHKCRKey(
+    _In_ HKEY hKey,
+    _Out_ HKEY* PreferredKey)
+{
+    UNICODE_STRING KeyName;
+    LPWSTR SubKeyName;
+    LONG ErrorCode;
+    REGSAM SamDesired;
+
+    /* Get the key name */
+    ErrorCode = GetKeyName(hKey, &KeyName);
+    if (ErrorCode != ERROR_SUCCESS)
+        return ErrorCode;
+
+    /* See if we really need a conversion */
+    if (!RtlPrefixUnicodeString(&HKLM_ClassesPath, &KeyName, TRUE))
+    {
+        RtlFreeUnicodeString(&KeyName);
+        *PreferredKey = hKey;
+        return ERROR_SUCCESS;
+    }
+
+    /* 18 == wcslen(L"\\Registry\\Machine\\") */
+    SubKeyName = KeyName.Buffer + 18;
+
+    /* Use the same access mask than the original key */
+    ErrorCode = GetKeySam(hKey, &SamDesired);
+    if (ErrorCode != ERROR_SUCCESS)
+    {
+        RtlFreeUnicodeString(&KeyName);
+        return ErrorCode;
+    }
+
+    /* Open the key. */
+    ErrorCode = RegOpenKeyExW(
+        HKEY_CURRENT_USER,
+        SubKeyName,
+        0,
+        SamDesired,
+        PreferredKey);
+
+    RtlFreeUnicodeString(&KeyName);
+
+    return ErrorCode;
+}
+
+/* Same as RegOpenKeyExW, but for HKEY_CLASSES_ROOT subkeys */
+LONG
+WINAPI
+OpenHKCRKey(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey,
+    _In_ DWORD ulOptions,
+    _In_ REGSAM samDesired,
+    _In_ PHKEY phkResult)
+{
+    HKEY QueriedKey;
+    LONG ErrorCode;
+
+    ASSERT(IsHKCRKey(hKey));
+
+    /* Remove the HKCR flag while we're working */
+    hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
+
+    ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
+
+    if (ErrorCode == ERROR_FILE_NOT_FOUND)
+    {
+        /* The key doesn't exist on HKCU side, no chance for a subkey */
+        ErrorCode = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
+        if (ErrorCode == ERROR_SUCCESS)
+            MakeHKCRKey(phkResult);
+        return ErrorCode;
+    }
+
+    if (ErrorCode != ERROR_SUCCESS)
+    {
+        /* Somehow we failed for another reason (maybe deleted key or whatever) */
+        return ErrorCode;
+    }
+
+    /* Try on the HKCU side */
+    ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
+    if (ErrorCode == ERROR_SUCCESS)
+        MakeHKCRKey(phkResult);
+
+    /* Close it if we must */
+    if (QueriedKey != hKey)
+    {
+        /* The original key is on the machine view */
+        RegCloseKey(QueriedKey);
+    }
+
+    /* Anything else than ERROR_FILE_NOT_FOUND means that we found it, even if it is with failures. */
+    if (ErrorCode != ERROR_FILE_NOT_FOUND)
+        return ErrorCode;
+
+    /* If we're here, we must open from HKLM key. */
+    ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey);
+    if (ErrorCode != ERROR_SUCCESS)
+    {
+        /* Maybe the key doesn't exist in the HKLM view */
+        return ErrorCode;
+    }
+
+    ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
+    if (ErrorCode == ERROR_SUCCESS)
+        MakeHKCRKey(phkResult);
+
+    /* Close it if we must */
+    if (QueriedKey != hKey)
+    {
+        /* The original key is on the machine view */
+        RegCloseKey(QueriedKey);
+    }
+
+    return ErrorCode;
+}
index 8fef998..92f8d31 100644 (file)
@@ -3483,6 +3483,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;
 
@@ -3500,11 +3503,13 @@ RegOpenKeyExW(HKEY hKey,
     Status = NtOpenKey((PHANDLE)phkResult,
                        samDesired,
                        &ObjectAttributes);
+
     if (!NT_SUCCESS(Status))
     {
         ErrorCode = RtlNtStatusToDosError(Status);
     }
 
+
     ClosePredefKey(KeyHandle);
 
     return ErrorCode;
index 8228be4..45e8113 100644 (file)
@@ -19,5 +19,14 @@ FORCEINLINE
 void
 MakeHKCRKey(_Inout_ HKEY* hKey)
 {
-    *hKey = (HKEY)((ULONG_PTR)*hKey | 0x2);
+    *hKey = (HKEY)((ULONG_PTR)(*hKey) | 0x2);
 }
+
+LONG
+WINAPI
+OpenHKCRKey(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey,
+    _In_ DWORD ulOptions,
+    _In_ REGSAM samDesired,
+    _In_ PHKEY phkResult);