I initially wanted to do the refactoring in a separate merge request, but since my merge request yesterday broke the tests, I decided to add the implementation into this commit as well.
-- v3: kernelbase: Recursively obtain the Wow6432Node parent. kernelbase: Add support for shared registry keys.
From: Sven Baars sbaars@codeweavers.com
These can never exist in a newly created key. --- dlls/kernelbase/registry.c | 13 ------------- 1 file changed, 13 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 63855eeb555..9fd1abceabb 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -303,19 +303,6 @@ static NTSTATUS create_key( HKEY *retkey, HKEY root, UNICODE_STRING name, ULONG while (i < len && buffer[i] == '\') i++; buffer += i; len -= i; - - if (force_wow32) - { - name.Buffer = buffer; - name.Length = len * sizeof(WCHAR); - if (is_wow6432node( &name )) force_wow32 = FALSE; - else if ((subkey = open_wow6432node( attr.RootDirectory ))) - { - NtClose( attr.RootDirectory ); - attr.RootDirectory = subkey; - force_wow32 = FALSE; - } - } } } if (status == STATUS_PREDEFINED_HANDLE)
From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 121 ++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 50 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 9fd1abceabb..f9e647a026a 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -227,25 +227,76 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o return status; }
-/* wrapper for NtCreateKey that creates the key recursively if necessary */ -static NTSTATUS create_key( HKEY *retkey, HKEY root, UNICODE_STRING name, ULONG options, ACCESS_MASK access, - const UNICODE_STRING *class, PULONG dispos ) +static NTSTATUS create_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, + const UNICODE_STRING *class, PULONG dispos ) { - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + DWORD i = 0, len = name->Length / sizeof(WCHAR); + WCHAR *buffer = name->Buffer; OBJECT_ATTRIBUTES attr; - HKEY subkey; + UNICODE_STRING str; + NTSTATUS status;
attr.Length = sizeof(attr); attr.RootDirectory = root; - attr.ObjectName = &name; + attr.ObjectName = &str; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; - if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
- if (!force_wow32) + if (i < len && buffer[i] == '\') return STATUS_OBJECT_PATH_INVALID; + while (i < len && buffer[i] != '\') i++; + + str.Buffer = name->Buffer; + str.Length = i * sizeof(WCHAR); + + if (i == len) + { + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + } + else + { + options &= ~REG_OPTION_CREATE_LINK; + } + + status = NtCreateKey( (HANDLE *)subkey, access, &attr, 0, class, options, dispos ); + if (status == STATUS_PREDEFINED_HANDLE) + { + *subkey = get_perflib_key( *subkey ); + status = STATUS_SUCCESS; + } + + if (!status) + { + while (i < len && buffer[i] == '\') i++; + + name->Buffer += i; + name->Length -= i * sizeof(WCHAR); + } + + return status; +} + +/* wrapper for NtCreateKey that creates the key recursively if necessary */ +static NTSTATUS create_key( HKEY *retkey, HKEY root, UNICODE_STRING name, ULONG options, ACCESS_MASK access, + const UNICODE_STRING *class, PULONG dispos ) +{ + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + HKEY subkey, subkey_root = root; + + *retkey = NULL; + + if (!(is_win64 && (access & KEY_WOW64_32KEY))) { + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = root; + attr.ObjectName = &name; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + status = NtCreateKey( (HANDLE *)retkey, access, &attr, 0, class, options, dispos ); if (status == STATUS_PREDEFINED_HANDLE) { @@ -257,60 +308,30 @@ static NTSTATUS create_key( HKEY *retkey, HKEY root, UNICODE_STRING name, ULONG return status; }
- status = open_key( &subkey, root, &name, options & REG_OPTION_OPEN_LINK, access, TRUE ); + status = open_key( &subkey_root, root, &name, options & REG_OPTION_OPEN_LINK, access, TRUE ); if (!status && (options & REG_OPTION_CREATE_LINK)) { - NtClose( subkey ); + NtClose( subkey_root ); status = STATUS_OBJECT_NAME_COLLISION; }
if (!status) if (dispos) *dispos = REG_OPENED_EXISTING_KEY;
- attr.RootDirectory = subkey; if (status == STATUS_OBJECT_NAME_NOT_FOUND) { - DWORD attrs, i, len = name.Length / sizeof(WCHAR); - WCHAR *buffer = name.Buffer; - - attrs = attr.Attributes; - - while (len) + status = STATUS_SUCCESS; + while (!status && name.Length) { - i = 0; - - /* don't try to create registry root */ - if (!attr.RootDirectory && len > 10 && !wcsnicmp( buffer, L"\Registry\", 10 )) i += 10; - while (i < len && buffer[i] != '\') i++; - - name.Buffer = buffer; - name.Length = i * sizeof(WCHAR); - - if (i == len) - { - attr.Attributes = attrs; - status = NtCreateKey( (HANDLE *)&subkey, access, &attr, 0, class, options, dispos ); - } - else - { - attr.Attributes = attrs & ~OBJ_OPENLINK; - status = NtCreateKey( (HANDLE *)&subkey, access, &attr, 0, class, - options & ~REG_OPTION_CREATE_LINK, dispos ); - } - if (attr.RootDirectory != root) NtClose( attr.RootDirectory ); - if (!NT_SUCCESS(status)) return status; - attr.RootDirectory = subkey; - while (i < len && buffer[i] == '\') i++; - buffer += i; - len -= i; + status = create_subkey( &subkey, subkey_root, &name, options, access, class, dispos ); + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; } } - if (status == STATUS_PREDEFINED_HANDLE) - { - attr.RootDirectory = get_perflib_key( attr.RootDirectory ); - status = STATUS_SUCCESS; - } - *retkey = attr.RootDirectory; + + if (!status) + *retkey = subkey_root; + return status; }
From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index f9e647a026a..a69a87ebb3d 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -227,44 +227,28 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o return status; }
+static NTSTATUS create_key( HKEY *retkey, HKEY root, UNICODE_STRING name, ULONG options, ACCESS_MASK access, + const UNICODE_STRING *class, PULONG dispos ); + static NTSTATUS create_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, const UNICODE_STRING *class, PULONG dispos ) { + ACCESS_MASK access_64 = access & ~KEY_WOW64_32KEY; DWORD i = 0, len = name->Length / sizeof(WCHAR); WCHAR *buffer = name->Buffer; - OBJECT_ATTRIBUTES attr; UNICODE_STRING str; NTSTATUS status;
- attr.Length = sizeof(attr); - attr.RootDirectory = root; - attr.ObjectName = &str; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - if (i < len && buffer[i] == '\') return STATUS_OBJECT_PATH_INVALID; while (i < len && buffer[i] != '\') i++;
str.Buffer = name->Buffer; str.Length = i * sizeof(WCHAR);
- if (i == len) - { - if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; - } - else - { + if (i < len) options &= ~REG_OPTION_CREATE_LINK; - } - - status = NtCreateKey( (HANDLE *)subkey, access, &attr, 0, class, options, dispos ); - if (status == STATUS_PREDEFINED_HANDLE) - { - *subkey = get_perflib_key( *subkey ); - status = STATUS_SUCCESS; - }
+ status = create_key( subkey, root, str, options, access_64, class, dispos ); if (!status) { while (i < len && buffer[i] == '\') i++;
From: Sven Baars sbaars@codeweavers.com
--- dlls/advapi32/tests/registry.c | 132 ++++++++++++++++----------------- dlls/kernelbase/registry.c | 108 +++++++++++++++++++++++++-- 2 files changed, 168 insertions(+), 72 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index 80bf39bb178..e7e9ef0c2ab 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2589,8 +2589,7 @@ static void _todo_check_key_value( int line, HANDLE root, const char *name, DWOR } #define todo_check_key_value(root,name,flags,expect, todo) _todo_check_key_value( __LINE__, root, name, flags, expect, todo )
-static void _check_enum_value( int line, const char *name, DWORD flags, DWORD subkeys_in, BOOL found_in, - BOOL todo_subkeys, BOOL todo_found) +static void _check_enum_value( int line, const char *name, DWORD flags, DWORD subkeys_in, BOOL found_in) { char buffer[1024]; DWORD err, i, subkeys; @@ -2603,7 +2602,7 @@ static void _check_enum_value( int line, const char *name, DWORD flags, DWORD su err = RegQueryInfoKeyA( key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); ok_( __FILE__, line )( err == ERROR_SUCCESS, "RegQueryInfoKeyA failed: %lu\n", err ); - todo_wine_if(todo_subkeys) ok_( __FILE__, line )( subkeys == subkeys_in, "wrong number of subkeys: %lu\n", subkeys ); + ok_( __FILE__, line )( subkeys == subkeys_in, "wrong number of subkeys: %lu\n", subkeys );
found = FALSE; for (i = 0; i < subkeys; i++) @@ -2614,11 +2613,10 @@ static void _check_enum_value( int line, const char *name, DWORD flags, DWORD su if (!strcmp(buffer, "Wine")) found = TRUE; } - todo_wine_if(todo_found) ok_( __FILE__, line )( found == found_in, "found equals %d\n", found ); + ok_( __FILE__, line )( found == found_in, "found equals %d\n", found ); RegCloseKey( key ); } -#define check_enum_value(name, flags, subkeys, found, todo_subkeys, todo_found) _check_enum_value( \ - __LINE__, name, flags, subkeys, found, todo_subkeys, todo_found ) +#define check_enum_value(name, flags, subkeys, found) _check_enum_value( __LINE__, name, flags, subkeys, found )
static void test_redirection(void) { @@ -2834,7 +2832,7 @@ static void test_redirection(void)
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); RegCloseKey( key );
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", @@ -2857,16 +2855,16 @@ static void test_redirection(void)
check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", 0, 64 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_64KEY, 64 ); - todo_check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_32KEY, 64, ptr_size == 64 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_32KEY, 64 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", 0, ptr_size == 64 ? 0 : 64 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", KEY_WOW64_64KEY, 0 ); - todo_check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", KEY_WOW64_32KEY, 64, ptr_size == 64 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", KEY_WOW64_32KEY, 64 );
RegDeleteKeyA( key32, "" ); RegCloseKey( key32 );
- todo_check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", 0, 0, ptr_size == 64 ); - todo_check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_64KEY, 0, ptr_size == 64 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", 0, 0 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_64KEY, 0 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", KEY_WOW64_32KEY, 0 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", 0, 0 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", KEY_WOW64_64KEY, 0 ); @@ -2892,11 +2890,11 @@ static void test_redirection(void) RegCloseKey( key );
err = RegOpenKeyExA( root32, "Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); RegCloseKey( key );
err = RegOpenKeyExA( root32, "Wine", 0, KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); RegCloseKey( key );
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, @@ -2914,16 +2912,16 @@ static void test_redirection(void) check_key_value( root64, "Wine", 0, 64 ); check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 ); check_key_value( root64, "Wine", KEY_WOW64_32KEY, 64 ); - todo_check_key_value( root32, "Wine", 0, 64, ptr_size == 64 ); - todo_check_key_value( root32, "Wine", KEY_WOW64_64KEY, 64, ptr_size == 64 ); - todo_check_key_value( root32, "Wine", KEY_WOW64_32KEY, 64, ptr_size == 64 ); + check_key_value( root32, "Wine", 0, 64 ); + check_key_value( root32, "Wine", KEY_WOW64_64KEY, 64 ); + check_key_value( root32, "Wine", KEY_WOW64_32KEY, 64 );
RegDeleteKeyA( key32, "" ); RegCloseKey( key32 );
- todo_check_key_value( root64, "Wine", 0, 0, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0, ptr_size == 64 ); + check_key_value( root64, "Wine", 0, 0 ); + check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0 ); + check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0 ); check_key_value( root32, "Wine", 0, 0 ); check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 ); check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 ); @@ -2939,9 +2937,9 @@ static void test_redirection(void) err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) ); ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
- todo_check_key_value( root64, "Wine", 0, 32, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 32, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); + check_key_value( root64, "Wine", 0, 32 ); + check_key_value( root64, "Wine", KEY_WOW64_64KEY, 32 ); + check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 ); check_key_value( root32, "Wine", 0, 32 ); check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 ); @@ -2958,7 +2956,7 @@ static void test_redirection(void)
err = RegOpenKeyExA( HKEY_CLASSES_ROOT, "Interface", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &root32 ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
err = RegOpenKeyExA( HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS, &root ); @@ -2966,10 +2964,10 @@ static void test_redirection(void)
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key ); - ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -2978,10 +2976,10 @@ static void test_redirection(void)
err = RegCreateKeyExA( root64, "Wine", 0, NULL, 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 32 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + ok( err == (ptr_size == 32 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3014,7 +3012,7 @@ static void test_redirection(void)
err = RegOpenKeyExA( root32, "Interface", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key32 ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Interface", 0, KEY_ALL_ACCESS, &key ); @@ -3030,10 +3028,10 @@ static void test_redirection(void)
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key ); - ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3067,11 +3065,11 @@ static void test_redirection(void)
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key32, NULL); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
dw = 32; err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
dw = 64; err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) ); @@ -3080,9 +3078,9 @@ static void test_redirection(void) check_key_value( root64, "Wine", 0, 64 ); check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 ); todo_check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", 0, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 ); + todo_check_key_value( root32, "Wine", 0, 32, ptr_size == 64 ); + todo_check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32, ptr_size == 64 ); + todo_check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 );
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Interface", 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key ); @@ -3094,10 +3092,10 @@ static void test_redirection(void)
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Interface", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); - todo_wine_if(ptr_size == 64) check_key_value( key, "Wine", 0, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( key, "Wine", KEY_WOW64_64KEY, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( key, "Wine", KEY_WOW64_32KEY, 32 ); + ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); + todo_check_key_value( key, "Wine", 0, 32, ptr_size == 64 ); + todo_check_key_value( key, "Wine", KEY_WOW64_64KEY, 32, ptr_size == 64 ); + todo_check_key_value( key, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); RegCloseKey( key );
check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size ); @@ -3107,15 +3105,15 @@ static void test_redirection(void) RegDeleteKeyA( key32, "" ); RegCloseKey( key32 );
- check_key_value( root64, "Wine", 0, 64 ); - check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0, ptr_size == 64 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", 0, 0 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 ); + todo_check_key_value( root64, "Wine", 0, 64, ptr_size == 64 ); + todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64, ptr_size == 64 ); + check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0 ); + check_key_value( root32, "Wine", 0, 0 ); + check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 ); + check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 );
- check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size == 64 ? 64 : 0 ); - check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_64KEY, 64 ); + todo_wine_if(ptr_size == 64) check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size == 64 ? 64 : 0 ); + todo_wine_if(ptr_size == 64) check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_64KEY, 64 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_32KEY, 0 );
RegDeleteKeyA( key64, "" ); @@ -3123,18 +3121,18 @@ static void test_redirection(void)
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key32, NULL); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
dw = 32; err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err ); + ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
- check_key_value( root64, "Wine", 0, 0 ); - check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0 ); - todo_wine_if(ptr_size == 64) check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", 0, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); - todo_wine_if(ptr_size == 64) check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 ); + todo_check_key_value( root64, "Wine", 0, 0, ptr_size == 64 ); + todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0, ptr_size == 64 ); + check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 ); + check_key_value( root32, "Wine", 0, 32 ); + check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); + check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 );
RegDeleteKeyA( key32, "" ); RegCloseKey( key32 ); @@ -3153,7 +3151,7 @@ static void test_redirection(void)
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Wow6432Node\Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3171,7 +3169,7 @@ static void test_redirection(void)
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3188,7 +3186,7 @@ static void test_redirection(void) err = RegQueryInfoKeyA(root32, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); ok( err == ERROR_SUCCESS, "RegQueryInfoKeyA failed: %lu\n", err ); - todo_wine_if(ptr_size == 64) ok( subkeys > 0, "wrong number of subkeys: %lu\n", subkeys ); + ok( subkeys > 0, "wrong number of subkeys: %lu\n", subkeys ); subkeys32 = subkeys; RegCloseKey( root32 );
@@ -3204,23 +3202,23 @@ static void test_redirection(void) RegCloseKey( root64 );
check_enum_value( "Software\Classes", - KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32, ptr_size == 64, FALSE ); + KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 ); check_enum_value( "Software\Classes", - KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32, FALSE, FALSE ); + KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 ); check_enum_value( "Software\Classes", - KEY_ALL_ACCESS, subkeys64, ptr_size == 32, FALSE, FALSE ); + KEY_ALL_ACCESS, subkeys64, ptr_size == 32 ); check_enum_value( "Software\Classes\Wow6432Node", - KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64, FALSE, ptr_size == 64 ); + KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 ); check_enum_value( "Software\Classes\Wow6432Node", - KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64, ptr_size == 64, FALSE ); + KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 ); check_enum_value( "Software\Classes\Wow6432Node", - KEY_ALL_ACCESS, subkeys32, ptr_size == 64, ptr_size == 64, FALSE ); + KEY_ALL_ACCESS, subkeys32, ptr_size == 64 ); check_enum_value( "Software\Wow6432Node\Classes", - KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32, ptr_size == 64, FALSE ); + KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 ); check_enum_value( "Software\Wow6432Node\Classes", - KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64, ptr_size == 64, FALSE ); + KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 ); check_enum_value( "Software\Wow6432Node\Classes", - KEY_ALL_ACCESS, ptr_size == 32 ? subkeys64 : subkeys32, TRUE, ptr_size == 64, FALSE ); + KEY_ALL_ACCESS, ptr_size == 32 ? subkeys64 : subkeys32, TRUE );
RegDeleteKeyA( key32, "" ); RegCloseKey( key32 ); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index a69a87ebb3d..84ab8125bd1 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -104,11 +104,56 @@ static BOOL is_wow6432node( const UNICODE_STRING *name ) return (len >= 11 && !wcsnicmp( name->Buffer, L"Wow6432Node\", min( len, 12 ) )); }
-/* open the Wow6432Node subkey of the specified key */ +static BOOL is_classes_root( const UNICODE_STRING *name ) +{ + return (name->Length >= wcslen(root_key_names[0]) * sizeof(WCHAR) && !wcsnicmp( name->Buffer, root_key_names[0], wcslen(root_key_names[0]) )); +} + +static BOOL is_classes_wow6432node( HKEY key ) +{ + char buffer[256], *buf_ptr = buffer; + KEY_NAME_INFORMATION *info = (KEY_NAME_INFORMATION *)buffer; + DWORD len = sizeof(buffer); + UNICODE_STRING name; + NTSTATUS status; + BOOL ret = FALSE; + + /* Obtain the name of the root key */ + status = NtQueryKey( key, KeyNameInformation, info, len, &len ); + if (status && status != STATUS_BUFFER_OVERFLOW) return FALSE; + + /* Retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( len ))) return FALSE; + info = (KEY_NAME_INFORMATION *)buf_ptr; + status = NtQueryKey( key, KeyNameInformation, info, len, &len ); + } + + /* Check if the key ends in Wow6432Node and if the root is the Classes key*/ + if (!status && info->NameLength / sizeof(WCHAR) >= 11) + { + name.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11; + name.Length = 11 * sizeof(WCHAR); + if (is_wow6432node( &name )) + { + name.Buffer = info->Name; + name.Length = info->NameLength; + ret = is_classes_root( &name ); + } + } + + if (buf_ptr != buffer) heap_free( buf_ptr ); + + return ret; +} + +/* Open the Wow6432Node subkey of the specified key */ static HANDLE open_wow6432node( HANDLE key ) { - OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"Wow6432Node" ); + OBJECT_ATTRIBUTES attr; HANDLE ret;
attr.Length = sizeof(attr); @@ -117,7 +162,25 @@ static HANDLE open_wow6432node( HANDLE key ) attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; - if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; + if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return key; + return ret; +} + +/* Open HKCR, which should already exist because it's used when we're in its Wow6432Node child */ +static HANDLE open_classes_root( void ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + HANDLE ret = 0; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, root_key_names[0] ); + NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 ); return ret; }
@@ -162,6 +225,21 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR options &= ~REG_OPTION_OPEN_LINK;
status = open_key( subkey, root, &str, options, access_64, FALSE ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND && root && is_wow64_key) + { + /* Try to open the shared parent if we can't find the key in the Wow6432Node */ + if (!is_classes_wow6432node( root )) + return STATUS_OBJECT_NAME_NOT_FOUND; + + root = open_classes_root(); + status = open_key( subkey, root, &str, options, access_64, FALSE ); + + if (!status) + NtClose( root ); + else + *subkey = root; + } + if (!status) { while (i < len && buffer[i] == '\') i++; @@ -172,7 +250,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR if (is_wow64_key && !is_wow6432node( name )) { HKEY wow6432node = open_wow6432node( *subkey ); - if (wow6432node) + if (wow6432node != *subkey) { NtClose( *subkey ); *subkey = wow6432node; @@ -186,8 +264,10 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, BOOL create ) { + BOOL is_wow64_key = (is_win64 && (access & KEY_WOW64_32KEY)) || (is_wow64 && !(access & KEY_WOW64_64KEY)); HKEY subkey = 0, subkey_root = root; - NTSTATUS status = 0; + NTSTATUS status = STATUS_SUCCESS; + BOOL was_wow6432node = TRUE;
*retkey = NULL;
@@ -212,13 +292,31 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o return status; }
+ if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name )) + { + subkey_root = open_wow6432node( root ); + if (!is_classes_wow6432node( subkey_root ) && subkey_root != root) + { + NtClose( subkey_root ); + subkey_root = root; + } + } + while (!status && (name->Length || !subkey)) { + was_wow6432node = is_wow6432node( name ); status = open_subkey( &subkey, subkey_root, name, options, access ); if (subkey && subkey_root && subkey_root != root) NtClose( subkey_root ); if (subkey) subkey_root = subkey; }
+ /* Return the shared parent if we didn't explicitly look for the Wow6432Node */ + if (!status && !was_wow6432node && is_wow64_key && is_classes_wow6432node( subkey_root )) + { + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = open_classes_root(); + } + if (!status || (status == STATUS_OBJECT_NAME_NOT_FOUND && create)) *retkey = subkey_root; else if (subkey_root && subkey_root != root)
From: Sven Baars sbaars@codeweavers.com
--- dlls/advapi32/tests/registry.c | 60 +++++++++++++--------------------- dlls/kernelbase/registry.c | 49 ++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 38 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index e7e9ef0c2ab..9e051056eed 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2582,13 +2582,6 @@ static void _check_key_value( int line, HANDLE root, const char *name, DWORD fla } #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
-static void _todo_check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect, BOOL todo ) -{ - DWORD dw = get_key_value( root, name, flags ); - todo_wine_if(todo) ok_(__FILE__,line)( dw == expect, "%08lx: wrong value %lu/%lu\n", flags, dw, expect ); -} -#define todo_check_key_value(root,name,flags,expect, todo) _todo_check_key_value( __LINE__, root, name, flags, expect, todo ) - static void _check_enum_value( int line, const char *name, DWORD flags, DWORD subkeys_in, BOOL found_in) { char buffer[1024]; @@ -2679,12 +2672,9 @@ static void test_redirection(void) err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL ); ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err ); - check_key_value( key, "Wine\Winetest", 0, ptr_size ); check_key_value( key, "Wine\Winetest", KEY_WOW64_64KEY, ptr_size ); - dw = get_key_value( key, "Wine\Winetest", KEY_WOW64_32KEY ); - todo_wine_if (ptr_size == 64) ok( dw == 32, "wrong value %lu\n", dw ); - + check_key_value( key, "Wine\Winetest", KEY_WOW64_32KEY, 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", 0, ptr_size == 32 ? 0 : 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", KEY_WOW64_64KEY, ptr_size == 32 ? 0 : 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", KEY_WOW64_32KEY, ptr_size == 32 ? 0 : 32 ); @@ -2696,8 +2686,7 @@ static void test_redirection(void) dw = get_key_value( key, "Wine\Winetest", 0 ); ok( dw == 64 || broken(dw == 32) /* win7 */, "wrong value %lu\n", dw ); check_key_value( key, "Wine\Winetest", KEY_WOW64_64KEY, 64 ); - dw = get_key_value( key, "Wine\Winetest", KEY_WOW64_32KEY ); - todo_wine_if (ptr_size == 64) ok( dw == 32, "wrong value %lu\n", dw ); + check_key_value( key, "Wine\Winetest", KEY_WOW64_32KEY, 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", 0, 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", KEY_WOW64_64KEY, 32 ); check_key_value( key, "Wow6432Node\Wine\Winetest", KEY_WOW64_32KEY, 32 ); @@ -2774,9 +2763,7 @@ static void test_redirection(void) ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err ); check_key_value( key, "Winetest", 0, ptr_size ); check_key_value( key, "Winetest", KEY_WOW64_64KEY, ptr_size ); - dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY ); - todo_wine_if (ptr_size != 32) - ok( dw == 32, "wrong value %lu\n", dw ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); RegCloseKey( key );
err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\Wine", 0, NULL, 0, @@ -2784,8 +2771,7 @@ static void test_redirection(void) ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err ); check_key_value( key, "Winetest", 0, 64 ); check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 ); - dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY ); - todo_wine_if (ptr_size == 64) ok( dw == 32, "wrong value %lu\n", dw ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); RegCloseKey( key );
err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\Wine", 0, NULL, 0, @@ -2967,7 +2953,7 @@ static void test_redirection(void) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3031,7 +3017,7 @@ static void test_redirection(void) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), + ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS), "RegOpenKeyExA failed: %lu\n", err ); if (!err) RegCloseKey( key );
@@ -3058,10 +3044,10 @@ static void test_redirection(void) ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
err = RegOpenKeyExA( root32, "Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err );
err = RegOpenKeyExA( root32, "Wine", 0, KEY_ALL_ACCESS, &key ); - todo_wine_if(ptr_size == 64) ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err ); + ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err );
err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key32, NULL); @@ -3077,43 +3063,43 @@ static void test_redirection(void)
check_key_value( root64, "Wine", 0, 64 ); check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); - todo_check_key_value( root32, "Wine", 0, 32, ptr_size == 64 ); - todo_check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32, ptr_size == 64 ); - todo_check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); + check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 ); + check_key_value( root32, "Wine", 0, 32 ); + check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); + check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 );
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Interface", 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key ); ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); check_key_value( key, "Wine", 0, 64 ); check_key_value( key, "Wine", KEY_WOW64_64KEY, 64 ); - todo_check_key_value( key, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); + check_key_value( key, "Wine", KEY_WOW64_32KEY, 32 ); RegCloseKey( key );
err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\Classes\Interface", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key ); ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err ); - todo_check_key_value( key, "Wine", 0, 32, ptr_size == 64 ); - todo_check_key_value( key, "Wine", KEY_WOW64_64KEY, 32, ptr_size == 64 ); - todo_check_key_value( key, "Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); + check_key_value( key, "Wine", 0, 32 ); + check_key_value( key, "Wine", KEY_WOW64_64KEY, 32 ); + check_key_value( key, "Wine", KEY_WOW64_32KEY, 32 ); RegCloseKey( key );
check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_64KEY, 64 ); - todo_check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_32KEY, 32, ptr_size == 64 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_32KEY, 32 );
RegDeleteKeyA( key32, "" ); RegCloseKey( key32 );
- todo_check_key_value( root64, "Wine", 0, 64, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64, ptr_size == 64 ); + check_key_value( root64, "Wine", 0, 64 ); + check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 ); check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0 ); check_key_value( root32, "Wine", 0, 0 ); check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 ); check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 );
- todo_wine_if(ptr_size == 64) check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size == 64 ? 64 : 0 ); - todo_wine_if(ptr_size == 64) check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_64KEY, 64 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", 0, ptr_size == 64 ? 64 : 0 ); + check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_64KEY, 64 ); check_key_value( HKEY_LOCAL_MACHINE, "Software\Classes\Interface\Wine", KEY_WOW64_32KEY, 0 );
RegDeleteKeyA( key64, "" ); @@ -3127,8 +3113,8 @@ static void test_redirection(void) err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) ); ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
- todo_check_key_value( root64, "Wine", 0, 0, ptr_size == 64 ); - todo_check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0, ptr_size == 64 ); + check_key_value( root64, "Wine", 0, 0 ); + check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0 ); check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 ); check_key_value( root32, "Wine", 0, 32 ); check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 ); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 84ab8125bd1..40e9c6aaeca 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -261,6 +261,51 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR return status; }
+static NTSTATUS open_wow6432node_parent( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access ) +{ + char buffer[256], *buf_ptr = buffer; + KEY_NAME_INFORMATION *info = (KEY_NAME_INFORMATION *)buffer; + DWORD len = sizeof(buffer); + UNICODE_STRING name; + NTSTATUS status; + + /* Obtain the name of the root key */ + status = NtQueryKey( root, KeyNameInformation, info, len, &len ); + if (status && status != STATUS_BUFFER_OVERFLOW) return status; + + /* Retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( len ))) + return STATUS_NO_MEMORY; + info = (KEY_NAME_INFORMATION *)buf_ptr; + status = NtQueryKey( root, KeyNameInformation, info, len, &len ); + } + + if (status) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + return status; + } + + name.Buffer = info->Name; + name.Length = info->NameLength; + root = 0; + + /* Obtain the parent Wow6432Node if it exists */ + while (!status && name.Length) + { + status = open_subkey( retkey, root, &name, options & ~REG_OPTION_OPEN_LINK, access ); + if (root) NtClose( root ); + root = *retkey; + } + + if (buf_ptr != buffer) heap_free( buf_ptr ); + + return status; +} + /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, BOOL create ) { @@ -292,7 +337,9 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o return status; }
- if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name )) + if (root && (access & KEY_WOW64_32KEY) && !is_wow6432node( name )) + status = open_wow6432node_parent( &subkey_root, root, options, access ); + else if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name )) { subkey_root = open_wow6432node( root ); if (!is_classes_wow6432node( subkey_root ) && subkey_root != root)
The remaining msi test failures on my system seem to be caused by ccd96404933, not one of my commits.