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
This commit is contained in:
Kacper Michajłow 2024-07-06 19:45:28 +02:00
parent d448598588
commit 6c56a413ab
1 changed files with 14 additions and 3 deletions

View File

@ -20,10 +20,12 @@
#include <stdatomic.h>
#include <stdio.h>
#define _DECL_DLLMAIN
#include <windows.h>
#include <windowsx.h>
#include <dwmapi.h>
#include <ole2.h>
#include <process.h>
#include <shobjidl.h>
#include <avrt.h>
@ -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;
}