[PATCH] comctl32/tests: Add some tests for ownerdrawn listbox.

Nikolay Sivov nsivov at codeweavers.com
Wed Jul 4 05:40:57 CDT 2018


Adapted from user32 tests contributed by Dmitry Timoshkov.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42602
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/comctl32/tests/listbox.c | 243 ++++++++++++++++++++++++++++++----
 1 file changed, 215 insertions(+), 28 deletions(-)

diff --git a/dlls/comctl32/tests/listbox.c b/dlls/comctl32/tests/listbox.c
index f44fdff77f..790c2c4357 100644
--- a/dlls/comctl32/tests/listbox.c
+++ b/dlls/comctl32/tests/listbox.c
@@ -30,6 +30,51 @@
 #include "wine/heap.h"
 #include "wine/test.h"
 #include "v6util.h"
+#include "msg.h"
+
+enum seq_index
+{
+    PARENT_SEQ_INDEX,
+    NUM_MSG_SEQUENCES
+};
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+/* encoded MEASUREITEMSTRUCT into a WPARAM */
+typedef struct
+{
+    union
+    {
+        struct
+        {
+            UINT CtlType : 4;
+            UINT CtlID   : 4;
+            UINT itemID  : 4;
+            UINT wParam  : 20;
+        } item;
+        WPARAM wp;
+    } u;
+} MEASURE_ITEM_STRUCT;
+
+static unsigned hash_Ly_W(const WCHAR *str)
+{
+    unsigned hash = 0;
+
+    for (; *str; str++)
+        hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
+
+    return hash;
+}
+
+static unsigned hash_Ly(const char *str)
+{
+    unsigned hash = 0;
+
+    for (; *str; str++)
+        hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
+
+    return hash;
+}
 
 static const char * const strings[4] = {
     "First added",
@@ -43,14 +88,7 @@ static const char * const strings[4] = {
 
 static const char BAD_EXTENSION[] = "*.badtxt";
 
-static int strcmp_aw(LPCWSTR strw, const char *stra)
-{
-    WCHAR buf[1024];
-
-    if (!stra) return 1;
-    MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, ARRAY_SIZE(buf));
-    return lstrcmpW(strw, buf);
-}
+#define ID_LISTBOX 1
 
 static HWND create_listbox(DWORD add_style, HWND parent)
 {
@@ -58,7 +96,7 @@ static HWND create_listbox(DWORD add_style, HWND parent)
     HWND handle;
 
     if (parent)
-      ctl_id=1;
+        ctl_id = ID_LISTBOX;
 
     handle = CreateWindowA(WC_LISTBOXA, "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100,
         parent, (HMENU)ctl_id, NULL, 0);
@@ -234,41 +272,87 @@ static void test_item_height(void)
 
 static int got_selchange;
 
-static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
+    static LONG defwndproc_counter = 0;
+    struct message m = { 0 };
+    LRESULT ret;
+
+    m.message = msg;
+    m.flags = sent|wparam|lparam;
+    if (defwndproc_counter) m.flags |= defwinproc;
+    m.wParam = wParam;
+    m.lParam = lParam;
+
     switch (msg)
     {
     case WM_MEASUREITEM:
     {
-        DWORD style = GetWindowLongA(GetWindow(hwnd, GW_CHILD), GWL_STYLE);
-        MEASUREITEMSTRUCT *mi = (void*)lparam;
+        MEASUREITEMSTRUCT *mis = (void *)lParam;
+        BOOL is_unicode_data = FALSE;
+        MEASURE_ITEM_STRUCT mi;
+
+        if (mis->CtlType == ODT_LISTBOX)
+        {
+            HWND ctrl = GetDlgItem(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 = wParam;
+
+        m.wParam = mi.u.wp;
+        if (is_unicode_data)
+            m.lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
+        else
+            m.lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
+        add_message(sequences, PARENT_SEQ_INDEX, &m);
+
+        ok(wParam == mis->CtlID, "got wParam=%08lx, expected %08x\n", wParam, mis->CtlID);
+        ok(mis->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mis->CtlType);
+        ok(mis->CtlID == 1, "mi->CtlID = %u\n", mis->CtlID);
+        ok(mis->itemHeight, "mi->itemHeight = 0\n");
+
+        break;
+    }
+    case WM_COMPAREITEM:
+    {
+        COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lParam;
+        HWND ctrl = GetDlgItem(hwnd, cis->CtlID);
+        BOOL is_unicode_data = TRUE;
 
-        ok(wparam == mi->CtlID, "got wParam=%08lx, expected %08x\n", wparam, mi->CtlID);
-        ok(mi->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mi->CtlType);
-        ok(mi->CtlID == 1, "mi->CtlID = %u\n", mi->CtlID);
-        ok(mi->itemHeight, "mi->itemHeight = 0\n");
+        ok(wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, 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);
 
-        if (mi->itemID > 4 || style & LBS_OWNERDRAWFIXED)
-            break;
+        if (cis->CtlType == ODT_LISTBOX)
+            is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
 
-        if (style & LBS_HASSTRINGS)
+        if (is_unicode_data)
         {
-            ok(!strcmp_aw((WCHAR*)mi->itemData, strings[mi->itemID]),
-                    "mi->itemData = %s (%d)\n", wine_dbgstr_w((WCHAR*)mi->itemData), mi->itemID);
+            m.wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
+            m.lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
         }
         else
         {
-            ok((void*)mi->itemData == strings[mi->itemID],
-                    "mi->itemData = %08lx, expected %p\n", mi->itemData, strings[mi->itemID]);
+            m.wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
+            m.lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
         }
+        add_message(sequences, PARENT_SEQ_INDEX, &m);
         break;
     }
     case WM_DRAWITEM:
     {
         RECT rc_item, rc_client, rc_clip;
-        DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
+        DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
 
-        ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wparam, dis->CtlID);
+        ok(wParam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wParam, dis->CtlID);
         ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
 
         GetClientRect(dis->hwndItem, &rc_client);
@@ -284,14 +368,18 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA
     }
 
     case WM_COMMAND:
-        if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
+        if (HIWORD( wParam ) == LBN_SELCHANGE) got_selchange++;
         break;
 
     default:
         break;
     }
 
-    return DefWindowProcA(hwnd, msg, wparam, lparam);
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, msg, wParam, lParam);
+    defwndproc_counter--;
+
+    return msg == WM_COMPAREITEM ? -1 : ret;
 }
 
 static HWND create_parent( void )
@@ -1871,10 +1959,34 @@ static void test_listbox(void)
     run_test(EMS_NS);
 }
 
