[PATCH] comctl32/listview: Fix the listview sorting error.
Haoyang Chen
chenhaoyang at uniontech.com
Mon Mar 8 02:35:30 CST 2021
在 2021/3/8 下午4:17, Nikolay Sivov 写道:
>
> On 3/8/21 11:09 AM, Haoyang Chen wrote:
>> hi,
>>
>> lParam may hold the initial sequence. During the sorting process, this
>> sequence is disrupted. But the initial queue order may still be used
>> during sorting.
>> For example, the original queue: 6 4 5.
>> First sort result: 4 6 5.
>> Second sort result: 4 6 5.
>> Here it is wrong, because it should compare "6" and "5", but the index
>> stored in the lParam of "6" is 0 (it has not changed), which is the
>> first data, so it actually compares "4" and "5".
> I still don't see how this affects listview item's lParam. Do you mean
> that during LVM_SORTITEMS execution order does not change? E.g. if you
> ask for index N in sort callback you'll get index N in pre-sorted order?
It should be said that the "lParam" does not change, while the
hdpa->ptrs queue keeps changing.
The lParam holds the index that the user has to use to get the data, but
wine treats it as the current order.
eg: The index of lParam in "6" is always 0, "4" = 1, "5" = 2.
thands.
>> I will send V2 for the test error.
> Alright.
>
>> Thanks.
>>
>> 在 2021/3/8 上午11:22, Haoyang Chen 写道:
>>> The original sequence may be stored in lparam. During the sorting
>>> process,
>>> this sequence is out-of-order, but lparam remains unchanged.
>>>
>>> Signed-off-by: Haoyang Chen <chenhaoyang at uniontech.com>
>>> ---
>>> dlls/comctl32/dpa.c | 13 ++++++--
>>> dlls/comctl32/tests/listview.c | 59 ++++++++++++++++++++++++++++++++++
>>> 2 files changed, 70 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/dlls/comctl32/dpa.c b/dlls/comctl32/dpa.c
>>> index 36b3a422e8c..69e9d0a33bb 100644
>>> --- a/dlls/comctl32/dpa.c
>>> +++ b/dlls/comctl32/dpa.c
>>> @@ -818,8 +818,17 @@ BOOL WINAPI DPA_Sort (HDPA hdpa, PFNDPACOMPARE
>>> pfnCompare, LPARAM lParam)
>>> TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
>>> if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
>>> - DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
>>> - pfnCompare, lParam);
>>> + {
>>> + LPVOID *ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
>>> + hdpa->nItemCount *
>>> sizeof(LPVOID));
>>> + if (!ptrs)
>>> + return FALSE;
>>> + memcpy(ptrs, hdpa->ptrs, hdpa->nItemCount * sizeof(LPVOID));
>>> + DPA_QuickSort (ptrs, 0, hdpa->nItemCount - 1, pfnCompare,
>>> lParam);
>>> +
>>> + memcpy(hdpa->ptrs, ptrs, hdpa->nItemCount * sizeof(LPVOID));
>>> + HeapFree (hdpa->hHeap, 0, ptrs);
>>> + }
>>> return TRUE;
>>> }
>>> diff --git a/dlls/comctl32/tests/listview.c
>>> b/dlls/comctl32/tests/listview.c
>>> index e95b81f5bb1..7b036a9f6c1 100644
>>> --- a/dlls/comctl32/tests/listview.c
>>> +++ b/dlls/comctl32/tests/listview.c
>>> @@ -2921,6 +2921,28 @@ static INT WINAPI test_CallBackCompare(LPARAM
>>> first, LPARAM second, LPARAM lPara
>>> return (first > second ? 1 : -1);
>>> }
>>> +static INT WINAPI test_CallBackCompare1(LPARAM first, LPARAM
>>> second, LPARAM lParam)
>>> +{
>>> + CHAR str1[5];
>>> + CHAR str2[5];
>>> + INT r;
>>> + HWND hwnd = (HWND)lParam;
>>> + LV_ITEMA item = {0};
>>> +
>>> + if (first == second) return 0;
>>> + item.cchTextMax = 5;
>>> + item.iSubItem = 0;
>>> + item.pszText = str1;
>>> + r = SendMessageA(hwnd, LVM_GETITEMTEXTA, first, (LPARAM)&item);
>>> + expect(TRUE, r);
>>> +
>>> + item.pszText = str2;
>>> + r = SendMessageA(hwnd, LVM_GETITEMTEXTA, second, (LPARAM)&item);
>>> + expect(TRUE, r);
>>> +
>>> + return atoi(str1) > atoi(str2) ? 1 : -1;
>>> +}
>>> +
>>> static void test_sorting(void)
>>> {
>>> HWND hwnd;
>>> @@ -2929,6 +2951,9 @@ static void test_sorting(void)
>>> LONG_PTR style;
>>> static CHAR names[][5] = {"A", "B", "C", "D", "0"};
>>> CHAR buff[10];
>>> + static CHAR before_sort_array[][5] = {"6","3","1","4","2"};
>>> + static CHAR after_sort_arary[][5] = {"1","2","3","4","6"};
>>> + INT i;
>>> hwnd = create_listview_control(LVS_REPORT);
>>> ok(hwnd != NULL, "failed to create a listview window\n");
>>> @@ -2979,6 +3004,40 @@ static void test_sorting(void)
>>> DestroyWindow(hwnd);
>>> + hwnd = create_listview_control(LVS_REPORT);
>>> + ok(hwnd != NULL, "failed to create a listview window\n");
>>> +
>>> + item.mask = LVIF_PARAM | LVIF_TEXT;
>>> + item.iSubItem = 0;
>>> + item.cchTextMax = 5;
>>> +
>>> + for (i = 0; i < sizeof(before_sort_array)/5; i++)
>>> + {
>>> + item.iItem = i;
>>> + item.lParam = i;
>>> + item.pszText = &before_sort_array[i][0];
>>> + r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
>>> + expect(i, r);
>>> + }
>>> +
>>> + r = SendMessageA(hwnd, LVM_SORTITEMS, (WPARAM)(LPARAM)hwnd,
>>> (LPARAM)test_CallBackCompare1);
>>> + expect(TRUE, r);
>>> +
>>> + for (i = 0; i < sizeof(after_sort_arary)/5; i++)
>>> + {
>>> + CHAR str[5];
>>> + item.iItem = i;
>>> + item.cchTextMax = 5;
>>> + item.iSubItem = 0;
>>> + item.pszText = str;
>>> + r = SendMessageA(hwnd, LVM_GETITEMTEXTA, i, (LPARAM)&item);
>>> + expect(TRUE, r);
>>> +
>>> + expect(0, strcmp(str,&after_sort_arary[i][0]));
>>> + }
>>> +
>>> + DestroyWindow(hwnd);
>>> +
>>> /* switch to LVS_SORTASCENDING when some items added */
>>> hwnd = create_listview_control(LVS_REPORT);
>>> ok(hwnd != NULL, "failed to create a listview window\n");
>>
>
>
>
More information about the wine-devel
mailing list