This reimplements all logic from the server in kernelbase, which is needed because Nt*Key ignores KEY_WOW64_32KEY. Unfortunately this requires a lot of server calls.
The full branch can be found here
https://gitlab.winehq.org/sbaars/wine/-/tree/shared-classes-new
The old approach that doesn't duplicate code to kernelbase can be found here
https://gitlab.winehq.org/sbaars/wine/-/tree/shared-classes-old
I ran make_requests by the way, not sure if we should still leave that out with the gitlab workflow.
From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 134 ++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 55 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 91462d80e06..135ff48bf7e 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -100,7 +100,7 @@ static inline BOOL is_version_nt(void)
static BOOL is_wow6432node( const UNICODE_STRING *name ) { - return (name->Length == 11 * sizeof(WCHAR) && !wcsnicmp( name->Buffer, L"Wow6432Node", 11 )); + return (name->Length >= 11 * sizeof(WCHAR) && !wcsnicmp( name->Buffer, L"Wow6432Node", 11 )); }
/* open the Wow6432Node subkey of the specified key */ @@ -214,19 +214,77 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES return status; }
-/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ -static NTSTATUS open_key( HKEY *retkey, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) +static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { - NTSTATUS status; - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - HANDLE subkey, root = attr->RootDirectory; - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + DWORD i = 0, len = name->Length / sizeof(WCHAR); + WCHAR *buffer = name->Buffer; + OBJECT_ATTRIBUTES attr; UNICODE_STRING str; + NTSTATUS status = 0; + + attr.Length = sizeof(attr); + attr.RootDirectory = (HANDLE)root; + attr.ObjectName = &str; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (!root && len > 10 && !wcsnicmp( buffer, L"\Registry\", 10 )) i += 10; + 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; + status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options ); + } + else + { + if (!(options & REG_OPTION_OPEN_LINK)) attr.Attributes &= ~OBJ_OPENLINK; + status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options & ~REG_OPTION_OPEN_LINK ); + } + + 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); + + if (!is_wow6432node( name )) + { + HKEY wow6432node = open_wow6432node( *subkey ); + if (wow6432node) + { + NtClose( *subkey ); + *subkey = wow6432node; + } + } + } + + return status; +} + + +/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ +static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) +{ + HKEY subkey, subkey_root = root; + UNICODE_STRING name; + NTSTATUS status = 0;
*retkey = NULL;
- if (!force_wow32) + if (!(is_win64 && (access & KEY_WOW64_32KEY))) { if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; status = NtOpenKeyEx( (HANDLE *)retkey, access, attr, options ); @@ -238,53 +296,19 @@ static NTSTATUS open_key( HKEY *retkey, DWORD options, ACCESS_MASK access, OBJEC return status; }
- if (len && buffer[0] == '\') return STATUS_OBJECT_PATH_INVALID; - while (i < len && buffer[i] != '\') i++; - attr->ObjectName = &str; + name.Buffer = attr->ObjectName->Buffer; + name.Length = attr->ObjectName->Length;
- for (;;) - { - 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 ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options ); - } - else - { - if (!(options & REG_OPTION_OPEN_LINK)) attr->Attributes &= ~OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options & ~REG_OPTION_OPEN_LINK ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (status) return status; - attr->RootDirectory = subkey; - if (i == len) break; - while (i < len && buffer[i] == '\') i++; - pos = i; - while (i < len && buffer[i] != '\') i++; - } - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - if (status == STATUS_PREDEFINED_HANDLE) + while (!status && name.Length) { - attr->RootDirectory = get_perflib_key( attr->RootDirectory ); - status = STATUS_SUCCESS; + status = open_subkey( &subkey, subkey_root, &name, options, access ); + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; } - *retkey = attr->RootDirectory; + + if (!status) + *retkey = subkey_root; + return status; }
@@ -538,7 +562,7 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD o attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, name ); - return RtlNtStatusToDosError( open_key( retkey, options, access, &attr ) ); + return RtlNtStatusToDosError( open_key( retkey, hkey, options, access, &attr ) ); }
@@ -596,7 +620,7 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD op if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, &nameA, FALSE ))) { - status = open_key( retkey, options, access, &attr ); + status = open_key( retkey, hkey, options, access, &attr ); } return RtlNtStatusToDosError( status ); }
From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 176 +++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 78 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 135ff48bf7e..2664d13f05a 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -140,82 +140,10 @@ static HKEY get_perflib_key( HANDLE key ) return key; }
-/* 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 ) -{ - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; - HANDLE subkey, root = attr->RootDirectory; - - if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - { - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); - UNICODE_STRING str; - - /* 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++; - if (i == len && !force_wow32) return status; - - attrs = attr->Attributes; - attr->ObjectName = &str; - - for (;;) - { - 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 ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - attr->Attributes = attrs; - status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - } - else - { - attr->Attributes = attrs & ~OBJ_OPENLINK; - status = NtCreateKey( &subkey, access, attr, 0, class, - options & ~REG_OPTION_CREATE_LINK, dispos ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (!NT_SUCCESS(status)) return status; - if (i == len) break; - attr->RootDirectory = subkey; - while (i < len && buffer[i] == '\') i++; - pos = i; - while (i < len && buffer[i] != '\') i++; - } - } - attr->RootDirectory = subkey; - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - if (status == STATUS_PREDEFINED_HANDLE) - { - attr->RootDirectory = get_perflib_key( attr->RootDirectory ); - status = STATUS_SUCCESS; - } - *retkey = attr->RootDirectory; - return status; -} - static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { + BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); + ACCESS_MASK access_64 = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY; DWORD i = 0, len = name->Length / sizeof(WCHAR); WCHAR *buffer = name->Buffer; OBJECT_ATTRIBUTES attr; @@ -239,14 +167,14 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR if (i == len) { if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; - status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options ); } else { if (!(options & REG_OPTION_OPEN_LINK)) attr.Attributes &= ~OBJ_OPENLINK; - status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options & ~REG_OPTION_OPEN_LINK ); + options &= ~REG_OPTION_OPEN_LINK; }
+ status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); if (status == STATUS_PREDEFINED_HANDLE) { *subkey = get_perflib_key( *subkey ); @@ -260,7 +188,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR name->Buffer += i; name->Length -= i * sizeof(WCHAR);
- if (!is_wow6432node( name )) + if (is_wow64_key && !is_wow6432node( name )) { HKEY wow6432node = open_wow6432node( *subkey ); if (wow6432node) @@ -274,7 +202,6 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR return status; }
- /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) { @@ -312,6 +239,99 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK ac return status; }
+static NTSTATUS create_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, + const UNICODE_STRING *class, PULONG dispos ) +{ + 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 = (HANDLE)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 + { + 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, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, + const UNICODE_STRING *class, ULONG options, PULONG dispos ) +{ + HKEY subkey, root = attr->RootDirectory, subkey_root = root; + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + UNICODE_STRING name; + + *retkey = NULL; + + name.Buffer = attr->ObjectName->Buffer; + name.Length = attr->ObjectName->Length; + + while (name.Length) + { + status = open_subkey( &subkey, subkey_root, &name, options & REG_OPTION_OPEN_LINK, access ); + if (status) break; + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + + if (!status && (options & REG_OPTION_CREATE_LINK)) + { + NtClose( subkey_root ); + status = STATUS_OBJECT_NAME_COLLISION; + } + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + status = STATUS_SUCCESS; + while (!status && name.Length) + { + 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) + *retkey = subkey_root; + + return status; +} + /* create one of the HKEY_* special root keys */ static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) {
From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 2664d13f05a..b3865eb8467 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -150,6 +150,8 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR UNICODE_STRING str; NTSTATUS status = 0;
+ *subkey = 0; + attr.Length = sizeof(attr); attr.RootDirectory = (HANDLE)root; attr.ObjectName = &str; @@ -202,12 +204,30 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR return status; }
+/* wrapper for NtOpenKeyEx that handles Wow6432 nodes but also returns a key on error */ +static NTSTATUS unsafe_open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) +{ + HKEY subkey = 0, subkey_root = root; + NTSTATUS status = 0; + + while (!status && (name->Length || !subkey)) + { + status = open_subkey( &subkey, subkey_root, name, options, access ); + if (subkey && subkey_root && subkey_root != root) NtClose( subkey_root ); + if (subkey) subkey_root = subkey; + } + + *retkey = subkey_root; + + return status; +} + /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) { - HKEY subkey, subkey_root = root; UNICODE_STRING name; NTSTATUS status = 0; + HKEY subkey;
*retkey = NULL;
@@ -226,15 +246,11 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK ac name.Buffer = attr->ObjectName->Buffer; name.Length = attr->ObjectName->Length;
- while (!status && name.Length) - { - status = open_subkey( &subkey, subkey_root, &name, options, access ); - if (subkey_root && subkey_root != root) NtClose( subkey_root ); - subkey_root = subkey; - } - + status = unsafe_open_key( &subkey, root, &name, options, access ); if (!status) - *retkey = subkey_root; + *retkey = subkey; + else if (subkey && subkey != root) + NtClose( subkey );
return status; } @@ -293,21 +309,19 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES const UNICODE_STRING *class, ULONG options, PULONG dispos ) { HKEY subkey, root = attr->RootDirectory, subkey_root = root; - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; UNICODE_STRING name; + NTSTATUS status;
*retkey = NULL;
name.Buffer = attr->ObjectName->Buffer; name.Length = attr->ObjectName->Length;
- while (name.Length) - { - status = open_subkey( &subkey, subkey_root, &name, options & REG_OPTION_OPEN_LINK, access ); - if (status) break; - if (subkey_root && subkey_root != root) NtClose( subkey_root ); + status = unsafe_open_key( &subkey, subkey_root, &name, options & REG_OPTION_OPEN_LINK, access ); + if (!status || status == STATUS_OBJECT_NAME_NOT_FOUND) subkey_root = subkey; - } + else if (subkey && subkey != root) + NtClose( subkey );
if (!status && (options & REG_OPTION_CREATE_LINK)) {
From: Sven Baars sbaars@codeweavers.com
--- dlls/ntdll/tests/reg.c | 52 ++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/registry.c | 18 +++++++++++- include/wine/server_protocol.h | 4 ++- server/protocol.def | 1 + server/registry.c | 23 +++++++++++++++ server/request.h | 9 +++--- server/trace.c | 1 + 7 files changed, 102 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index 978d50dbd0d..bf1d715f46f 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -115,6 +115,12 @@ typedef enum _KEY_VALUE_INFORMATION_CLASS {
#endif
+typedef struct _KEY_FLAGS_INFORMATION{ + ULONG Unknown1; + ULONG Unknown2; + ULONG WowShare; +} KEY_FLAGS_INFORMATION, *PKEY_FLAGS_INFORMATION; + static BOOLEAN (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR); static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING); @@ -2135,6 +2141,7 @@ static void test_NtQueryKey(void) OBJECT_ATTRIBUTES attr; ULONG length, len; KEY_NAME_INFORMATION *info = NULL; + KEY_FLAGS_INFORMATION flags_info; KEY_CACHED_INFORMATION cached_info; UNICODE_STRING str; DWORD dw; @@ -2242,6 +2249,51 @@ static void test_NtQueryKey(void)
pNtClose(subkey2); pNtClose(subkey); + + status = pNtQueryKey(key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status); + ok(len == sizeof(flags_info), "got unexpected length %ld\n", len); + ok(flags_info.WowShare == 0, "flags_info.WowShare = %lu\n", flags_info.WowShare); + + pNtClose(key); + + pRtlCreateUnicodeStringFromAsciiz(&str, "\Registry\Machine\Software\Classes"); + attr.RootDirectory = 0; + status = pNtOpenKey(&key, KEY_READ, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status); + pRtlFreeUnicodeString(&str); + + status = pNtQueryKey(key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status); + ok(len == sizeof(flags_info), "got unexpected length %ld\n", len); + ok(flags_info.WowShare == 10, "flags_info.WowShare = %lu\n", flags_info.WowShare); + + pNtClose(key); + + pRtlCreateUnicodeStringFromAsciiz(&str, "\Registry\Machine\Software\Classes\Interface"); + attr.RootDirectory = 0; + status = pNtOpenKey(&key, KEY_READ, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status); + pRtlFreeUnicodeString(&str); + + status = pNtQueryKey(key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status); + ok(len == sizeof(flags_info), "got unexpected length %ld\n", len); + ok(flags_info.WowShare == 10, "flags_info.WowShare = %lu\n", flags_info.WowShare); + + pNtClose(key); + + pRtlCreateUnicodeStringFromAsciiz(&str, "\Registry\Machine\Software\Classes\Wow6432Node"); + attr.RootDirectory = 0; + status = pNtOpenKey(&key, KEY_READ, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status); + pRtlFreeUnicodeString(&str); + + status = pNtQueryKey(key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status); + ok(len == sizeof(flags_info), "got unexpected length %ld\n", len); + ok(flags_info.WowShare == 10, "flags_info.WowShare = %lu\n", flags_info.WowShare); + pNtClose(key); }
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 797e32a5bf1..aa99f5bb4de 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -232,7 +232,6 @@ NTSTATUS WINAPI NtRenameKey( HANDLE key, UNICODE_STRING *name ) return ret; }
- /****************************************************************************** * enumerate_key * @@ -242,6 +241,12 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i void *info, DWORD length, DWORD *result_len )
{ + typedef struct { + ULONG Unknown1; + ULONG Unknown2; + ULONG WowShare; + } KEY_FLAGS_INFORMATION; + NTSTATUS ret; void *data_ptr; size_t fixed_size; @@ -253,6 +258,7 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break; case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break; case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break; + case KeyFlagsInformation: data_ptr = ((KEY_FLAGS_INFORMATION *)info)+1; break; default: FIXME( "Information class %d not implemented\n", info_class ); return STATUS_INVALID_PARAMETER; @@ -339,6 +345,16 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i break; }
+ case KeyFlagsInformation: + { + KEY_FLAGS_INFORMATION keyinfo; + keyinfo.Unknown1 = 0; + keyinfo.Unknown2 = 0; + keyinfo.WowShare = reply->wowshare; + memcpy( info, &keyinfo, min( length, fixed_size ) ); + break; + } + default: break; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 472c0ea709d..fbdaf965a06 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2301,6 +2301,8 @@ struct enum_key_reply int values; int max_value; int max_data; + int wowshare; + char __pad_36[4]; timeout_t modif; data_size_t total; data_size_t namelen; @@ -6356,7 +6358,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 758 +#define SERVER_PROTOCOL_VERSION 759
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index 8c2fbeb4afe..0dba49f75d3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1791,6 +1791,7 @@ struct process_info int values; /* number of values */ int max_value; /* longest value name */ int max_data; /* longest value data */ + int wowshare; /* wowshare flags */ timeout_t modif; /* last modification time */ data_size_t total; /* total length needed for full name and class */ data_size_t namelen; /* length of key name in bytes */ diff --git a/server/registry.c b/server/registry.c index 03e5f20cae5..895a962d3a7 100644 --- a/server/registry.c +++ b/server/registry.c @@ -900,6 +900,17 @@ static struct key *create_key_recursive( struct key *root, const struct unicode_ return parent; }
+static int has_wowshare_parent( struct key *key ) +{ + if (!key) + return 0; + + if (key->wow6432node) + return (key->wow6432node->flags & KEY_WOWSHARE) ? 1 : 0; + + return has_wowshare_parent( get_parent( key ) ); +} + /* query information about a key or a subkey */ static void enum_key( struct key *key, int index, int info_class, struct enum_key_reply *reply ) { @@ -942,6 +953,7 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke reply->max_class = 0; reply->max_value = 0; reply->max_data = 0; + reply->wowshare = 0; break; case KeyFullInformation: case KeyCachedInformation: @@ -959,11 +971,22 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke reply->max_class = max_class; reply->max_value = max_value; reply->max_data = max_data; + reply->wowshare = 0; reply->namelen = namelen; if (info_class == KeyCachedInformation) classlen = 0; /* don't return any data, only its size */ namelen = 0; /* don't return name */ break; + case KeyFlagsInformation: + namelen = 0; + classlen = 0; + reply->max_subkey = 0; + reply->max_class = 0; + reply->max_value = 0; + reply->max_data = 0; + reply->wowshare = has_wowshare_parent(key) ? 10 : 0; + reply->namelen = 0; + break; default: set_error( STATUS_INVALID_PARAMETER ); return; diff --git a/server/request.h b/server/request.h index 089af79e199..befd1cf93f1 100644 --- a/server/request.h +++ b/server/request.h @@ -1209,10 +1209,11 @@ C_ASSERT( FIELD_OFFSET(struct enum_key_reply, max_class) == 16 ); C_ASSERT( FIELD_OFFSET(struct enum_key_reply, values) == 20 ); C_ASSERT( FIELD_OFFSET(struct enum_key_reply, max_value) == 24 ); C_ASSERT( FIELD_OFFSET(struct enum_key_reply, max_data) == 28 ); -C_ASSERT( FIELD_OFFSET(struct enum_key_reply, modif) == 32 ); -C_ASSERT( FIELD_OFFSET(struct enum_key_reply, total) == 40 ); -C_ASSERT( FIELD_OFFSET(struct enum_key_reply, namelen) == 44 ); -C_ASSERT( sizeof(struct enum_key_reply) == 48 ); +C_ASSERT( FIELD_OFFSET(struct enum_key_reply, wowshare) == 32 ); +C_ASSERT( FIELD_OFFSET(struct enum_key_reply, modif) == 40 ); +C_ASSERT( FIELD_OFFSET(struct enum_key_reply, total) == 48 ); +C_ASSERT( FIELD_OFFSET(struct enum_key_reply, namelen) == 52 ); +C_ASSERT( sizeof(struct enum_key_reply) == 56 ); C_ASSERT( FIELD_OFFSET(struct set_key_value_request, hkey) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_key_value_request, type) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_key_value_request, namelen) == 20 ); diff --git a/server/trace.c b/server/trace.c index a0076d5449b..301f1a0ff35 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2360,6 +2360,7 @@ static void dump_enum_key_reply( const struct enum_key_reply *req ) fprintf( stderr, ", values=%d", req->values ); fprintf( stderr, ", max_value=%d", req->max_value ); fprintf( stderr, ", max_data=%d", req->max_data ); + fprintf( stderr, ", wowshare=%d", req->wowshare ); dump_timeout( ", modif=", &req->modif ); fprintf( stderr, ", total=%u", req->total ); fprintf( stderr, ", namelen=%u", req->namelen );
From: Sven Baars sbaars@codeweavers.com
--- dlls/advapi32/tests/registry.c | 2 +- dlls/kernelbase/registry.c | 97 +++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index b4f0398b358..ecc71ec8db8 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2778,7 +2778,7 @@ static void test_redirection(void)
/* verify subkey is not present in native mode */ err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key); - ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err); + todo_wine_if(ptr_size == 64) ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err);
err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0); ok(err == ERROR_SUCCESS, "got %li\n", err); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index b3865eb8467..a4a3f667987 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -117,7 +117,7 @@ static HANDLE open_wow6432node( HANDLE key ) attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, L"Wow6432Node" ); - if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; + if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return key; return ret; }
@@ -140,6 +140,67 @@ static HKEY get_perflib_key( HANDLE key ) return key; }
+static BOOL is_shared( HKEY key ) +{ + NTSTATUS status; + DWORD len; + struct { + ULONG Unknown1; + ULONG Unknown2; + ULONG WowShare; + } flags_info; + + status = NtQueryKey( key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len ); + return (!status && flags_info.WowShare); +} + +static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ); + +static NTSTATUS open_shared_parent( HKEY *subkey, HKEY root, DWORD options, ACCESS_MASK access ) +{ + BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); + ACCESS_MASK access_64 = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY; + KEY_NAME_INFORMATION *info = NULL; + UNICODE_STRING str; + NTSTATUS status; + DWORD len; + + if (is_wow64_key && is_shared( root )) + { + /* Obtain the name of the root key */ + status = NtQueryKey( root, KeyNameInformation, info, 0, &len ); + if (status != STATUS_BUFFER_TOO_SMALL) return status; + + if (!(info = heap_alloc( len ))) + return STATUS_NO_MEMORY; + + /* Open the shared parent only if the key ends in a Wow6432Node */ + status = NtQueryKey( root, KeyNameInformation, info, len, &len ); + if (!status && info->NameLength / sizeof(WCHAR) >= 11) + { + str.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11; + str.Length = 11 * sizeof(WCHAR); + if (is_wow6432node( &str )) + { + root = 0; + str.Buffer = info->Name; + str.Length = info->NameLength - 11 * sizeof(WCHAR); + while (!status && str.Length) + { + status = open_subkey( subkey, root, &str, options & ~REG_OPTION_OPEN_LINK, access_64 ); + if (root) NtClose( root ); + root = *subkey; + } + heap_free( info ); + return status; + } + } + heap_free( info ); + } + + return STATUS_OBJECT_NAME_NOT_FOUND; +} + static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); @@ -177,6 +238,23 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR }
status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND && root) + { + HKEY shared_root; + + /* Try to open the shared parent if we can't find the key in the Wow6432Node */ + if (open_shared_parent( &shared_root, root, options, access )) + return STATUS_OBJECT_NAME_NOT_FOUND; + + attr.RootDirectory = (HANDLE)shared_root; + status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); + + if (!status) + NtClose( shared_root ); + else + *subkey = shared_root; + } + if (status == STATUS_PREDEFINED_HANDLE) { *subkey = get_perflib_key( *subkey ); @@ -193,7 +271,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; @@ -208,15 +286,30 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR static NTSTATUS unsafe_open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { HKEY subkey = 0, subkey_root = root; + BOOL was_wow6432node = TRUE; NTSTATUS status = 0;
+ if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name ) && is_shared( root )) + subkey_root = open_wow6432node( 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) + { + if (!open_shared_parent( &subkey, subkey_root, options, access )) + { + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + } + *retkey = subkey_root;
return status;
From: Sven Baars sbaars@codeweavers.com
--- dlls/advapi32/tests/registry.c | 17 ++++-------- dlls/kernelbase/registry.c | 49 +++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index ecc71ec8db8..fe84c0ef417 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2615,12 +2615,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 ); @@ -2632,8 +2629,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 ); @@ -2710,9 +2706,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, @@ -2720,8 +2714,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, @@ -2778,7 +2771,7 @@ static void test_redirection(void)
/* verify subkey is not present in native mode */ err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key); - todo_wine_if(ptr_size == 64) ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err); + ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err);
err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0); ok(err == ERROR_SUCCESS, "got %li\n", err); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index a4a3f667987..224e7b3cc37 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -282,6 +282,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; + UNICODE_STRING name; + NTSTATUS status; + DWORD len; + + /* Obtain the name of the root key */ + status = NtQueryKey( root, KeyNameInformation, buffer, sizeof(buffer), &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, buf_ptr, 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 that handles Wow6432 nodes but also returns a key on error */ static NTSTATUS unsafe_open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { @@ -289,7 +334,9 @@ static NTSTATUS unsafe_open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, BOOL was_wow6432node = TRUE; NTSTATUS status = 0;
- if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name ) && is_shared( root )) + 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 ) && is_shared( root )) subkey_root = open_wow6432node( root );
while (!status && (name->Length || !subkey))
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=126473
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w7u_adm (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w7u_el (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w8 (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w8adm (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w864 (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w1064v1507 (32 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w864 (64 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== w1064v1507 (64 bit report) ===
ntdll: reg.c:2263: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2267: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2269: Test failed: flags_info.WowShare = 0 reg.c:2276: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2280: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2282: Test failed: flags_info.WowShare = 0 reg.c:2289: Test failed: NtOpenKey Failed: 0xc000003a reg.c:2293: Test failed: NtQueryKey Failed: 0xc0000008 reg.c:2295: Test failed: flags_info.WowShare = 0
=== debian11 (32 bit report) ===
crypt32: store.c:1251: Test failed: Expected REG_OPENED_EXISTING_KEY, got 3 store.c:1359: Test failed: Expected ERROR_FILE_EXISTS, got 00000002
d3d9: stateblock: Timeout visual: Timeout
d3dcompiler_43: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3dcompiler_46: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3dcompiler_47: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3drm: d3drm: Timeout vector: Timeout
d3dx10_34: d3dx10: Timeout
d3dx10_35: d3dx10: Timeout
d3dx10_36: d3dx10: Timeout
d3dx10_37: d3dx10: Timeout
d3dx10_38: d3dx10: Timeout
d3dx10_39: d3dx10: Timeout
d3dx10_40: d3dx10: Timeout
d3dx10_41: d3dx10: Timeout
d3dx10_42: d3dx10: Timeout
d3dx10_43: d3dx10: Timeout
d3dx11_42: d3dx11: Timeout
d3dx11_43: d3dx11: Timeout
d3dx9_36: asm: Timeout core: Timeout effect: Timeout line: Timeout math: Timeout mesh: Timeout shader: Timeout surface: Timeout texture: Timeout volume: Timeout xfile: Timeout
ddrawex: ddrawex: Timeout surface: Timeout
ddraw: d3d: Timeout ddraw1: Timeout
Report validation errors: ddraw2: Timeout
=== debian11 (build log) ===
WineRunWineTest.pl:error: The task timed out
Ok, that clearly still needs some work. Good to know.