[PATCH 0/4] MR9822: Fix possible EA launcher hangs.
Registering window classes in DllMain() is prone to deadlocks. Tests show that comctl32 window classes should probably be registered in RegisterClassNameW(). Fix possible EA launcher hangs due to deadlocks. A deadlock can happen, like the following, based on Tim Clem's findings. Say there are two threads, T1 and T2. T1: does some COM stuff that results in registering the window class OleMainThreadWndClass. T1: NtUserRegisterClassExWOW() does get_desktop_window(). Because this is not a built-in class. T1: doesn't yet have a desktop window, so it makes one and calls register_builtin_classes(). T1: starts the pthread_once in register_builtin_classes() to actually register the classes. T1: starts calling NtUserRegisterClassExWOW() with its classes. T2: loads comctl32.dll, calls its PROCESS_ATTACH. It grabs the loader lock. T2: comctl32's DllMain starts registering its classes. T2: comctl32's attempts to register classes also call get_desktop_window(). T2: get_desktop_window hits the pthread_once in register_builtin_classes() and starts waiting for T1 to finish it. T1: some built-in class registration results in a LoadImageW call for a class's cursor. T1: LoadImage has to grab a resource, so it tries to grab the loader lock. T1: the loader lock is held by T2. Deadlock; T2 is waiting on T1, which is waiting on T2. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822
From: Zhiyi Zhang <zzhang@codeweavers.com> --- dlls/comctl32/tests/misc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index c61b71b6309..e69eeed3ac2 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -404,12 +404,13 @@ static void check_class( const char *name, int must_exist, UINT style, UINT igno HWND hwnd; DWORD objid; + todo_wine_if(!strcmp(name, "flatsb_class32")) ok( must_exist, "System class %s should %sexist\n", name, must_exist ? "" : "NOT " ); todo_wine_if(!strcmp(name, "ScrollBar") || (!strcmp(name, "tooltips_class32") && v6)) ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n", name, ~wc.style & style, wc.style, style ); - todo_wine_if((!strcmp(name, "tooltips_class32") && v6) || !strcmp(name, "SysLink")) + todo_wine_if((!strcmp(name, "tooltips_class32") && v6) || !strcmp(name, "SysLink") || !strcmp(name, "flatsb_class32")) ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n", name, wc.style & ~style, wc.style, style ); ok( !wc.hInstance, "System class %s has hInstance %p\n", name, wc.hInstance ); @@ -474,6 +475,7 @@ static void test_comctl32_classes(BOOL v6) check_class(WC_TREEVIEWA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE, 0x10019, FALSE); check_class(UPDOWN_CLASSA, 1, CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE, 0x10016, FALSE); check_class("SysLink", v6, CS_GLOBALCLASS, 0, FALSE, 0, FALSE); + check_class("flatsb_class32", 0, 0, 0, FALSE, 0, FALSE); } struct wm_themechanged_test -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9822
From: Zhiyi Zhang <zzhang@codeweavers.com> There is no such window class on Windows. I checked on Windows 10, XP and even Windows 95. The window class was added by 638f169b in 1999. --- dlls/comctl32/comctl32.h | 2 -- dlls/comctl32/commctrl.c | 2 -- dlls/comctl32/flatsb.c | 63 ---------------------------------------- include/commctrl.h | 11 ------- 4 files changed, 78 deletions(-) diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index a3b683d4410..bf3179350c0 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -254,8 +254,6 @@ extern void COMBOLBOX_Register(void); extern void DATETIME_Register(void); extern void DATETIME_Unregister(void); extern void EDIT_Register(void); -extern void FLATSB_Register(void); -extern void FLATSB_Unregister(void); extern void HEADER_Register(void); extern void HEADER_Unregister(void); extern void HOTKEY_Register(void); diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index 9bf342ea800..0eb81dcccf5 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -189,7 +189,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) ANIMATE_Register (); COMBOEX_Register (); DATETIME_Register (); - FLATSB_Register (); HEADER_Register (); HOTKEY_Register (); IPADDRESS_Register (); @@ -218,7 +217,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) ANIMATE_Unregister (); COMBOEX_Unregister (); DATETIME_Unregister (); - FLATSB_Unregister (); HEADER_Unregister (); HOTKEY_Unregister (); IPADDRESS_Unregister (); diff --git a/dlls/comctl32/flatsb.c b/dlls/comctl32/flatsb.c index 1cedca98a6c..76dedd60a43 100644 --- a/dlls/comctl32/flatsb.c +++ b/dlls/comctl32/flatsb.c @@ -222,66 +222,3 @@ FlatSB_SetScrollRange(HWND hwnd, int nBar, INT min, INT max, BOOL bRedraw) { return SetScrollRange(hwnd, nBar, min, max, bRedraw); } - - -static LRESULT -FlatSB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("[%p] wParam %Ix, lParam %Ix\n", hwnd, wParam, lParam); - return 0; -} - - -static LRESULT -FlatSB_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("[%p] wParam %Ix, lParam %Ix\n", hwnd, wParam, lParam); - return 0; -} - - -static LRESULT WINAPI -FlatSB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (!GetWindowLongPtrW(hwnd, 0) && (uMsg != WM_CREATE)) - return DefWindowProcW( hwnd, uMsg, wParam, lParam ); - - switch (uMsg) - { - case WM_CREATE: - return FlatSB_Create (hwnd, wParam, lParam); - - case WM_DESTROY: - return FlatSB_Destroy (hwnd, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) - ERR("unknown msg %04x, wp %#Ix, lp %#Ix\n", uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -FLATSB_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = FlatSB_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(FLATSB_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = FLATSB_CLASSW; - - RegisterClassW (&wndClass); -} - - -VOID -FLATSB_Unregister (void) -{ - UnregisterClassW (FLATSB_CLASSW, NULL); -} diff --git a/include/commctrl.h b/include/commctrl.h index 5a67c1284a0..6030b885a34 100644 --- a/include/commctrl.h +++ b/include/commctrl.h @@ -643,17 +643,6 @@ typedef struct tagTRACKMOUSEEVENT { WINCOMMCTRLAPI BOOL WINAPI _TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); -/* Flat Scrollbar control */ - -#define FLATSB_CLASSA "flatsb_class32" -#if defined(_MSC_VER) || defined(__MINGW32__) -# define FLATSB_CLASSW L"flatsb_class32" -#else -static const WCHAR FLATSB_CLASSW[] = { 'f','l','a','t','s','b','_', - 'c','l','a','s','s','3','2',0 }; -#endif -#define FLATSB_CLASS WINELIB_NAME_AW(FLATSB_CLASS) - #define WSB_PROP_CYVSCROLL __MSABI_LONG(0x00000001) #define WSB_PROP_CXHSCROLL __MSABI_LONG(0x00000002) #define WSB_PROP_CYHSCROLL __MSABI_LONG(0x00000004) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9822
From: Zhiyi Zhang <zzhang@codeweavers.com> --- dlls/comctl32/tests/misc.c | 55 +++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index e69eeed3ac2..0d8feefd8d5 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -1337,29 +1337,60 @@ static void test_version(BOOL v6) static void test_RegisterClassNameW(BOOL v6) { - static const WCHAR *class_names[] = + static const struct + { + const WCHAR *class_name; + BOOL v6_only; + } + tests[] = { - L"Button", - L"ComboBox", - L"ComboLBox", - L"Edit", - L"ListBox", - L"Static", + {WC_BUTTONW, TRUE}, + {WC_COMBOBOXW, TRUE}, + {L"ComboLBox", TRUE}, + {WC_EDITW, TRUE}, + {WC_LINK, TRUE}, + {WC_LISTBOXW, TRUE}, + {WC_STATICW, TRUE}, + {ANIMATE_CLASSW}, + {WC_COMBOBOXEXW}, + {DATETIMEPICK_CLASSW}, + {WC_HEADERW}, + {HOTKEY_CLASSW}, + {WC_IPADDRESSW}, + {WC_LISTVIEWW}, + {MONTHCAL_CLASSW}, + {WC_NATIVEFONTCTLW}, + {WC_PAGESCROLLERW}, + {PROGRESS_CLASSW}, + {REBARCLASSNAMEW}, + {STATUSCLASSNAMEW}, + {WC_TABCONTROLW}, + {TOOLBARCLASSNAMEW}, + {TOOLTIPS_CLASSW}, + {TRACKBAR_CLASSW}, + {WC_TREEVIEWW}, + {UPDOWN_CLASSW}, }; unsigned int i; BOOL ret; winetest_push_context("v%d", v6 ? 6 : 5); - for (i = 0; i < ARRAY_SIZE(class_names); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { - ret = pRegisterClassNameW(class_names[i]); - if (v6) - ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(class_names[i]), GetLastError()); + ret = pRegisterClassNameW(tests[i].class_name); + if (!v6 && tests[i].v6_only) + ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(tests[i].class_name)); else - ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(class_names[i])); + todo_wine_if(i > 5) + ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(tests[i].class_name), GetLastError()); } + /* Test registering an already registered class */ + ret = pRegisterClassNameW(ANIMATE_CLASSW); + todo_wine + ok(ret, "RegisterClassNameW failed, error %lu.\n", GetLastError()); + winetest_pop_context(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9822
From: Zhiyi Zhang <zzhang@codeweavers.com> Registering window classes in DllMain() is prone to deadlocks. Tests show that comctl32 window classes should probably be registered in RegisterClassNameW(). Fix possible EA launcher hangs due to deadlocks. A deadlock can happen, like the following, based on Tim Clem's findings. Say there are two threads, T1 and T2. T1: does some COM stuff that results in registering the window class OleMainThreadWndClass. T1: NtUserRegisterClassExWOW() does get_desktop_window(). Because this is not a built-in class. T1: doesn't yet have a desktop window, so it makes one and calls register_builtin_classes(). T1: starts the pthread_once in register_builtin_classes() to actually register the classes. T1: starts calling NtUserRegisterClassExWOW() with its classes. T2: loads comctl32.dll, calls its PROCESS_ATTACH. It grabs the loader lock. T2: comctl32's DllMain starts registering its classes. T2: comctl32's attempts to register classes also call get_desktop_window(). T2: get_desktop_window hits the pthread_once in register_builtin_classes() and starts waiting for T1 to finish it. T1: some built-in class registration results in a LoadImageW call for a class's cursor. T1: LoadImage has to grab a resource, so it tries to grab the loader lock. T1: the loader lock is held by T2. Deadlock; T2 is waiting on T1, which is waiting on T2. --- dlls/comctl32/animate.c | 6 -- dlls/comctl32/comboex.c | 6 -- dlls/comctl32/comctl32.h | 37 +++------ dlls/comctl32/commctrl.c | 154 +++++++++++++++---------------------- dlls/comctl32/datetime.c | 7 -- dlls/comctl32/header.c | 7 -- dlls/comctl32/hotkey.c | 7 -- dlls/comctl32/ipaddress.c | 6 -- dlls/comctl32/listview.c | 15 ---- dlls/comctl32/monthcal.c | 7 -- dlls/comctl32/nativefont.c | 7 -- dlls/comctl32/pager.c | 7 -- dlls/comctl32/progress.c | 11 --- dlls/comctl32/rebar.c | 7 -- dlls/comctl32/status.c | 13 ---- dlls/comctl32/tab.c | 7 -- dlls/comctl32/tests/misc.c | 2 - dlls/comctl32/toolbar.c | 7 -- dlls/comctl32/tooltips.c | 3 +- dlls/comctl32/trackbar.c | 6 -- dlls/comctl32/treeview.c | 8 -- dlls/comctl32/updown.c | 11 --- dlls/comctl32_v6/syslink.c | 11 --- 23 files changed, 74 insertions(+), 278 deletions(-) diff --git a/dlls/comctl32/animate.c b/dlls/comctl32/animate.c index a3603b8bfbe..436faf920b4 100644 --- a/dlls/comctl32/animate.c +++ b/dlls/comctl32/animate.c @@ -971,9 +971,3 @@ void ANIMATE_Register(void) RegisterClassW(&wndClass); } - - -void ANIMATE_Unregister(void) -{ - UnregisterClassW(ANIMATE_CLASSW, NULL); -} diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c index 5dc6b8d4ca0..7765df893cb 100644 --- a/dlls/comctl32/comboex.c +++ b/dlls/comctl32/comboex.c @@ -2173,9 +2173,3 @@ void COMBOEX_Register (void) RegisterClassW (&wndClass); } - - -void COMBOEX_Unregister (void) -{ - UnregisterClassW (WC_COMBOBOXEXW, NULL); -} diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index bf3179350c0..a71374d9ee9 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -244,54 +244,35 @@ BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2); HRGN set_control_clipping(HDC hdc, const RECT *rect); -extern void ANIMATE_Register(void); -extern void ANIMATE_Unregister(void); +#if __WINE_COMCTL32_VERSION == 6 extern void BUTTON_Register(void); extern void COMBO_Register(void); -extern void COMBOEX_Register(void); -extern void COMBOEX_Unregister(void); extern void COMBOLBOX_Register(void); -extern void DATETIME_Register(void); -extern void DATETIME_Unregister(void); extern void EDIT_Register(void); +extern void LISTBOX_Register(void); +extern void SYSLINK_Register(void); +extern void STATIC_Register(void); +#endif +extern void ANIMATE_Register(void); +extern void COMBOEX_Register(void); +extern void DATETIME_Register(void); extern void HEADER_Register(void); -extern void HEADER_Unregister(void); extern void HOTKEY_Register(void); -extern void HOTKEY_Unregister(void); extern void IPADDRESS_Register(void); -extern void IPADDRESS_Unregister(void); -extern void LISTBOX_Register(void); extern void LISTVIEW_Register(void); -extern void LISTVIEW_Unregister(void); extern void MONTHCAL_Register(void); -extern void MONTHCAL_Unregister(void); extern void NATIVEFONT_Register(void); -extern void NATIVEFONT_Unregister(void); extern void PAGER_Register(void); -extern void PAGER_Unregister(void); extern void PROGRESS_Register(void); -extern void PROGRESS_Unregister(void); extern void REBAR_Register(void); -extern void REBAR_Unregister(void); -extern void STATIC_Register(void); extern void STATUS_Register(void); -extern void STATUS_Unregister(void); -#if __WINE_COMCTL32_VERSION == 6 -extern void SYSLINK_Register(void); -extern void SYSLINK_Unregister(void); -#endif extern void TAB_Register(void); -extern void TAB_Unregister(void); extern void TOOLBAR_Register(void); -extern void TOOLBAR_Unregister(void); extern void TOOLTIPS_Register(void); -extern void TOOLTIPS_Unregister(void); +extern void TOOLTIPS_AfterUnregister(void); extern void TRACKBAR_Register(void); -extern void TRACKBAR_Unregister(void); extern void TREEVIEW_Register(void); -extern void TREEVIEW_Unregister(void); extern void UPDOWN_Register(void); -extern void UPDOWN_Unregister(void); int MONTHCAL_MonthLength(int month, int year); diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index 0eb81dcccf5..a4edda7de2a 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -91,60 +91,82 @@ static const WORD wPattern55AA[] = static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo"; +static struct +{ + const WCHAR *name; + void (*fn_register)(void); + void (*fn_after_unregister)(void); + BOOL registered; +} +classes[] = +{ #if __WINE_COMCTL32_VERSION == 6 -static void unregister_versioned_classes(void) + {WC_BUTTONW, BUTTON_Register}, + {WC_COMBOBOXW, COMBO_Register}, + {L"ComboLBox", COMBOLBOX_Register}, + {WC_EDITW, EDIT_Register}, + {WC_LINK, SYSLINK_Register}, + {WC_LISTBOXW, LISTBOX_Register}, + {WC_STATICW, STATIC_Register}, +#endif + {ANIMATE_CLASSW, ANIMATE_Register}, + {WC_COMBOBOXEXW, COMBOEX_Register}, + {DATETIMEPICK_CLASSW, DATETIME_Register}, + {WC_HEADERW, HEADER_Register}, + {HOTKEY_CLASSW, HOTKEY_Register}, + {WC_IPADDRESSW, IPADDRESS_Register}, + {WC_LISTVIEWW, LISTVIEW_Register}, + {MONTHCAL_CLASSW, MONTHCAL_Register}, + {WC_NATIVEFONTCTLW, NATIVEFONT_Register}, + {WC_PAGESCROLLERW, PAGER_Register}, + {PROGRESS_CLASSW, PROGRESS_Register}, + {REBARCLASSNAMEW, REBAR_Register}, + {STATUSCLASSNAMEW, STATUS_Register}, + {WC_TABCONTROLW, TAB_Register}, + {TOOLBARCLASSNAMEW, TOOLBAR_Register}, + {TOOLTIPS_CLASSW, TOOLTIPS_Register, TOOLTIPS_AfterUnregister}, + {TRACKBAR_CLASSW, TRACKBAR_Register}, + {WC_TREEVIEWW, TREEVIEW_Register}, + {UPDOWN_CLASSW, UPDOWN_Register} +}; + +static void unregister_classes(void) { -#define VERSION "6.0.2600.2982!" - static const char *classes[] = + for (unsigned int i = 0; i < ARRAY_SIZE(classes); i++) { - VERSION WC_BUTTONA, - VERSION WC_COMBOBOXA, - VERSION "ComboLBox", - VERSION WC_EDITA, - VERSION WC_LISTBOXA, - VERSION WC_STATICA, - }; - int i; + if (classes[i].registered) + { +#if __WINE_COMCTL32_VERSION == 6 + WCHAR versioned_class[40]; - for (i = 0; i < ARRAY_SIZE(classes); i++) - UnregisterClassA(classes[i], NULL); + wcscpy(versioned_class, L"6.0.2600.2982!"); + wcscat(versioned_class, classes[i].name); + UnregisterClassW(versioned_class, NULL); +#else + UnregisterClassW(classes[i].name, NULL); +#endif -#undef VERSION + if (classes[i].fn_after_unregister) + classes[i].fn_after_unregister(); + } + } } -#endif /* __WINE_COMCTL32_VERSION == 6 */ -BOOL WINAPI RegisterClassNameW(const WCHAR *class) +BOOL WINAPI RegisterClassNameW(const WCHAR *class_name) { -#if __WINE_COMCTL32_VERSION == 6 - static const struct - { - const WCHAR nameW[16]; - void (*fn_register)(void); - } - classes[] = - { - { L"Button", BUTTON_Register }, - { L"ComboBox", COMBO_Register }, - { L"ComboLBox", COMBOLBOX_Register }, - { L"Edit", EDIT_Register }, - { L"ListBox", LISTBOX_Register }, - { L"Static", STATIC_Register }, - }; - - int min = 0, max = ARRAY_SIZE(classes) - 1; - - while (min <= max) + for (unsigned int i = 0; i < ARRAY_SIZE(classes); i++) { - int res, pos = (min + max) / 2; - if (!(res = wcsicmp(class, classes[pos].nameW))) + if (!wcsicmp(class_name, classes[i].name)) { - classes[pos].fn_register(); + if (!classes[i].registered) + { + classes[i].fn_register(); + classes[i].registered = TRUE; + } + return TRUE; } - if (res < 0) max = pos - 1; - else min = pos + 1; } -#endif /* __WINE_COMCTL32_VERSION == 6 */ return FALSE; } @@ -184,61 +206,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) /* Get all the colors at DLL load */ COMCTL32_RefreshSysColors(); - - /* like comctl32 5.82+ register all the common control classes */ - ANIMATE_Register (); - COMBOEX_Register (); - DATETIME_Register (); - HEADER_Register (); - HOTKEY_Register (); - IPADDRESS_Register (); - LISTVIEW_Register (); - MONTHCAL_Register (); - NATIVEFONT_Register (); - PAGER_Register (); - PROGRESS_Register (); - REBAR_Register (); - STATUS_Register (); -#if __WINE_COMCTL32_VERSION == 6 - SYSLINK_Register (); -#endif - TAB_Register (); - TOOLBAR_Register (); - TOOLTIPS_Register (); - TRACKBAR_Register (); - TREEVIEW_Register (); - UPDOWN_Register (); break; case DLL_PROCESS_DETACH: if (lpvReserved) break; /* unregister all common control classes */ - ANIMATE_Unregister (); - COMBOEX_Unregister (); - DATETIME_Unregister (); - HEADER_Unregister (); - HOTKEY_Unregister (); - IPADDRESS_Unregister (); - LISTVIEW_Unregister (); - MONTHCAL_Unregister (); - NATIVEFONT_Unregister (); - PAGER_Unregister (); - PROGRESS_Unregister (); - REBAR_Unregister (); - STATUS_Unregister (); - TAB_Unregister (); - TOOLBAR_Unregister (); - TOOLTIPS_Unregister (); - TRACKBAR_Unregister (); - TREEVIEW_Unregister (); - UPDOWN_Unregister (); - -#if __WINE_COMCTL32_VERSION == 6 - SYSLINK_Unregister (); - - unregister_versioned_classes (); -#endif /* __WINE_COMCTL32_VERSION == 6 */ + unregister_classes (); /* delete local pattern brush */ DeleteObject (COMCTL32_hPattern55AABrush); diff --git a/dlls/comctl32/datetime.c b/dlls/comctl32/datetime.c index f7498842008..60e08f2815b 100644 --- a/dlls/comctl32/datetime.c +++ b/dlls/comctl32/datetime.c @@ -1801,10 +1801,3 @@ DATETIME_Register (void) RegisterClassW (&wndClass); } - - -void -DATETIME_Unregister (void) -{ - UnregisterClassW (DATETIMEPICK_CLASSW, NULL); -} diff --git a/dlls/comctl32/header.c b/dlls/comctl32/header.c index a21f4bb9934..2543e0afe21 100644 --- a/dlls/comctl32/header.c +++ b/dlls/comctl32/header.c @@ -2303,10 +2303,3 @@ HEADER_Register (void) RegisterClassW (&wndClass); } - - -VOID -HEADER_Unregister (void) -{ - UnregisterClassW (WC_HEADERW, NULL); -} diff --git a/dlls/comctl32/hotkey.c b/dlls/comctl32/hotkey.c index 484ab479c9f..032c57725b2 100644 --- a/dlls/comctl32/hotkey.c +++ b/dlls/comctl32/hotkey.c @@ -562,10 +562,3 @@ HOTKEY_Register (void) RegisterClassW (&wndClass); } - - -void -HOTKEY_Unregister (void) -{ - UnregisterClassW (HOTKEY_CLASSW, NULL); -} diff --git a/dlls/comctl32/ipaddress.c b/dlls/comctl32/ipaddress.c index 4e194af1c57..391e51f3958 100644 --- a/dlls/comctl32/ipaddress.c +++ b/dlls/comctl32/ipaddress.c @@ -700,9 +700,3 @@ void IPADDRESS_Register (void) RegisterClassW (&wndClass); } - - -void IPADDRESS_Unregister (void) -{ - UnregisterClassW (WC_IPADDRESSW, NULL); -} diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 661a09bcc7f..f91e63f1f5b 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -11980,21 +11980,6 @@ void LISTVIEW_Register(void) RegisterClassW(&wndClass); } -/*** - * DESCRIPTION: - * Unregisters the window class. - * - * PARAMETER(S): - * None - * - * RETURN: - * None - */ -void LISTVIEW_Unregister(void) -{ - UnregisterClassW(WC_LISTVIEWW, NULL); -} - /*** * DESCRIPTION: * Handle any WM_COMMAND messages diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c index 52a18eb0593..c814998d2b6 100644 --- a/dlls/comctl32/monthcal.c +++ b/dlls/comctl32/monthcal.c @@ -3023,10 +3023,3 @@ MONTHCAL_Register(void) RegisterClassW(&wndClass); } - - -void -MONTHCAL_Unregister(void) -{ - UnregisterClassW(MONTHCAL_CLASSW, NULL); -} diff --git a/dlls/comctl32/nativefont.c b/dlls/comctl32/nativefont.c index ede08d155b6..4db6d9bc152 100644 --- a/dlls/comctl32/nativefont.c +++ b/dlls/comctl32/nativefont.c @@ -123,10 +123,3 @@ NATIVEFONT_Register (void) RegisterClassW (&wndClass); } - - -VOID -NATIVEFONT_Unregister (void) -{ - UnregisterClassW (WC_NATIVEFONTCTLW, NULL); -} diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c index 8db7a76157f..fdf5ffbe136 100644 --- a/dlls/comctl32/pager.c +++ b/dlls/comctl32/pager.c @@ -1160,10 +1160,3 @@ PAGER_Register (void) RegisterClassW (&wndClass); } - - -VOID -PAGER_Unregister (void) -{ - UnregisterClassW (WC_PAGESCROLLERW, NULL); -} diff --git a/dlls/comctl32/progress.c b/dlls/comctl32/progress.c index 9b7a1617e20..539dacf8fdf 100644 --- a/dlls/comctl32/progress.c +++ b/dlls/comctl32/progress.c @@ -822,14 +822,3 @@ void PROGRESS_Register (void) RegisterClassW (&wndClass); } - - -/*********************************************************************** - * PROGRESS_Unregister [Internal] - * - * Unregisters the progress bar window class. - */ -void PROGRESS_Unregister (void) -{ - UnregisterClassW (PROGRESS_CLASSW, NULL); -} diff --git a/dlls/comctl32/rebar.c b/dlls/comctl32/rebar.c index 70dc66af816..27270a9b63c 100644 --- a/dlls/comctl32/rebar.c +++ b/dlls/comctl32/rebar.c @@ -3783,10 +3783,3 @@ REBAR_Register (void) mindragy = GetSystemMetrics (SM_CYDRAG); } - - -VOID -REBAR_Unregister (void) -{ - UnregisterClassW (REBARCLASSNAMEW, NULL); -} diff --git a/dlls/comctl32/status.c b/dlls/comctl32/status.c index ec68b8d3e0c..f27453aab8d 100644 --- a/dlls/comctl32/status.c +++ b/dlls/comctl32/status.c @@ -1307,16 +1307,3 @@ STATUS_Register (void) RegisterClassW (&wndClass); } - - -/*********************************************************************** - * STATUS_Unregister [Internal] - * - * Unregisters the status window class. - */ - -void -STATUS_Unregister (void) -{ - UnregisterClassW (STATUSCLASSNAMEW, NULL); -} diff --git a/dlls/comctl32/tab.c b/dlls/comctl32/tab.c index a83d6a5277d..3a964c41608 100644 --- a/dlls/comctl32/tab.c +++ b/dlls/comctl32/tab.c @@ -3468,10 +3468,3 @@ TAB_Register (void) RegisterClassW (&wndClass); } - - -void -TAB_Unregister (void) -{ - UnregisterClassW (WC_TABCONTROLW, NULL); -} diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index 0d8feefd8d5..d081e8b30b6 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -1382,13 +1382,11 @@ static void test_RegisterClassNameW(BOOL v6) if (!v6 && tests[i].v6_only) ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(tests[i].class_name)); else - todo_wine_if(i > 5) ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(tests[i].class_name), GetLastError()); } /* Test registering an already registered class */ ret = pRegisterClassNameW(ANIMATE_CLASSW); - todo_wine ok(ret, "RegisterClassNameW failed, error %lu.\n", GetLastError()); winetest_pop_context(); diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index df4a6e73415..3826b18d4c6 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -7045,13 +7045,6 @@ TOOLBAR_Register (void) RegisterClassW (&wndClass); } - -VOID -TOOLBAR_Unregister (void) -{ - UnregisterClassW (TOOLBARCLASSNAMEW, NULL); -} - static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id) { HIMAGELIST himlold; diff --git a/dlls/comctl32/tooltips.c b/dlls/comctl32/tooltips.c index 028b4c8e57c..fb3198c057c 100644 --- a/dlls/comctl32/tooltips.c +++ b/dlls/comctl32/tooltips.c @@ -2328,10 +2328,9 @@ TOOLTIPS_Register (void) VOID -TOOLTIPS_Unregister (void) +TOOLTIPS_AfterUnregister (void) { int i; for (i = TTI_INFO; i <= TTI_ERROR; i++) DestroyIcon(hTooltipIcons[i]); - UnregisterClassW (TOOLTIPS_CLASSW, NULL); } diff --git a/dlls/comctl32/trackbar.c b/dlls/comctl32/trackbar.c index 04faae1efcd..b0b5d245e45 100644 --- a/dlls/comctl32/trackbar.c +++ b/dlls/comctl32/trackbar.c @@ -2093,9 +2093,3 @@ void TRACKBAR_Register (void) RegisterClassW (&wndClass); } - - -void TRACKBAR_Unregister (void) -{ - UnregisterClassW (TRACKBAR_CLASSW, NULL); -} diff --git a/dlls/comctl32/treeview.c b/dlls/comctl32/treeview.c index 0618eeacf84..6cc49fa02ab 100644 --- a/dlls/comctl32/treeview.c +++ b/dlls/comctl32/treeview.c @@ -5973,14 +5973,6 @@ TREEVIEW_Register(void) RegisterClassW(&wndClass); } - -VOID -TREEVIEW_Unregister(void) -{ - UnregisterClassW(WC_TREEVIEWW, NULL); -} - - /* Tree Verification ****************************************************/ static inline void diff --git a/dlls/comctl32/updown.c b/dlls/comctl32/updown.c index ba7c89a822c..1a03d250638 100644 --- a/dlls/comctl32/updown.c +++ b/dlls/comctl32/updown.c @@ -1280,14 +1280,3 @@ void UPDOWN_Register(void) RegisterClassW( &wndClass ); } - - -/*********************************************************************** - * UPDOWN_Unregister [Internal] - * - * Unregisters the updown window class. - */ -void UPDOWN_Unregister (void) -{ - UnregisterClassW (UPDOWN_CLASSW, NULL); -} diff --git a/dlls/comctl32_v6/syslink.c b/dlls/comctl32_v6/syslink.c index 0880c0da527..ecf9b242704 100644 --- a/dlls/comctl32_v6/syslink.c +++ b/dlls/comctl32_v6/syslink.c @@ -2328,14 +2328,3 @@ VOID SYSLINK_Register (void) RegisterClassW (&wndClass); } - - -/*********************************************************************** - * SYSLINK_Unregister [Internal] - * - * Unregisters the SysLink window class. - */ -VOID SYSLINK_Unregister (void) -{ - UnregisterClassW (WC_LINK, NULL); -} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9822
Nikolay Sivov (@nsivov) commented about dlls/comctl32/tests/misc.c:
winetest_push_context("v%d", v6 ? 6 : 5);
- for (i = 0; i < ARRAY_SIZE(class_names); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { - ret = pRegisterClassNameW(class_names[i]); - if (v6) - ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(class_names[i]), GetLastError()); + ret = pRegisterClassNameW(tests[i].class_name); + if (!v6 && tests[i].v6_only) + ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(tests[i].class_name)); else - ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(class_names[i])); + todo_wine_if(i > 5) + ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(tests[i].class_name), GetLastError()); }
Let's have two name lists instead, and two loops. Those extra flags and conditions while making it generic do not make it easier to understand. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126065
Nikolay Sivov (@nsivov) commented about dlls/comctl32/commctrl.c:
static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
+static struct +{ + const WCHAR *name; + void (*fn_register)(void); + void (*fn_after_unregister)(void); + BOOL registered;
With this flag we now have same thing tracked in two places - registered classes are tracked by win32u/server atoms. What happens if class is registered implicitly with RegisterClassNameW(), then unregistered by the user. Should this hook register it again, or it stays permanently broken? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126067
Nikolay Sivov (@nsivov) commented about dlls/comctl32/commctrl.c:
static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
+static struct +{ + const WCHAR *name; + void (*fn_register)(void); + void (*fn_after_unregister)(void);
Is it a problem to do DestroyIcon() in DllMain? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126066
On Tue Dec 23 18:06:52 2025 +0000, Nikolay Sivov wrote:
Is it a problem to do DestroyIcon() in DllMain? DestroyIcon() doesn't hold the loader lock, so it should be fine.
Calling user32 functions, for example, UnregisterClassW(), in DllMain() is against best practices. However, due to the lack of an UnregisterClassNameW(), we need to unregister those window classes in DllMain(). Such an issue is mentioned on Raymond Chen's blog [Don’t forget to unregister your window classes when your DLL shuts down dynamically](https://devblogs.microsoft.com/oldnewthing/20060920-07/?p=29663). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126107
participants (3)
-
Nikolay Sivov (@nsivov) -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)