Previously, a plugin author needed an implementation of the __pfnDliFailureHook2 or __pfnDliNotifyHook2 hook in the plugin. Now all they need is a null exported pointer with the right name (win32_common.c). If QEMU finds this, it will set it to the hook function, which has now moved into qemu (os-win32.c). --- contrib/plugins/win32_linker.c | 23 +++-------------------- include/sysemu/os-win32.h | 25 +++++++++++++++++++++++++ os-win32.c | 33 +++++++++++++++++++++++++++++++++ plugins/loader.c | 3 +++ 4 files changed, 64 insertions(+), 20 deletions(-)
diff --git a/contrib/plugins/win32_linker.c b/contrib/plugins/win32_linker.c index 7534b2b8bf..619fdd38c8 100644 --- a/contrib/plugins/win32_linker.c +++ b/contrib/plugins/win32_linker.c @@ -4,8 +4,8 @@ * This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here: * https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification * It gets called when a delay-loaded DLL encounters various errors. - * We handle the specific case of a DLL looking for a "qemu.exe", - * and give it the running executable (regardless of what it is named). + * QEMU will set it to a function which handles the specific case of a DLL looking for + * a "qemu.exe", and give it the running executable (regardless of what it is named). * * This work is licensed under the terms of the GNU LGPL, version 2 or later. * See the COPYING.LIB file in the top-level directory. @@ -14,21 +14,4 @@ #include <windows.h> #include <delayimp.h> -FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli); - - -PfnDliHook __pfnDliFailureHook2 = dll_failure_hook; - -FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) { - if (dliNotify == dliFailLoadLib) { - /* If the failing request was for qemu.exe, ... */ - if (strcmp(pdli->szDll, "qemu.exe") == 0) { - /* Then pass back a pointer to the top level module. */ - HMODULE top = GetModuleHandle(NULL); - return (FARPROC) top; - } - } - /* Otherwise we can't do anything special. */ - return 0; -} - +__declspec(dllexport) PfnDliHook __pfnDliNotifyHook2 = NULL; diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 1047d260cb..0f698554b2 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -30,6 +30,8 @@ #include <windows.h> #include <ws2tcpip.h> #include "qemu/typedefs.h" +#include <delayimp.h> +#include <gmodule.h> #ifdef HAVE_AFUNIX_H #include <afunix.h> @@ -265,6 +267,29 @@ win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*, void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp); void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp); + +/* dll_delaylink_hook: + * @dliNotify: Type of event that caused this callback. + * @pdli: Extra data about the DLL being loaded + * + * For more info on the arguments and when this gets invoked see + * https://learn.microsoft.com/en-us/cpp/build/reference/understanding-the-helper-function + * + * This is to be used on windows as the target of a __pfnDliNotifyHook2 or __pfnDliFailureHook2 + * hook. If the DLL being loaded is 'qemu.exe', it instead passes back a pointer to the main + * executable This gets set into plugins to assist with the plugins delay-linking back to the main + * executable, if they define an appropriate symbol. */ +FARPROC WINAPI dll_delaylink_hook(unsigned dliNotify, PDelayLoadInfo pdli); + +/* set_dll_delaylink_hook: + * @mod: pointer to the DLL being loaded + * + * takes a pointer to a loaded plugin DLL, and tries to find a __pfnDliNotifyHook2 or + * __pfnDliFailureHook2 hook. If it finds either one, and its value is null, it sets it to the + * address fo dll_delaylink_hook. + */ +void set_dll_delaylink_hook(GModule *mod); + #ifdef __cplusplus } #endif diff --git a/os-win32.c b/os-win32.c index 725ad652e8..4a113d1d10 100644 --- a/os-win32.c +++ b/os-win32.c @@ -60,3 +60,36 @@ void os_set_line_buffering(void) setbuf(stdout, NULL); setbuf(stderr, NULL); } + +FARPROC WINAPI dll_delaylink_hook(unsigned dliNotify, PDelayLoadInfo pdli) { + /* If we just tried, or are about to try to load a DLL ... */ + if (dliNotify == dliFailLoadLib || dliNotify == dliNotePreLoadLibrary) { + /* ... if the failing request was for qemu.exe, ... */ + if (strcmp(pdli->szDll, "qemu.exe") == 0) { + /* ... then pass back a pointer to the top level module. */ + HMODULE top = GetModuleHandle(NULL); + return (FARPROC) top; + } + } + /* Otherwise we can't do anything special. */ + return 0; +} +void set_dll_delaylink_hook(GModule *mod) { + /* find the __pfnDliFailureHook2 symbol in the DLL. + * if found, set it to our handler. + */ + gpointer sym; + PfnDliHook *hook; + if (g_module_symbol(mod, "__pfnDliFailureHook2", &sym)) { + hook = (PfnDliHook*) sym; + if (hook != NULL && *hook == NULL) { + *hook = &dll_delaylink_hook; + } + } + if (g_module_symbol(mod, "__pfnDliNotifyHook2", &sym)) { + hook = (PfnDliHook*) sym; + if (hook != NULL && *hook == NULL) { + *hook = &dll_delaylink_hook; + } + } +} diff --git a/plugins/loader.c b/plugins/loader.c index 734c11cae0..7ead9b26e4 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -241,6 +241,9 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, E } QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry); ctx->installing = true; + #ifdef CONFIG_WIN32 + set_dll_delaylink_hook(ctx->handle); + #endif rc = install(ctx->id, info, desc->argc, desc->argv); ctx->installing = false; if (rc) { -- 2.42.0.windows.1