From 6c56a413abd7413c10a90e8f08659148f50972eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 6 Jul 2024 19:45:28 +0200 Subject: [PATCH] win32: unregister window class on dll detach Window classes are global per process, but they are associated with the module that registered them. Documentation is clear that it is the DLL's responsibility to unregister its own classes: No window classes registered by a DLL are unregistered when the DLL is unloaded. A DLL must explicitly unregister its classes when it is unloaded. See: https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-registerclassw Using a window class after the DLL is unloaded would result in access violation errors. This is not that important for libmpv, where it is unlikely someone would use the "mpv" window class externally. The real issue comes from the fact that reloading libmpv would fail to register the class (as it still exists) and consequently fail to create a window. This commit fixes the operability of libmpv after reloading it. Fixes: #11638 --- video/out/w32_common.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/video/out/w32_common.c b/video/out/w32_common.c index dc796b0ccd..0658422ba5 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -20,10 +20,12 @@ #include #include +#define _DECL_DLLMAIN #include #include #include #include +#include #include #include @@ -48,6 +50,8 @@ #include "misc/rendezvous.h" #include "mpv_talloc.h" +#define MPV_WINDOW_CLASS_NAME L"mpv" + EXTERN_C IMAGE_DOS_HEADER __ImageBase; #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) @@ -1802,7 +1806,7 @@ static void register_window_class(void) .hIcon = LoadIconW(HINST_THISCOMPONENT, L"IDI_ICON1"), .hCursor = LoadCursor(NULL, IDC_ARROW), .hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH), - .lpszClassName = L"mpv", + .lpszClassName = MPV_WINDOW_CLASS_NAME, }); } @@ -2036,7 +2040,7 @@ static MP_THREAD_VOID gui_thread(void *ptr) if (w32->parent) { RECT r; GetClientRect(w32->parent, &r); - CreateWindowExW(WS_EX_NOPARENTNOTIFY, (LPWSTR)MAKEINTATOM(cls), L"mpv", + CreateWindowExW(WS_EX_NOPARENTNOTIFY, (LPWSTR)MAKEINTATOM(cls), MPV_WINDOW_CLASS_NAME, WS_CHILD | WS_VISIBLE, 0, 0, r.right, r.bottom, w32->parent, 0, HINST_THISCOMPONENT, w32); @@ -2044,7 +2048,7 @@ static MP_THREAD_VOID gui_thread(void *ptr) if (w32->window) install_parent_hook(w32); } else { - CreateWindowExW(0, (LPWSTR)MAKEINTATOM(cls), L"mpv", + CreateWindowExW(0, (LPWSTR)MAKEINTATOM(cls), MPV_WINDOW_CLASS_NAME, update_style(w32, 0), CW_USEDEFAULT, SW_HIDE, 100, 100, 0, 0, HINST_THISCOMPONENT, w32); } @@ -2483,3 +2487,10 @@ void vo_w32_set_transparency(struct vo *vo, bool enable) DwmEnableBlurBehindWindow(w32->window, &dbb); } } + +BOOL WINAPI DllMain(HANDLE dll, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_DETACH && window_class) + UnregisterClassW(MPV_WINDOW_CLASS_NAME, HINST_THISCOMPONENT); + return TRUE; +}