[PATCH v2 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. -- v2: comctl32: Register window classes in RegisterClassNameW() instead of DllMain(). comctl32/tests: Add more RegisterClassNameW() tests. comctl32: Remove flatsb_class32 window class. 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 -------------------------------------- dlls/comctl32/tests/misc.c | 3 +- include/commctrl.h | 11 ------- 5 files changed, 1 insertion(+), 80 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/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index e69eeed3ac2..4b01009fdc9 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -404,13 +404,12 @@ 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") || !strcmp(name, "flatsb_class32")) + todo_wine_if((!strcmp(name, "tooltips_class32") && v6) || !strcmp(name, "SysLink")) 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 ); 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 | 99 +++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index 4b01009fdc9..1dd0b1e80eb 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -1336,28 +1336,103 @@ static void test_version(BOOL v6) static void test_RegisterClassNameW(BOOL v6) { - static const WCHAR *class_names[] = + static const WCHAR *v6_class_names[] = { - L"Button", - L"ComboBox", + WC_BUTTONW, + WC_COMBOBOXW, L"ComboLBox", - L"Edit", - L"ListBox", - L"Static", + WC_EDITW, + WC_LISTBOXW, + WC_STATICW, + WC_LINK, + 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, + }; + static const WCHAR *v5_class_names[] = + { + 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; + WNDCLASSW wc; BOOL ret; winetest_push_context("v%d", v6 ? 6 : 5); - for (i = 0; i < ARRAY_SIZE(class_names); i++) + if (v6) { - ret = pRegisterClassNameW(class_names[i]); - if (v6) - ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(class_names[i]), GetLastError()); - else - ok(!ret, "RegisterClassNameW %s succeeded.\n", wine_dbgstr_w(class_names[i])); + for (i = 0; i < ARRAY_SIZE(v6_class_names); i++) + { + ret = pRegisterClassNameW(v6_class_names[i]); + todo_wine_if(i > 5) + ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(v6_class_names[i]), GetLastError()); + } } + else + { + for (i = 0; i < ARRAY_SIZE(v5_class_names); i++) + { + ret = pRegisterClassNameW(v5_class_names[i]); + todo_wine + ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(v5_class_names[i]), GetLastError()); + } + } + + /* Test unregistering a class that's implicitly registered by RegisterClassNameW() */ + ret = UnregisterClassW(ANIMATE_CLASSW, NULL); + ok(ret, "UnregisterClassW failed, error %lu.\n", GetLastError()); + + /* Make sure that it's really unregistered */ + ret = UnregisterClassW(ANIMATE_CLASSW, NULL); + ok(!ret, "UnregisterClassW succeeded.\n"); + + /* GetClassInfoW() should succeed */ + ret = GetClassInfoW(0, ANIMATE_CLASSW, &wc); + todo_wine + ok(ret, "GetClassInfoW failed, error %lu.\n", GetLastError()); + + /* Test registering an already registered window class */ + ret = pRegisterClassNameW(ANIMATE_CLASSW); + todo_wine + ok(ret, "RegisterClassNameW failed, error %lu.\n", GetLastError()); + + /* Test registering an non-existent window class */ + ret = pRegisterClassNameW(L"non-existent"); + ok(!ret, "RegisterClassNameW succeeded.\n"); 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 | 36 ++------- dlls/comctl32/commctrl.c | 149 +++++++++++++++---------------------- 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 | 4 - dlls/comctl32/toolbar.c | 7 -- dlls/comctl32/tooltips.c | 22 ++---- dlls/comctl32/trackbar.c | 6 -- dlls/comctl32/treeview.c | 8 -- dlls/comctl32/updown.c | 11 --- dlls/comctl32_v6/syslink.c | 11 --- 23 files changed, 72 insertions(+), 295 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..90a9a5fcd03 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -244,54 +244,34 @@ 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 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..53d2033a798 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -91,60 +91,75 @@ static const WORD wPattern55AA[] = static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo"; -#if __WINE_COMCTL32_VERSION == 6 -static void unregister_versioned_classes(void) +static struct { -#define VERSION "6.0.2600.2982!" - static const char *classes[] = - { - VERSION WC_BUTTONA, - VERSION WC_COMBOBOXA, - VERSION "ComboLBox", - VERSION WC_EDITA, - VERSION WC_LISTBOXA, - VERSION WC_STATICA, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(classes); i++) - UnregisterClassA(classes[i], NULL); - -#undef VERSION + const WCHAR *name; + void (*fn_register)(void); + BOOL registered; } -#endif /* __WINE_COMCTL32_VERSION == 6 */ - -BOOL WINAPI RegisterClassNameW(const WCHAR *class) +classes[] = { #if __WINE_COMCTL32_VERSION == 6 - static const struct - { - const WCHAR nameW[16]; - void (*fn_register)(void); - } - classes[] = + {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}, + {TRACKBAR_CLASSW, TRACKBAR_Register}, + {WC_TREEVIEWW, TREEVIEW_Register}, + {UPDOWN_CLASSW, UPDOWN_Register} +}; + +static void unregister_classes(void) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(classes); i++) { - { L"Button", BUTTON_Register }, - { L"ComboBox", COMBO_Register }, - { L"ComboLBox", COMBOLBOX_Register }, - { L"Edit", EDIT_Register }, - { L"ListBox", LISTBOX_Register }, - { L"Static", STATIC_Register }, - }; + if (classes[i].registered) + { +#if __WINE_COMCTL32_VERSION == 6 + WCHAR versioned_class[40]; - int min = 0, max = ARRAY_SIZE(classes) - 1; + 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 + } + } +} - while (min <= max) +BOOL WINAPI RegisterClassNameW(const WCHAR *class_name) +{ + 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(); + /* User might have unregistered the window class. Register it again regardless */ + 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 +199,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 1dd0b1e80eb..805766958a1 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -1398,7 +1398,6 @@ static void test_RegisterClassNameW(BOOL v6) for (i = 0; i < ARRAY_SIZE(v6_class_names); i++) { ret = pRegisterClassNameW(v6_class_names[i]); - todo_wine_if(i > 5) ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(v6_class_names[i]), GetLastError()); } } @@ -1407,7 +1406,6 @@ static void test_RegisterClassNameW(BOOL v6) for (i = 0; i < ARRAY_SIZE(v5_class_names); i++) { ret = pRegisterClassNameW(v5_class_names[i]); - todo_wine ok(ret, "RegisterClassNameW %s failed, error %lu.\n", wine_dbgstr_w(v5_class_names[i]), GetLastError()); } } @@ -1422,12 +1420,10 @@ static void test_RegisterClassNameW(BOOL v6) /* GetClassInfoW() should succeed */ ret = GetClassInfoW(0, ANIMATE_CLASSW, &wc); - todo_wine ok(ret, "GetClassInfoW failed, error %lu.\n", GetLastError()); /* Test registering an already registered window class */ ret = pRegisterClassNameW(ANIMATE_CLASSW); - todo_wine ok(ret, "RegisterClassNameW failed, error %lu.\n", GetLastError()); /* Test registering an non-existent window class */ 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..876736b11e4 100644 --- a/dlls/comctl32/tooltips.c +++ b/dlls/comctl32/tooltips.c @@ -2313,25 +2313,15 @@ TOOLTIPS_Register (void) hTooltipIcons[TTI_NONE] = NULL; hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, LR_SHARED); hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, LR_SHARED); hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, LR_SHARED); hTooltipIcons[TTI_INFO_LARGE] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_MD), IMAGE_ICON, 0, 0, 0); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_MD), IMAGE_ICON, 0, 0, LR_SHARED); hTooltipIcons[TTI_WARNING_LARGE] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_MD), IMAGE_ICON, 0, 0, 0); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_MD), IMAGE_ICON, 0, 0, LR_SHARED); hTooltipIcons[TTI_ERROR_LARGE] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_MD), IMAGE_ICON, 0, 0, 0); -} - - -VOID -TOOLTIPS_Unregister (void) -{ - int i; - for (i = TTI_INFO; i <= TTI_ERROR; i++) - DestroyIcon(hTooltipIcons[i]); - UnregisterClassW (TOOLTIPS_CLASSW, NULL); + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_MD), IMAGE_ICON, 0, 0, LR_SHARED); } 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
On Tue Dec 23 18:06:52 2025 +0000, Nikolay Sivov wrote:
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? I added more tests and they show that RegisterClassNameW() should register the window class again even if it gets unregistered by the user.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126113
v2: - Modify tests to use two loops. - Remove redundant todo_wines for flatsb_class32. - Register window classes even if they are registered, in case they get unregistered by the user. - Modify TOOLTIPS_Register() to load icons with LR_SHARED, as TOOLTIPS_Register() may be called multiple times. This also eliminates the need for TOOLTIPS_AfterRegister(). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126115
Nikolay Sivov (@nsivov) commented about dlls/comctl32/commctrl.c:
- VERSION WC_BUTTONA, - VERSION WC_COMBOBOXA, - VERSION "ComboLBox", - VERSION WC_EDITA, - VERSION WC_LISTBOXA, - VERSION WC_STATICA, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(classes); i++) - UnregisterClassA(classes[i], NULL); - -#undef VERSION + const WCHAR *name; + void (*fn_register)(void); + BOOL registered; Could we get rid of this flag and unregister unconditionally? For example, if you load comctl32.dll manually, without triggering registration (is that possible?), then register some custom class called ListView, does it get unregistered on dll unload? Or maybe it's always safe if you use comctl32's HINSTANCE. As it is now, this flag name does not match what it necessarily means internally.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9822#note_126212
participants (3)
-
Nikolay Sivov (@nsivov) -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)