+static const struct message lb_addstring_ownerdraw_parent_seq[] =
+{
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
+    { 0 }
+};
+
+static const struct message lb_addstring_sort_parent_seq[] =
+{
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
+    { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
+    { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
+    { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
+    { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
+    { 0 }
+};
+
+static const struct message empty_seq[] =
+{
+    { 0 }
+};
+
 static void test_WM_MEASUREITEM(void)
 {
     HWND parent, listbox;
-    LRESULT data;
+    LRESULT data, ret;
 
     parent = create_parent();
     listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
@@ -1888,6 +2000,79 @@ static void test_WM_MEASUREITEM(void)
 
     data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
     ok(!data, "data = %08lx\n", data);
+
+    /* LBS_HASSTRINGS */
+    parent = create_parent();
+    listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
+                              WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
+                              10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    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");
+    ok(ret == 1, "expected 1, got %ld\n", ret);
+    ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
+    ok(ret == 2, "expected 2, got %ld\n", ret);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
+        "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
+    DestroyWindow(listbox);
+
+    /* LBS_SORT, no LBS_HASSTRINGS */
+    listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
+                              WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
+                              10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    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(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", TRUE);
+    DestroyWindow(listbox);
+
+    /* LBS_HASSTRINGS */
+    listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
+                              WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
+                              10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
+    ok(ret == 0, "expected 0, got %ld\n", ret);
+    ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
+    ok(ret == 1, "expected 1, got %ld\n", ret);
+    ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
+    ok(ret == 2, "expected 2, got %ld\n", ret);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
+    DestroyWindow(listbox);
+
+    /* LBS_HASSTRINGS, LBS_SORT */
+    listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
+                              WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
+                              10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
+    ok(ret == 0, "expected 0, got %ld\n", ret);
+    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");
+    ok(ret == 1, "expected 1, got %ld\n", ret);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
+    DestroyWindow(listbox);
+
     DestroyWindow(parent);
 }
 
@@ -1899,6 +2084,8 @@ START_TEST(listbox)
     if (!load_v6_module(&ctx_cookie, &hCtx))
         return;
 
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
     test_listbox();
     test_item_height();
     test_ownerdraw();
-- 
2.18.0




More information about the wine-devel mailing list