[PATCH v4 0/2] MR6160: comctl32: Fix sorting for listview.
The listview bug is caused by passing the incorrect index to the LISTVIEW_SortItems callers custom compare function. If we pass the copied array indices, which are different because of the sorting, the caller is going to use those indices for their unsorted array which don't match. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56140 -- v4: comctl32: Fix sorting for listview. comctl32/tests: Add test for listview sorting order. https://gitlab.winehq.org/wine/wine/-/merge_requests/6160
From: Jacob Czekalla <jczekalla(a)codeweavers.com> --- dlls/comctl32/tests/listview.c | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 1081a045cde..e179ec473f8 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <windows.h> #include <commctrl.h> +#include <time.h> #include <objbase.h> #include "wine/test.h" @@ -3028,6 +3029,83 @@ static void test_subitem_rect(void) DestroyWindow(hwnd); } +static INT WINAPI test_CallBackCompareEx(LPARAM first, LPARAM second, LPARAM lParam) +{ + HWND hwnd_List_view = (HWND)lParam; + CHAR buffer1[256], buffer2[256]; + int itm1, itm2; + + ListView_GetItemTextA(hwnd_List_view, first, 0, buffer1, sizeof(buffer1)); + ListView_GetItemTextA(hwnd_List_view, second, 0, buffer2, sizeof(buffer2)); + + itm1 = atoi(buffer1); + itm2 = atoi(buffer2); + + return (itm1 - itm2); +} + +static void test_sort_order(void) +{ + LVITEMA lvi = {0}; + LV_COLUMNA lvc = {0}; + RECT rcClient; + CHAR buffer[256]; + CHAR col_names[][2] = { "1", "2" }; + HWND hwndListView = create_listview_control(LVS_REPORT); + int prev_value; + + GetClientRect(hwndparent, &rcClient); + + lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; + lvc.pszText = col_names[0]; + lvc.cx = rcClient.right / 2; + lvc.iSubItem = 0; + SendMessageA(hwndListView, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc); + + lvc.pszText = col_names[1]; + lvc.iSubItem = 1; + lvc.cx = rcClient.right / 2; + SendMessageA(hwndListView, LVM_INSERTCOLUMNA, 1, (LPARAM) &lvc); + + srand((unsigned)time(NULL)); + + for (int i = 0; i < 100; i++) + { + lvi.mask = LVIF_TEXT; + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.pszText = buffer; + sprintf(buffer, "%d", rand() % 100); + SendMessageA(hwndListView, LVM_INSERTITEMA, 0, (LPARAM) &lvi); + + lvi.iSubItem = 1; + sprintf(buffer, "%d", rand() % 100); + SendMessageA(hwndListView, LVM_SETITEMTEXTA, i, (LPARAM) &lvi); + } + + SendMessageA(hwndListView, LVM_SORTITEMSEX, (WPARAM) hwndListView, (LPARAM) test_CallBackCompareEx); + + memset(&lvi, 0, sizeof(lvi)); + for (int i = 1; i < 100; i++) + { + ListView_GetItemTextA(hwndListView, i-1, 0, buffer, sizeof(buffer)); + prev_value = atoi(buffer); + + ListView_GetItemTextA(hwndListView, i, 0, buffer, sizeof(buffer)); + + if (atoi(buffer) < prev_value) + { + prev_value = 1; + break; + } + prev_value = 0; + } + + todo_wine ok(!prev_value, "ListView not sorted correctly.\n"); + + DestroyWindow(hwndListView); +} + /* comparison callback for test_sorting */ static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam) { @@ -3211,6 +3289,8 @@ static void test_sorting(void) ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff); DestroyWindow(hwnd); + + test_sort_order(); } static void test_ownerdata(void) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6160
From: Jacob Czekalla <jczekalla(a)codeweavers.com> --- dlls/comctl32/listview.c | 2 +- dlls/comctl32/tests/listview.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index c82473b6205..0302e3e19a0 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -9396,7 +9396,7 @@ static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, if (infoPtr->nFocusedItem >= 0) focusedItem = DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem); - context.items = hdpaItems; + context.items = infoPtr->hdpaItems; context.compare_func = pfnCompare; context.lParam = lParamSort; if (IsEx) diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index e179ec473f8..64db477b11f 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -3101,7 +3101,7 @@ static void test_sort_order(void) prev_value = 0; } - todo_wine ok(!prev_value, "ListView not sorted correctly.\n"); + ok(!prev_value, "ListView not sorted correctly.\n"); DestroyWindow(hwndListView); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6160
Fabian Maurer (@DarkShadow44) commented about dlls/comctl32/tests/listview.c:
+ int prev_value; + + GetClientRect(hwndparent, &rcClient); + + lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; + lvc.pszText = col_names[0]; + lvc.cx = rcClient.right / 2; + lvc.iSubItem = 0; + SendMessageA(hwndListView, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc); + + lvc.pszText = col_names[1]; + lvc.iSubItem = 1; + lvc.cx = rcClient.right / 2; + SendMessageA(hwndListView, LVM_INSERTCOLUMNA, 1, (LPARAM) &lvc); + + srand((unsigned)time(NULL)); Wouldn't it be better if the tests were deterministic?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6160#note_77307
On Mon Jul 29 17:35:31 2024 +0000, Fabian Maurer wrote:
It fails only for 64bit (with a warning that is treated as error. Reason is the return value being casted, but not used by the macro. I'd recommend just using SendMessageA directly and avoiding the macro. Thanks for the advice. It fixed it!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6160#note_77330
On Mon Jul 29 20:06:51 2024 +0000, Fabian Maurer wrote:
Wouldn't it be better if the tests were deterministic? Yes, definitely.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6160#note_77335
On Tue Jul 30 08:50:37 2024 +0000, Nikolay Sivov wrote:
Yes, definitely. Ok, I will fix that. Thanks.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6160#note_77349
participants (4)
-
Fabian Maurer (@DarkShadow44) -
Jacob Czekalla -
Jacob Czekalla (@JacobCzekalla) -
Nikolay Sivov (@nsivov)