It turns out that in .NET Framework, the GAC has precedence over the appdomain paths (usually the exe path) when searching for libraries. Some applications (typically MonoGame packages) take advantage of this by shipping Mono libraries with the exe, which are ignored in .NET Framework and used in an included Linux Mono build. Those libraries break Wine Mono if they're loaded. This was a surprising behavior to me, but I verified it using an automated test in the Wine Mono test suite. To prevent this change from causing Mono's builtin libraries to interfere with application libraries with the same name, various Wine Mono specific libraries have been removed or renamed. Mono.Cecil has been left in place because it has a stable ABI, and the application's version is likely to be broken due to a Wine Mono bug.
As part of this work, I also added the ability to prevent loading from the Mono GAC, and ensured that the GlobalAssemblyCache property of the assembly, which indicates whether the library was loaded from the GAC, is set correctly.
From: Esme Povirk esme@codeweavers.com
--- dlls/appwiz.cpl/addons.c | 4 ++-- dlls/mscoree/mscoree_private.h | 2 +- tools/gitlab/test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index 57855648ff1..e69b47745f1 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif
-#define MONO_VERSION "7.4.0" +#define MONO_VERSION "8.0.0" #if defined(__i386__) || defined(__x86_64__) #define MONO_ARCH "x86" -#define MONO_SHA "6413ff328ebbf7ec7689c648feb3546d8102ded865079d1fbf0331b14b3ab0ec" +#define MONO_SHA "75b3f45dca1dc89857fe9e932da78710f64cc6d49ef1ab0c723a177085b4711b" #else #define MONO_ARCH "" #define MONO_SHA "???" diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 71e943d34c3..a06333b6874 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN;
-#define WINE_MONO_VERSION "7.4.0" +#define WINE_MONO_VERSION "8.0.0"
/* Mono embedding */ typedef struct _MonoDomain MonoDomain; diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index 490ca3b5b84..568addecb5c 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -7,7 +7,7 @@ variables: GIT_STRATEGY: none GECKO_VER: 2.47.4 - MONO_VER: 7.4.0 + MONO_VER: 8.0.0 cache: - key: wine-gecko-$GECKO_VER paths:
From: Esme Povirk esme@codeweavers.com
--- dlls/mscoree/metahost.c | 30 ++++++++++++++++++++++++------ dlls/mscoree/mscoree_private.h | 7 ++++++- 2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index c72f510c8ac..a9fb3be47d3 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -131,11 +131,13 @@ void (CDECL *mono_thread_manage)(void); void (CDECL *mono_trace_set_print_handler)(MonoPrintCallback callback); void (CDECL *mono_trace_set_printerr_handler)(MonoPrintCallback callback); static void (CDECL *wine_mono_install_assembly_preload_hook)(WineMonoAssemblyPreLoadFunc func, void *user_data); +static void (CDECL *wine_mono_install_assembly_preload_hook_v2)(WineMonoAssemblyPreLoadFunc func, void *user_data);
static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path);
static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data); static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, int *search_path, void *user_data); +static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data);
static void CDECL mono_shutdown_callback_fn(MonoProfiler *prof);
@@ -252,6 +254,7 @@ static HRESULT load_mono(LPCWSTR mono_path) LOAD_OPT_MONO_FUNCTION(mono_trace_set_print_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_printerr_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook, NULL); + LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook_v2, NULL);
#undef LOAD_OPT_MONO_FUNCTION
@@ -282,7 +285,9 @@ static HRESULT load_mono(LPCWSTR mono_path)
mono_config_parse(NULL);
- if (wine_mono_install_assembly_preload_hook) + if (wine_mono_install_assembly_preload_hook_v2) + wine_mono_install_assembly_preload_hook_v2(wine_mono_assembly_preload_hook_v2_fn, NULL); + else if (wine_mono_install_assembly_preload_hook) wine_mono_install_assembly_preload_hook(wine_mono_assembly_preload_hook_fn, NULL); else mono_install_assembly_preload_hook(mono_assembly_preload_hook_fn, NULL); @@ -1707,11 +1712,20 @@ static MonoAssembly* mono_assembly_try_load(WCHAR *path)
static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { - int dummy; - return wine_mono_assembly_preload_hook_fn(aname, assemblies_path, &dummy, user_data); + int flags = 0; + return wine_mono_assembly_preload_hook_v2_fn(aname, assemblies_path, &flags, user_data); }
static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, int *halt_search, void *user_data) +{ + int flags = 0; + MonoAssembly* result = wine_mono_assembly_preload_hook_v2_fn(aname, assemblies_path, &flags, user_data); + if (flags & WINE_PRELOAD_SKIP_PRIVATE_PATH) + *halt_search = 1; + return result; +} + +static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data) { HRESULT hr; MonoAssembly *result=NULL; @@ -1784,8 +1798,6 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * } }
- /* FIXME: We should search the given paths before the GAC. */ - if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) { stringnameW_size = MultiByteToWideChar(CP_UTF8, 0, stringname, -1, NULL, 0); @@ -1816,6 +1828,12 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * ERR("Failed to load %s, status=%u\n", debugstr_w(path), stat);
HeapFree(GetProcessHeap(), 0, pathA); + + if (result) + { + *flags |= WINE_PRELOAD_SET_GAC; + goto done; + } } } } @@ -1825,7 +1843,7 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * if ((search_flags & ASSEMBLY_SEARCH_PRIVATEPATH) == 0) { TRACE("skipping AppDomain search path due to override setting\n"); - *halt_search = 1; + *flags |= WINE_PRELOAD_SKIP_PRIVATE_PATH; }
done: diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index a06333b6874..50ed656a656 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -143,7 +143,12 @@ typedef enum {
typedef MonoAssembly* (CDECL *MonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
-typedef MonoAssembly* (CDECL *WineMonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, int *halt_search, void *user_data); +#define WINE_PRELOAD_CONTINUE 0 +#define WINE_PRELOAD_SKIP_PRIVATE_PATH 1 +#define WINE_PRELOAD_SKIP_GAC 2 +#define WINE_PRELOAD_SET_GAC 4 + +typedef MonoAssembly* (CDECL *WineMonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data);
typedef void (CDECL *MonoProfileFunc)(MonoProfiler *prof);
From: Esme Povirk esme@codeweavers.com
--- dlls/mscoree/metahost.c | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index a9fb3be47d3..309ad639d42 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -130,6 +130,7 @@ MonoThread* (CDECL *mono_thread_attach)(MonoDomain *domain); void (CDECL *mono_thread_manage)(void); void (CDECL *mono_trace_set_print_handler)(MonoPrintCallback callback); void (CDECL *mono_trace_set_printerr_handler)(MonoPrintCallback callback); +static MonoAssembly* (CDECL *wine_mono_assembly_load_from_gac)(MonoAssemblyName *aname, MonoImageOpenStatus *status, int refonly); static void (CDECL *wine_mono_install_assembly_preload_hook)(WineMonoAssemblyPreLoadFunc func, void *user_data); static void (CDECL *wine_mono_install_assembly_preload_hook_v2)(WineMonoAssemblyPreLoadFunc func, void *user_data);
@@ -253,6 +254,7 @@ static HRESULT load_mono(LPCWSTR mono_path) LOAD_OPT_MONO_FUNCTION(mono_set_crash_chaining, set_crash_chaining_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_print_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_printerr_handler, set_print_handler_dummy); + LOAD_OPT_MONO_FUNCTION(wine_mono_assembly_load_from_gac, NULL); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook, NULL); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook_v2, NULL);
@@ -1375,16 +1377,19 @@ HRESULT CLRMetaHostPolicy_CreateInstance(REFIID riid, void **ppobj) * Assembly search override settings: * * WINE_MONO_OVERRIDES=*,Gac=n - * Never search the GAC for libraries. + * Never search the Windows GAC for libraries. + * + * WINE_MONO_OVERRIDES=*,MonoGac=n + * Never search the Mono GAC for libraries. * * WINE_MONO_OVERRIDES=*,PrivatePath=n * Never search the AppDomain search path for libraries. * * WINE_MONO_OVERRIDES=Microsoft.Xna.Framework,Gac=n - * Never search the GAC for Microsoft.Xna.Framework + * Never search the Windows GAC for Microsoft.Xna.Framework * * WINE_MONO_OVERRIDES=Microsoft.Xna.Framework.*,Gac=n;Microsoft.Xna.Framework.GamerServices,Gac=y - * Never search the GAC for Microsoft.Xna.Framework, or any library starting + * Never search the Windows GAC for Microsoft.Xna.Framework, or any library starting * with Microsoft.Xna.Framework, except for Microsoft.Xna.Framework.GamerServices */
@@ -1392,7 +1397,8 @@ HRESULT CLRMetaHostPolicy_CreateInstance(REFIID riid, void **ppobj) #define ASSEMBLY_SEARCH_GAC 1 #define ASSEMBLY_SEARCH_UNDEFINED 2 #define ASSEMBLY_SEARCH_PRIVATEPATH 4 -#define ASSEMBLY_SEARCH_DEFAULT (ASSEMBLY_SEARCH_GAC|ASSEMBLY_SEARCH_PRIVATEPATH) +#define ASSEMBLY_SEARCH_MONOGAC 8 +#define ASSEMBLY_SEARCH_DEFAULT (ASSEMBLY_SEARCH_GAC|ASSEMBLY_SEARCH_PRIVATEPATH|ASSEMBLY_SEARCH_MONOGAC)
typedef struct override_entry { char *name; @@ -1441,6 +1447,14 @@ static void parse_override_entry(override_entry *entry, const char *string, int entry->flags &= ~ASSEMBLY_SEARCH_GAC; } break; + case 7: + if (!_strnicmp(string, "monogac", 7)) { + if (IS_OPTION_TRUE(*value)) + entry->flags |= ASSEMBLY_SEARCH_MONOGAC; + else if (IS_OPTION_FALSE(*value)) + entry->flags &= ~ASSEMBLY_SEARCH_MONOGAC; + } + break; case 11: if (!_strnicmp(string, "privatepath", 11)) { if (IS_OPTION_TRUE(*value)) @@ -1568,7 +1582,7 @@ static DWORD get_basename_search_flags(const char *basename, MonoAssemblyName *a if (strcmp(basename, "Microsoft.Xna.Framework.*") == 0 && mono_assembly_name_get_version(aname, NULL, NULL, NULL) == 4) /* Use FNA as a replacement for XNA4. */ - return 0; + return ASSEMBLY_SEARCH_MONOGAC;
return ASSEMBLY_SEARCH_UNDEFINED; } @@ -1840,6 +1854,26 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyNam else TRACE("skipping Windows GAC search due to override setting\n");
+ if (wine_mono_assembly_load_from_gac) + { + if (search_flags & ASSEMBLY_SEARCH_MONOGAC) + { + result = wine_mono_assembly_load_from_gac (aname, &stat, FALSE); + + if (result) + { + TRACE("found in Mono GAC\n"); + *flags |= WINE_PRELOAD_SET_GAC; + goto done; + } + } + else + { + *flags |= WINE_PRELOAD_SKIP_GAC; + TRACE("skipping Mono GAC search due to override setting\n"); + } + } + if ((search_flags & ASSEMBLY_SEARCH_PRIVATEPATH) == 0) { TRACE("skipping AppDomain search path due to override setting\n");
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 full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=132773
Your paranoid android.
=== debian11 (build log) ===
WineRunWineTest.pl:error: The task timed out
=== debian11b (build log) ===
Task: Could not create the wow64 wineprefix: Failed to disable the crash dialogs: Task: WineTest did not produce the wow64 report
Seems like the test failure is in imm32:imm32? I don't think that's related.