Alexandre Julliard : advapi32: Add support for the KEY_WOW64_32KEY flag in RegCreateKey on 64-bit.

Alexandre Julliard julliard at winehq.org
Fri Apr 2 10:17:11 CDT 2010


Module: wine
Branch: master
Commit: 68a5c34731253e5965615b0b1cf920b63938e035
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=68a5c34731253e5965615b0b1cf920b63938e035

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Apr  2 11:51:15 2010 +0200

advapi32: Add support for the KEY_WOW64_32KEY flag in RegCreateKey on 64-bit.

---

 dlls/advapi32/registry.c       |   71 ++++++++++++++++++++++++++++++++++------
 dlls/advapi32/tests/registry.c |    4 ++-
 2 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index 9266d3f..ba9d9a7 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -78,6 +78,7 @@ static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
     name_DYN_DATA
 };
 
+static const int is_win64 = (sizeof(void *) > sizeof(int));
 
 /* check if value type needs string conversion (Ansi<->Unicode) */
 static inline int is_string( DWORD type )
@@ -91,34 +92,84 @@ static inline int is_version_nt(void)
     return !(GetVersion() & 0x80000000);
 }
 
+static BOOL is_wow6432node( const UNICODE_STRING *name )
+{
+    static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
+
+    return (name->Length == sizeof(wow6432nodeW) &&
+            !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
+}
+
+/* open the Wow6432Node subkey of the specified key */
+static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
+{
+    static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    HANDLE ret;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = key;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &nameW, wow6432nodeW );
+    if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
+    return ret;
+}
+
 /* wrapper for NtCreateKey that creates the key recursively if necessary */
 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
                             const UNICODE_STRING *class, ULONG options, PULONG dispos )
 {
-    NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
+    BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
+    NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+    if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
 
     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
     {
-        DWORD attrs, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
+        HANDLE subkey, root = attr->RootDirectory;
+        WCHAR *buffer = attr->ObjectName->Buffer;
+        DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
+        UNICODE_STRING str;
+
+        while (i < len && buffer[i] != '\\') i++;
+        if (i == len && !force_wow32) return status;
 
-        while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
-        if (i == len) return status;
         attrs = attr->Attributes;
         attr->Attributes &= ~OBJ_OPENLINK;
+        attr->ObjectName = &str;
 
         while (i < len)
         {
-            attr->ObjectName->Length = i * sizeof(WCHAR);
-            status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class,
+            str.Buffer = buffer + pos;
+            str.Length = (i - pos) * sizeof(WCHAR);
+            if (force_wow32 && pos)
+            {
+                if (is_wow6432node( &str )) force_wow32 = FALSE;
+                else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
+                {
+                    if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
+                    attr->RootDirectory = subkey;
+                    force_wow32 = FALSE;
+                }
+            }
+            status = NtCreateKey( &subkey, access, attr, 0, class,
                                   options & ~REG_OPTION_CREATE_LINK, dispos );
+            if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
             if (status) return status;
-            NtClose( *retkey );
-            while (i < len && attr->ObjectName->Buffer[i] == '\\') i++;
-            while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
+            attr->RootDirectory = subkey;
+            while (i < len && buffer[i] == '\\') i++;
+            pos = i;
+            while (i < len && buffer[i] != '\\') i++;
         }
+        str.Buffer = buffer + pos;
+        str.Length = (i - pos) * sizeof(WCHAR);
         attr->Attributes = attrs;
-        attr->ObjectName->Length = len * sizeof(WCHAR);
         status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
+        if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
     }
     return status;
 }
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index 63ed984..ea036e8 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -1862,7 +1862,9 @@ static void test_redirection(void)
     ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
     check_key_value( key, "Winetest", 0, ptr_size );
     check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
-    check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
+    dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
+    if (ptr_size == 32) ok( dw == 32, "wrong value %u\n", dw );
+    else todo_wine ok( dw == 32, "wrong value %u\n", dw );
     RegCloseKey( key );
 
     if (ptr_size == 32)




More information about the wine-cvs mailing list