From a47000e41cb7bafa5aae202ac616b40b79dd5c81 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Mon, 20 Mar 2017 16:49:38 +0100 Subject: [PATCH] Added patch with multiple fixes for owner-drawn and sorted listbox. --- patches/patchinstall.sh | 35 ++++ ...-a-message-test-for-an-owner-drawn-s.patch | 160 ++++++++++++++++++ ...-of-items-passed-in-WM_COMPAREITEM-d.patch | 63 +++++++ ...32-Fix-the-listbox-sorting-algorithm.patch | 44 +++++ ...ner-drawn-listbox-without-strings-WM.patch | 40 +++++ patches/user32-Sorted_Listbox/definition | 2 + 6 files changed, 344 insertions(+) create mode 100644 patches/user32-Sorted_Listbox/0001-user32-tests-Add-a-message-test-for-an-owner-drawn-s.patch create mode 100644 patches/user32-Sorted_Listbox/0002-user32-Fix-order-of-items-passed-in-WM_COMPAREITEM-d.patch create mode 100644 patches/user32-Sorted_Listbox/0003-user32-Fix-the-listbox-sorting-algorithm.patch create mode 100644 patches/user32-Sorted_Listbox/0004-user32-For-an-owner-drawn-listbox-without-strings-WM.patch create mode 100644 patches/user32-Sorted_Listbox/definition diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 406fc3ec..02b8c306 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -371,6 +371,7 @@ patch_enable_all () enable_user32_PNG_Support="$1" enable_user32_Refresh_MDI_Menus="$1" enable_user32_ScrollWindowEx="$1" + enable_user32_Sorted_Listbox="$1" enable_user32_WM_MEASUREITEM="$1" enable_user32_lpCreateParams="$1" enable_uxtheme_CloseThemeClass="$1" @@ -1335,6 +1336,9 @@ patch_enable () user32-ScrollWindowEx) enable_user32_ScrollWindowEx="$2" ;; + user32-Sorted_Listbox) + enable_user32_Sorted_Listbox="$2" + ;; user32-WM_MEASUREITEM) enable_user32_WM_MEASUREITEM="$2" ;; @@ -2106,6 +2110,13 @@ if test "$enable_uxtheme_GTK_Theming" -eq 1; then enable_ntdll_DllRedirects=1 fi +if test "$enable_user32_Sorted_Listbox" -eq 1; then + if test "$enable_user32_WM_MEASUREITEM" -gt 1; then + abort "Patchset user32-WM_MEASUREITEM disabled, but user32-Sorted_Listbox depends on that." + fi + enable_user32_WM_MEASUREITEM=1 +fi + if test "$enable_user32_MessageBox_WS_EX_TOPMOST" -eq 1; then if test "$enable_user32_lpCreateParams" -gt 1; then abort "Patchset user32-lpCreateParams disabled, but user32-MessageBox_WS_EX_TOPMOST depends on that." @@ -7779,6 +7790,30 @@ if test "$enable_user32_WM_MEASUREITEM" -eq 1; then ) >> "$patchlist" fi +# Patchset user32-Sorted_Listbox +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * user32-WM_MEASUREITEM +# | +# | This patchset fixes the following Wine bugs: +# | * [#42602] Multiple fixes for owner-drawn and sorted listbox +# | +# | Modified files: +# | * dlls/user32/listbox.c, dlls/user32/tests/msg.c +# | +if test "$enable_user32_Sorted_Listbox" -eq 1; then + patch_apply user32-Sorted_Listbox/0001-user32-tests-Add-a-message-test-for-an-owner-drawn-s.patch + patch_apply user32-Sorted_Listbox/0002-user32-Fix-order-of-items-passed-in-WM_COMPAREITEM-d.patch + patch_apply user32-Sorted_Listbox/0003-user32-Fix-the-listbox-sorting-algorithm.patch + patch_apply user32-Sorted_Listbox/0004-user32-For-an-owner-drawn-listbox-without-strings-WM.patch + ( + printf '%s\n' '+ { "Dmitry Timoshkov", "user32/tests: Add a message test for an owner-drawn sorted listbox.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "user32: Fix order of items passed in WM_COMPAREITEM data.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "user32: Fix the listbox sorting algorithm.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "user32: For an owner-drawn listbox without strings WM_MEASUREITEM still needs correct itemData.", 1 },'; + ) >> "$patchlist" +fi + # Patchset uxtheme-CloseThemeClass # | # | This patchset fixes the following Wine bugs: diff --git a/patches/user32-Sorted_Listbox/0001-user32-tests-Add-a-message-test-for-an-owner-drawn-s.patch b/patches/user32-Sorted_Listbox/0001-user32-tests-Add-a-message-test-for-an-owner-drawn-s.patch new file mode 100644 index 00000000..9529cdc6 --- /dev/null +++ b/patches/user32-Sorted_Listbox/0001-user32-tests-Add-a-message-test-for-an-owner-drawn-s.patch @@ -0,0 +1,160 @@ +From 726802175f5249d2313620f488a55ffa391c56ce Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 8 Mar 2017 16:33:41 +0800 +Subject: user32/tests: Add a message test for an owner-drawn sorted listbox. + +--- + dlls/user32/tests/msg.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 88 insertions(+), 3 deletions(-) + +diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c +index a742f670ab..3a492b37bd 100644 +--- a/dlls/user32/tests/msg.c ++++ b/dlls/user32/tests/msg.c +@@ -2232,18 +2232,61 @@ static void add_message_(int line, const struct recvd_message *msg) + { + MEASURE_ITEM_STRUCT mi; + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam; ++ BOOL is_unicode_data = TRUE; + + sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx", + msg->descr, msg->hwnd, mis->CtlType, mis->CtlID, + mis->itemID, mis->itemData); + ++ if (mis->CtlType == ODT_LISTBOX) ++ { ++ HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID); ++ is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; ++ } ++ + mi.u.wp = 0; + mi.u.item.CtlType = mis->CtlType; + mi.u.item.CtlID = mis->CtlID; + mi.u.item.itemID = mis->itemID; + mi.u.item.wParam = msg->wParam; + seq->wParam = mi.u.wp; +- seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0; ++ if (is_unicode_data) ++ seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0; ++ else ++ seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0; ++ break; ++ } ++ ++ case WM_COMPAREITEM: ++ { ++ COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam; ++ HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID); ++ BOOL is_unicode_data = TRUE; ++ ++ ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam); ++ ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem); ++todo_wine ++ ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1); ++todo_wine ++ ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2); ++ ++ sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx", ++ msg->descr, msg->hwnd, cis->CtlType, cis->CtlID, ++ cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2); ++ ++ if (cis->CtlType == ODT_LISTBOX) ++ is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; ++ ++ if (is_unicode_data) ++ { ++ seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0; ++ seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0; ++ } ++ else ++ { ++ seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0; ++ seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0; ++ } + break; + } + +@@ -9261,7 +9304,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam + message == WM_PARENTNOTIFY || message == WM_CANCELMODE || + message == WM_SETFOCUS || message == WM_KILLFOCUS || + message == WM_ENABLE || message == WM_ENTERIDLE || +- message == WM_DRAWITEM || message == WM_MEASUREITEM || ++ message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM || + message == WM_COMMAND || message == WM_IME_SETCONTEXT) + { + switch (message) +@@ -9309,7 +9352,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + +- return ret; ++ return message == WM_COMPAREITEM ? -1 : ret; + } + + static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +@@ -14430,6 +14473,19 @@ static const struct message wm_lb_addstring[] = + { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, + { 0 } + }; ++static const struct message wm_lb_addstring_sort[] = ++{ ++ { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed }, ++ { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed }, ++ { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee }, ++ { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee }, ++ { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee }, ++ { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef }, ++ { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef }, ++ { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef }, ++ { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, ++ { 0 } ++}; + + #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__) + +@@ -14495,6 +14551,7 @@ static void test_listbox_messages(void) + + parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); ++ /* with LBS_HASSTRINGS */ + listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, + WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE, + 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); +@@ -14576,6 +14633,34 @@ static void test_listbox_messages(void) + log_all_parent_messages--; + + DestroyWindow(listbox); ++ ++ /* with LBS_SORT and without LBS_HASSTRINGS */ ++ listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, ++ WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE, ++ 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); ++ listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc); ++ ++ check_lb_state(listbox, 0, LB_ERR, 0, 0); ++ ++ flush_sequence(); ++ ++ log_all_parent_messages++; ++ ++ ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); ++ ok(ret == 0, "expected 0, got %ld\n", ret); ++ ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); ++todo_wine ++ ok(ret == 1, "expected 1, got %ld\n", ret); ++ ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); ++todo_wine ++ ok(ret == 2, "expected 2, got %ld\n", ret); ++ ++ ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", TRUE); ++ check_lb_state(listbox, 3, LB_ERR, 0, 0); ++ ++ log_all_parent_messages--; ++ ++ DestroyWindow(listbox); + DestroyWindow(parent); + } + +-- +2.11.0 + diff --git a/patches/user32-Sorted_Listbox/0002-user32-Fix-order-of-items-passed-in-WM_COMPAREITEM-d.patch b/patches/user32-Sorted_Listbox/0002-user32-Fix-order-of-items-passed-in-WM_COMPAREITEM-d.patch new file mode 100644 index 00000000..b8786301 --- /dev/null +++ b/patches/user32-Sorted_Listbox/0002-user32-Fix-order-of-items-passed-in-WM_COMPAREITEM-d.patch @@ -0,0 +1,63 @@ +From 25f564b7d279386c882c144fd6591d012049dcb7 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 8 Mar 2017 16:48:26 +0800 +Subject: user32: Fix order of items passed in WM_COMPAREITEM data. + +--- + dlls/user32/listbox.c | 10 +++++----- + dlls/user32/tests/msg.c | 4 ---- + 2 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c +index 689cb106c4..4269ef0717 100644 +--- a/dlls/user32/listbox.c ++++ b/dlls/user32/listbox.c +@@ -858,15 +858,15 @@ static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact ) + cis.hwndItem = descr->self; + /* note that some application (MetaStock) expects the second item + * to be in the listbox */ +- cis.itemID1 = -1; +- cis.itemData1 = (ULONG_PTR)str; +- cis.itemID2 = index; +- cis.itemData2 = descr->items[index].data; ++ cis.itemID1 = index; ++ cis.itemData1 = descr->items[index].data; ++ cis.itemID2 = -1; ++ cis.itemData2 = (ULONG_PTR)str; + cis.dwLocaleId = descr->locale; + res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis ); + } + if (!res) return index; +- if (res < 0) max = index; ++ if (res > 0) max = index; + else min = index + 1; + } + return exact ? -1 : max; +diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c +index 3a492b37bd..f806e5366e 100644 +--- a/dlls/user32/tests/msg.c ++++ b/dlls/user32/tests/msg.c +@@ -2265,9 +2265,7 @@ static void add_message_(int line, const struct recvd_message *msg) + + ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam); + ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem); +-todo_wine + ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1); +-todo_wine + ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2); + + sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx", +@@ -14649,10 +14647,8 @@ static void test_listbox_messages(void) + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); + ok(ret == 0, "expected 0, got %ld\n", ret); + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); +-todo_wine + ok(ret == 1, "expected 1, got %ld\n", ret); + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); +-todo_wine + ok(ret == 2, "expected 2, got %ld\n", ret); + + ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", TRUE); +-- +2.11.0 + diff --git a/patches/user32-Sorted_Listbox/0003-user32-Fix-the-listbox-sorting-algorithm.patch b/patches/user32-Sorted_Listbox/0003-user32-Fix-the-listbox-sorting-algorithm.patch new file mode 100644 index 00000000..642bf1f1 --- /dev/null +++ b/patches/user32-Sorted_Listbox/0003-user32-Fix-the-listbox-sorting-algorithm.patch @@ -0,0 +1,44 @@ +From 29128bbe18f85edc8f7760262c6b598bd789ffb0 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 8 Mar 2017 17:48:58 +0800 +Subject: user32: Fix the listbox sorting algorithm. + +--- + dlls/user32/listbox.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c +index 4269ef0717..5eb266b15a 100644 +--- a/dlls/user32/listbox.c ++++ b/dlls/user32/listbox.c +@@ -840,10 +840,11 @@ static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact ) + { + INT index, min, max, res; + +- if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */ ++ if (!descr->nb_items || !(descr->style & LBS_SORT)) return -1; /* Add it at the end */ ++ + min = 0; +- max = descr->nb_items; +- while (min != max) ++ max = descr->nb_items - 1; ++ while (min <= max) + { + index = (min + max) / 2; + if (HAS_STRINGS(descr)) +@@ -866,10 +867,10 @@ static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact ) + res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis ); + } + if (!res) return index; +- if (res > 0) max = index; ++ if (res > 0) max = index - 1; + else min = index + 1; + } +- return exact ? -1 : max; ++ return exact ? -1 : min; + } + + +-- +2.11.0 + diff --git a/patches/user32-Sorted_Listbox/0004-user32-For-an-owner-drawn-listbox-without-strings-WM.patch b/patches/user32-Sorted_Listbox/0004-user32-For-an-owner-drawn-listbox-without-strings-WM.patch new file mode 100644 index 00000000..0f1e47ed --- /dev/null +++ b/patches/user32-Sorted_Listbox/0004-user32-For-an-owner-drawn-listbox-without-strings-WM.patch @@ -0,0 +1,40 @@ +From 3a44891b4f5f206363492fc3ff91e8a97a70857d Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 8 Mar 2017 17:52:10 +0800 +Subject: user32: For an owner-drawn listbox without strings WM_MEASUREITEM + still needs correct itemData. + +--- + dlls/user32/listbox.c | 2 +- + dlls/user32/tests/msg.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c +index 5eb266b15a..4572b81bf3 100644 +--- a/dlls/user32/listbox.c ++++ b/dlls/user32/listbox.c +@@ -1566,7 +1566,7 @@ static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index, + mis.CtlType = ODT_LISTBOX; + mis.CtlID = id; + mis.itemID = index; +- mis.itemData = (ULONG_PTR)str; ++ mis.itemData = str ? (ULONG_PTR)str : data; + mis.itemHeight = descr->item_height; + TRACE("owner=%p CtlID=%08x, itemID=%08x, itemData=%08lx\n", + descr->owner, mis.CtlID, mis.itemID, mis.itemData); +diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c +index f806e5366e..34385bd266 100644 +--- a/dlls/user32/tests/msg.c ++++ b/dlls/user32/tests/msg.c +@@ -14651,7 +14651,7 @@ static void test_listbox_messages(void) + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); + ok(ret == 2, "expected 2, got %ld\n", ret); + +- ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", TRUE); ++ ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", FALSE); + check_lb_state(listbox, 3, LB_ERR, 0, 0); + + log_all_parent_messages--; +-- +2.11.0 + diff --git a/patches/user32-Sorted_Listbox/definition b/patches/user32-Sorted_Listbox/definition new file mode 100644 index 00000000..93fa5129 --- /dev/null +++ b/patches/user32-Sorted_Listbox/definition @@ -0,0 +1,2 @@ +Fixes: [42602] Multiple fixes for owner-drawn and sorted listbox +Depends: user32-WM_MEASUREITEM