[COMCTL32_WINETEST] Sync with Wine Staging 2.9. CORE-13362
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 12:53:30 +0000 (12:53 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 12:53:30 +0000 (12:53 +0000)
svn path=/trunk/; revision=74903

21 files changed:
rostests/winetests/comctl32/CMakeLists.txt
rostests/winetests/comctl32/animate.c
rostests/winetests/comctl32/button.c
rostests/winetests/comctl32/comboex.c
rostests/winetests/comctl32/datetime.c
rostests/winetests/comctl32/header.c
rostests/winetests/comctl32/imagelist.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/misc.c
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/msg.h
rostests/winetests/comctl32/pager.c
rostests/winetests/comctl32/propsheet.c
rostests/winetests/comctl32/syslink.c
rostests/winetests/comctl32/tab.c
rostests/winetests/comctl32/taskdialog.c [new file with mode: 0644]
rostests/winetests/comctl32/testlist.c
rostests/winetests/comctl32/toolbar.c
rostests/winetests/comctl32/trackbar.c
rostests/winetests/comctl32/treeview.c
rostests/winetests/comctl32/updown.c

index 006fadc..47d677d 100644 (file)
@@ -24,6 +24,7 @@ list(APPEND SOURCE
     subclass.c
     syslink.c
     tab.c
+    taskdialog.c
     toolbar.c
     tooltips.c
     trackbar.c
index 0bb90a4..28cf55b 100644 (file)
@@ -160,8 +160,9 @@ static void test_play(void)
 
     SetLastError(0xdeadbeef);
     res = SendMessageA(hAnimateWnd, ACM_PLAY, (WPARAM) -1, MAKELONG(0, -1));
+    err = GetLastError();
     ok(res == 0, "Play should have failed\n");
-    ok(err == ERROR_RESOURCE_NAME_NOT_FOUND, "Expected 1814, got %u\n", err);
+    ok(err == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", err);
     destroy_animate();
 
     create_animate(0, 0);
index de81377..8cb5b5f 100644 (file)
@@ -124,8 +124,8 @@ static BOOL ignore_message( UINT message )
 static LRESULT CALLBACK button_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR ref_data)
 {
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     if (ignore_message( message )) return pDefSubclassProc(hwnd, message, wParam, lParam);
 
@@ -160,8 +160,8 @@ static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam
 {
     static LONG defwndproc_counter = 0;
     static LONG beginpaint_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     if (ignore_message( message )) return 0;
 
@@ -171,17 +171,6 @@ static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam
         message == WM_DRAWITEM || message == WM_COMMAND ||
         message == WM_IME_SETCONTEXT)
     {
-        switch (message)
-        {
-            /* ignore */
-            case WM_NCHITTEST:
-                return HTCLIENT;
-            case WM_SETCURSOR:
-            case WM_MOUSEMOVE:
-            case WM_NCMOUSEMOVE:
-                return 0;
-        }
-
         msg.message = message;
         msg.flags = sent|parent|wparam|lparam;
         if (defwndproc_counter) msg.flags |= defwinproc;
index 23868eb..ec13e22 100644 (file)
@@ -90,8 +90,8 @@ static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wPar
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
index c0ea374..fcd7bee 100644 (file)
@@ -142,15 +142,14 @@ static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
index ab485e3..8be4db2 100644 (file)
@@ -394,7 +394,7 @@ static char pszOutOfRangeItem[] = "Out Of Range Item";
 
 static char *str_items[] =
     {pszFirstItem, pszSecondItem, pszThirdItem, pszFourthItem, pszReplaceItem, pszOutOfRangeItem};
-    
+
 static char pszUniTestA[]  = "TST";
 static WCHAR pszUniTestW[] = {'T','S','T',0};
 
@@ -414,15 +414,14 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, HEADER_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
@@ -1572,7 +1571,6 @@ static void test_header_order (void)
     {
         hdi.lParam = i;
         SendMessageA(hWndHeader, HDM_INSERTITEMA, rand1[i], (LPARAM)&hdi);
-        rand();
     }
     check_order(ids1, ord1, 5, "insert without iOrder");
 
@@ -1582,7 +1580,6 @@ static void test_header_order (void)
         hdi.lParam = i + 5;
         hdi.iOrder = rand2[i];
         SendMessageA(hWndHeader, HDM_INSERTITEMA, rand3[i], (LPARAM)&hdi);
-        rand(); rand();
     }
     check_order(ids2, ord2, 10, "insert with order");
 
@@ -1591,7 +1588,6 @@ static void test_header_order (void)
     {
         hdi.iOrder = rand5[i];
         SendMessageA(hWndHeader, HDM_SETITEMA, rand4[i], (LPARAM)&hdi);
-        rand(); rand();
     }
     check_order(ids2, ord3, 10, "setitems changing order");
 
index ddcecbd..3ffa68b 100644 (file)
@@ -922,36 +922,34 @@ static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, IN
     char *data;
     HRESULT hr;
 
-    trace("%s\n", comment);
-
     ret = ImageList_GetImageCount(himl);
-    ok(ret == cur, "expected image count %d got %d\n", cur, ret);
+    ok(ret == cur, "%s: expected image count %d got %d\n", comment, cur, ret);
 
     ret = ImageList_GetIconSize(himl, &cxx, &cyy);
     ok(ret, "ImageList_GetIconSize failed\n");
-    ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
-    ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
+    ok(cxx == cx, "%s: wrong cx %d (expected %d)\n", comment, cxx, cx);
+    ok(cyy == cy, "%s: wrong cy %d (expected %d)\n", comment, cyy, cy);
 
     init_memstream(&stream);
     ret = ImageList_Write(himl, &stream.IStream_iface);
-    ok(ret, "ImageList_Write failed\n");
+    ok(ret, "%s: ImageList_Write failed\n", comment);
 
     hr = GetHGlobalFromStream(stream.stream, &hglobal);
-    ok(hr == S_OK, "Failed to get hglobal, %#x\n", hr);
+    ok(hr == S_OK, "%s: Failed to get hglobal, %#x\n", comment, hr);
 
     IStream_Stat(stream.stream, &stat, STATFLAG_NONAME);
 
     data = GlobalLock(hglobal);
 
-    ok(data != 0, "ImageList_Write didn't write any data\n");
-    ok(stat.cbSize.LowPart > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
+    ok(data != 0, "%s: ImageList_Write didn't write any data\n", comment);
+    ok(stat.cbSize.LowPart > sizeof(ILHEAD), "%s: ImageList_Write wrote not enough data\n", comment);
 
     check_ilhead_data(data, cx, cy, cur, max, grow, flags);
     size = check_bitmap_data(data + sizeof(ILHEAD), stat.cbSize.LowPart - sizeof(ILHEAD),
             width, height, flags & 0xfe, comment);
     if (size < stat.cbSize.LowPart - sizeof(ILHEAD))  /* mask is present */
     {
-        ok( flags & ILC_MASK, "extra data %u/%u but mask not expected\n", stat.cbSize.LowPart, size );
+        ok( flags & ILC_MASK, "%s: extra data %u/%u but mask not expected\n", comment, stat.cbSize.LowPart, size );
         check_bitmap_data(data + sizeof(ILHEAD) + size, stat.cbSize.LowPart - sizeof(ILHEAD) - size,
                           width, height, 1, comment);
     }
@@ -960,7 +958,7 @@ static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, IN
     mv.QuadPart = 0;
     IStream_Seek(stream.stream, mv, STREAM_SEEK_SET, NULL);
     himl2 = ImageList_Read(&stream.IStream_iface);
-    ok(himl2 != NULL, "Failed to deserialize imagelist\n");
+    ok(himl2 != NULL, "%s: Failed to deserialize imagelist\n", comment);
     ImageList_Destroy(himl2);
 
     GlobalUnlock(hglobal);
@@ -2220,6 +2218,29 @@ static void test_color_table(UINT ilc)
     ImageList_Destroy(himl);
 }
 
+static void test_copy(void)
+{
+    HIMAGELIST dst, src;
+    BOOL ret;
+    int count;
+
+    dst = ImageList_Create(5, 11, ILC_COLOR, 1, 1);
+    count = ImageList_GetImageCount(dst);
+    ok(!count, "ImageList not empty.\n");
+    src = createImageList(7, 13);
+    count = ImageList_GetImageCount(src);
+    ok(count > 2, "Tests need an ImageList with more than 2 images\n");
+
+    /* ImageList_Copy() cannot copy between two ImageLists */
+    ret = ImageList_Copy(dst, 0, src, 2, ILCF_MOVE);
+    ok(!ret, "ImageList_Copy() should have returned FALSE\n");
+    count = ImageList_GetImageCount(dst);
+    ok(count == 0, "Expected no image in dst ImageList, got %d\n", count);
+
+    ImageList_Destroy(dst);
+    ImageList_Destroy(src);
+}
+
 static void test_IImageList_Clone(void)
 {
     IImageList *imgl, *imgl2;
@@ -2370,6 +2391,7 @@ START_TEST(imagelist)
     test_iconsize();
     test_color_table(ILC_COLOR4);
     test_color_table(ILC_COLOR8);
+    test_copy();
 
     FreeLibrary(hComCtl32);
 
index 2c4a7f3..ba3700f 100644 (file)
@@ -710,8 +710,8 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
@@ -744,15 +744,14 @@ static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wPar
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
 
     /* all we need is sizing */
     if (message == WM_WINDOWPOSCHANGING ||
@@ -5076,12 +5075,30 @@ static void test_finditem(void)
     fi.psz = f;
     r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
     expect(0, r);
+
+    fi.flags = LVFI_STRING | LVFI_PARTIAL;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+
+    fi.flags = LVFI_PARTIAL;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+
     /* partial string search, inserted text was "foo" */
     strcpy(f, "fo");
     fi.flags = LVFI_STRING | LVFI_PARTIAL;
     fi.psz = f;
     r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
     expect(0, r);
+
+    fi.flags = LVFI_STRING;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(-1, r);
+
+    fi.flags = LVFI_PARTIAL;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+
     /* partial string search, part after start char */
     strcpy(f, "oo");
     fi.flags = LVFI_STRING | LVFI_PARTIAL;
@@ -5112,12 +5129,22 @@ static void test_finditem(void)
     r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
     expect(-1, r);
 
+    strcpy(f, "o");
+    fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
+    fi.psz = f;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(-1, r);
+
     strcpy(f, "f");
     fi.flags = LVFI_SUBSTRING | LVFI_STRING;
     fi.psz = f;
     r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
     expect(0, r);
 
+    fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
+    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+
     DestroyWindow(hwnd);
 }
 
@@ -5549,6 +5576,43 @@ static void test_LVM_SETITEMTEXT(void)
     DestroyWindow(hwnd);
 }
 
+static void test_LVM_REDRAWITEMS(void)
+{
+    HWND list;
+    DWORD ret;
+
+    list = create_listview_control(LVS_ICON);
+    ok(list != NULL, "failed to create listview window\n");
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
+    expect(TRUE, ret);
+
+    insert_item(list, 0);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
+    expect(TRUE, ret);
+
+    DestroyWindow(list);
+}
+
 static void test_imagelists(void)
 {
     HWND hwnd, header;
@@ -5923,6 +5987,7 @@ START_TEST(listview)
     test_createdragimage();
     test_dispinfo();
     test_LVM_SETITEMTEXT();
+    test_LVM_REDRAWITEMS();
     test_imagelists();
     test_deleteitem();
     test_insertitem();
index 8b0781d..89fc5f7 100644 (file)
@@ -202,29 +202,6 @@ static void test_Alloc(void)
     ok(res == TRUE, "Expected TRUE, got %d\n", res);
 }
 
-static void test_TaskDialogIndirect(void)
-{
-    HINSTANCE hinst;
-    void *ptr, *ptr2;
-
-    hinst = LoadLibraryA("comctl32.dll");
-
-    ptr = GetProcAddress(hinst, "TaskDialogIndirect");
-    if (!ptr)
-    {
-#ifdef __REACTOS__
-        /* Skipped on 2k3 */
-        skip("TaskDialogIndirect not exported by name\n");
-#else
-        win_skip("TaskDialogIndirect not exported by name\n");
-#endif
-        return;
-    }
-
-    ptr2 = GetProcAddress(hinst, (const CHAR*)345);
-    ok(ptr == ptr2, "got wrong pointer for ordinal 345, %p expected %p\n", ptr2, ptr);
-}
-
 static void test_LoadIconWithScaleDown(void)
 {
     static const WCHAR nonexisting_fileW[] = {'n','o','n','e','x','i','s','t','i','n','g','.','i','c','o',0};
@@ -413,7 +390,6 @@ START_TEST(misc)
         return;
 
     test_builtin_classes();
-    test_TaskDialogIndirect();
     test_LoadIconWithScaleDown();
 
     unload_v6_module(ctx_cookie, hCtx);
index ffe9d5d..1ca593e 100644 (file)
@@ -624,15 +624,14 @@ static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
 
     /* some debug output for style changing */
index 2a2ee92..36327d1 100644 (file)
@@ -371,7 +371,7 @@ static void ok_sequence_(struct msg_sequence **seq, int sequence_index,
 
     if(todo && !failcount) /* succeeded yet marked todo */
     {
-        dump++;
+        if (!strcmp(winetest_platform, "wine")) dump++;
         todo_wine
         {
             ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
index 122742a..4eb48be 100644 (file)
 #define NUM_MSG_SEQUENCES   1
 #define PAGER_SEQ_INDEX     0
 
-static HWND parent_wnd;
+static HWND parent_wnd, child1_wnd, child2_wnd;
+
+#define CHILD1_ID 1
+#define CHILD2_ID 2
 
 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
 
@@ -42,6 +45,29 @@ static const struct message set_child_seq[] = {
     { WM_NCCALCSIZE, sent|wparam, TRUE },
     { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE },
     { WM_WINDOWPOSCHANGED, sent },
+    { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD1_ID },
+    { WM_NCCALCSIZE, sent|wparam|id|optional, TRUE, 0, CHILD1_ID },
+    { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD1_ID },
+    { WM_WINDOWPOSCHANGED, sent|id, 0, 0, CHILD1_ID },
+    { WM_SIZE, sent|id|defwinproc|optional, 0, 0, CHILD1_ID },
+    { 0 }
+};
+
+/* This differs from the above message list only in the child window that is
+ * expected to receive the child messages. No message is sent to the old child.
+ * Also child 2 is hidden while child 1 is visible. The pager does not make the
+ * hidden child visible. */
+static const struct message switch_child_seq[] = {
+    { PGM_SETCHILD, sent },
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_NCCALCSIZE, sent|wparam, TRUE },
+    { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE },
+    { WM_WINDOWPOSCHANGED, sent },
+    { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD2_ID },
+    { WM_NCCALCSIZE, sent|wparam|id, TRUE, 0, CHILD2_ID },
+    { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD2_ID },
+    { WM_WINDOWPOSCHANGED, sent|id, 0, 0, CHILD2_ID },
+    { WM_SIZE, sent|id|defwinproc, 0, 0, CHILD2_ID },
     { 0 }
 };
 
@@ -52,7 +78,20 @@ static const struct message set_pos_seq[] = {
     { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE },
     { WM_WINDOWPOSCHANGED, sent },
     { WM_MOVE, sent|optional },
+    /* The WM_SIZE handler sends WM_WINDOWPOSCHANGING, WM_CHILDACTIVATE
+     * and WM_WINDOWPOSCHANGED (which sends WM_MOVE) to the child.
+     * Another WM_WINDOWPOSCHANGING is sent afterwards.
+     *
+     * The 2nd WM_WINDOWPOSCHANGING is unconditional, but the comparison
+     * function is too simple to roll back an accepted message, so we have
+     * to mark the 2nd message optional. */
     { WM_SIZE, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD1_ID }, /* Actually optional. */
+    { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD1_ID }, /* Actually optional. */
+    { WM_WINDOWPOSCHANGED, sent|id|optional, TRUE, 0, CHILD1_ID},
+    { WM_MOVE, sent|id|optional|defwinproc, 0, 0, CHILD1_ID },
+    { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, CHILD1_ID }, /* Actually not optional. */
+    { WM_CHILDACTIVATE, sent|id|optional, 0, 0, CHILD1_ID }, /* Actually not optional. */
     { 0 }
 };
 
@@ -145,13 +184,12 @@ static HWND create_parent_window(void)
 static LRESULT WINAPI pager_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
-    struct message msg;
+    struct message msg = { 0 };
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id     = 0;
     add_message(sequences, PAGER_SEQ_INDEX, &msg);
     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
 }
@@ -170,9 +208,55 @@ static HWND create_pager_control( DWORD style )
     return hwnd;
 }
 
+static LRESULT WINAPI child_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static LONG defwndproc_counter;
+    struct message msg = { 0 };
+    LRESULT ret;
+
+    msg.message = message;
+    msg.flags = sent | wparam | lparam;
+    if (defwndproc_counter)
+        msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+
+    if (hwnd == child1_wnd)
+        msg.id = CHILD1_ID;
+    else if (hwnd == child2_wnd)
+        msg.id = CHILD2_ID;
+    else
+        msg.id = 0;
+
+    add_message(sequences, PAGER_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_child_wnd_class(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = child_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Pager test child class";
+    return RegisterClassA(&cls);
+}
+
 static void test_pager(void)
 {
-    HWND pager, child;
+    HWND pager;
     RECT rect, rect2;
 
     pager = create_pager_control( PGS_HORZ );
@@ -181,16 +265,36 @@ static void test_pager(void)
         win_skip( "Pager control not supported\n" );
         return;
     }
-    child = CreateWindowA( "BUTTON", "button", WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 300, 300,
+
+    register_child_wnd_class();
+
+    child1_wnd = CreateWindowA( "Pager test child class", "button", WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 300, 300,
                            pager, 0, GetModuleHandleA(0), 0 );
+    child2_wnd = CreateWindowA("Pager test child class", "button", WS_CHILD | WS_BORDER, 0, 0, 300, 300,
+        pager, 0, GetModuleHandleA(0), 0);
 
     flush_sequences( sequences, NUM_MSG_SEQUENCES );
-    SendMessageA( pager, PGM_SETCHILD, 0, (LPARAM)child );
-    ok_sequence(sequences, PAGER_SEQ_INDEX, set_child_seq, "set child", TRUE);
+    SendMessageA( pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd );
+    ok_sequence(sequences, PAGER_SEQ_INDEX, set_child_seq, "set child", FALSE);
     GetWindowRect( pager, &rect );
     ok( rect.right - rect.left == 100 && rect.bottom - rect.top == 100,
         "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top );
 
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    SendMessageA(pager, PGM_SETCHILD, 0, (LPARAM)child2_wnd);
+    ok_sequence(sequences, PAGER_SEQ_INDEX, switch_child_seq, "switch to invisible child", FALSE);
+    GetWindowRect(pager, &rect);
+    ok(rect.right - rect.left == 100 && rect.bottom - rect.top == 100,
+        "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top);
+    ok(!IsWindowVisible(child2_wnd), "Child window 2 is visible\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    SendMessageA(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd);
+    ok_sequence(sequences, PAGER_SEQ_INDEX, set_child_seq, "switch to visible child", FALSE);
+    GetWindowRect(pager, &rect);
+    ok(rect.right - rect.left == 100 && rect.bottom - rect.top == 100,
+        "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top);
+
     flush_sequences( sequences, NUM_MSG_SEQUENCES );
     SendMessageA( pager, PGM_SETPOS, 0, 10 );
     ok_sequence(sequences, PAGER_SEQ_INDEX, set_pos_seq, "set pos", TRUE);
index 0189c64..76e706a 100644 (file)
@@ -713,7 +713,7 @@ static const struct message property_sheet_seq[] = {
 
 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
 {
-    struct message msg;
+    struct message msg = { 0 };
 
     if (message < WM_USER &&
         message != WM_GETICON &&
@@ -990,6 +990,141 @@ if (0)
     DestroyWindow(hdlg);
 }
 
+struct custom_proppage
+{
+    union
+    {
+        PROPSHEETPAGEA pageA;
+        PROPSHEETPAGEW pageW;
+    } u;
+    unsigned int addref_called;
+    unsigned int release_called;
+};
+
+static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp)
+{
+    struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
+    PROPSHEETPAGEA *psp_orig = &cpage->u.pageA;
+
+    ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
+
+    ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
+            psp->lParam, psp);
+    ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
+    ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
+
+    switch (msg)
+    {
+    case PSPCB_ADDREF:
+        ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
+        cpage->addref_called++;
+        break;
+    case PSPCB_RELEASE:
+        ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
+        cpage->release_called++;
+        break;
+    default:
+        ok(0, "Unexpected message %u\n", msg);
+    }
+
+    return 1;
+}
+
+static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp)
+{
+    struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
+    PROPSHEETPAGEW *psp_orig = &cpage->u.pageW;
+
+    ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
+    ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
+            psp->lParam, psp);
+    ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
+    ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
+
+    switch (msg)
+    {
+    case PSPCB_ADDREF:
+        ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
+        cpage->addref_called++;
+        break;
+    case PSPCB_RELEASE:
+        ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
+        cpage->release_called++;
+        break;
+    default:
+        ok(0, "Unexpected message %u\n", msg);
+    }
+
+    return 1;
+}
+
+static void test_CreatePropertySheetPage(void)
+{
+    static const WCHAR titleW[] = {'T','i','t','l','e',0};
+    struct custom_proppage page;
+    HPROPSHEETPAGE hpsp;
+    BOOL ret;
+
+    memset(&page.u.pageA, 0, sizeof(page.u.pageA));
+    page.u.pageA.dwFlags = PSP_USECALLBACK;
+    page.u.pageA.pfnDlgProc = page_dlg_proc_messages;
+    page.u.pageA.pfnCallback = proppage_callback_a;
+    page.u.pageA.lParam = (LPARAM)&page;
+    page.u.pageA.pszTitle = "Title";
+
+    /* Only minimal size validation is performed */
+    for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1; page.u.pageA.dwSize <= PROPSHEETPAGEA_V4_SIZE + 1; page.u.pageA.dwSize++)
+    {
+        page.addref_called = 0;
+        hpsp = CreatePropertySheetPageA(&page.u.pageA);
+
+        if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE)
+            ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageA.dwSize);
+        else
+        {
+            ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageA.dwSize);
+            ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
+        }
+
+        if (hpsp)
+        {
+            page.release_called = 0;
+            ret = DestroyPropertySheetPage(hpsp);
+            ok(ret, "Failed to destroy a page\n");
+            ok(page.release_called == 1, "Expected RELEASE callback message\n");
+        }
+    }
+
+    memset(&page.u.pageW, 0, sizeof(page.u.pageW));
+    page.u.pageW.dwFlags = PSP_USECALLBACK;
+    page.u.pageW.pfnDlgProc = page_dlg_proc_messages;
+    page.u.pageW.pfnCallback = proppage_callback_w;
+    page.u.pageW.lParam = (LPARAM)&page;
+    page.u.pageW.pszTitle = titleW;
+
+    for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1; page.u.pageW.dwSize <= PROPSHEETPAGEW_V4_SIZE + 1; page.u.pageW.dwSize++)
+    {
+        page.addref_called = 0;
+        hpsp = CreatePropertySheetPageW(&page.u.pageW);
+
+        if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE)
+            ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageW.dwSize);
+        else
+        {
+            ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageW.dwSize);
+            ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
+        }
+
+        if (hpsp)
+        {
+            page.release_called = 0;
+            ret = DestroyPropertySheetPage(hpsp);
+            ok(ret, "Failed to destroy a page\n");
+            ok(page.release_called == 1, "Expected RELEASE callback message\n");
+        }
+    }
+}
+
 START_TEST(propsheet)
 {
     test_title();
@@ -1001,4 +1136,5 @@ START_TEST(propsheet)
     test_messages();
     test_PSM_ADDPAGE();
     test_PSM_INSERTPAGE();
+    test_CreatePropertySheetPage();
 }
index 0e523b9..9f7233f 100644 (file)
@@ -146,15 +146,14 @@ static WNDPROC syslink_oldproc;
 static LRESULT WINAPI syslink_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, SYSLINK_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
index bbc1188..431a49d 100644 (file)
@@ -304,8 +304,8 @@ create_tabcontrol (DWORD style, DWORD mask)
 static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     /* do not log painting messages */
     if (message != WM_PAINT &&
@@ -321,7 +321,6 @@ static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam
         if (defwndproc_counter) msg.flags |= defwinproc;
         msg.wParam = wParam;
         msg.lParam = lParam;
-        msg.id = 0;
         add_message(sequences, PARENT_SEQ_INDEX, &msg);
     }
 
@@ -367,8 +366,8 @@ static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam,
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     /* do not log painting messages */
     if (message != WM_PAINT &&
@@ -384,7 +383,6 @@ static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam,
         if (defwndproc_counter) msg.flags |= defwinproc;
         msg.wParam = wParam;
         msg.lParam = lParam;
-        msg.id = 0;
         add_message(sequences, TAB_SEQ_INDEX, &msg);
     }
 
diff --git a/rostests/winetests/comctl32/taskdialog.c b/rostests/winetests/comctl32/taskdialog.c
new file mode 100644 (file)
index 0000000..8a9d164
--- /dev/null
@@ -0,0 +1,58 @@
+/* Unit tests for the task dialog control.
+ *
+ * Copyright 2017 Fabian Maurer for the Wine project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "commctrl.h"
+
+#include "wine/test.h"
+#include "v6util.h"
+
+static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, int *, BOOL *);
+
+START_TEST(taskdialog)
+{
+    ULONG_PTR ctx_cookie;
+    void *ptr_ordinal;
+    HINSTANCE hinst;
+    HANDLE hCtx;
+
+    if (!load_v6_module(&ctx_cookie, &hCtx))
+        return;
+
+    /* Check if task dialogs are available */
+    hinst = LoadLibraryA("comctl32.dll");
+
+    pTaskDialogIndirect = (void *)GetProcAddress(hinst, "TaskDialogIndirect");
+    if (!pTaskDialogIndirect)
+    {
+        win_skip("TaskDialogIndirect not exported by name\n");
+        unload_v6_module(ctx_cookie, hCtx);
+        return;
+    }
+
+    ptr_ordinal = GetProcAddress(hinst, (const char *)345);
+    ok(pTaskDialogIndirect == ptr_ordinal, "got wrong pointer for ordinal 345, %p expected %p\n",
+                                            ptr_ordinal, pTaskDialogIndirect);
+
+    unload_v6_module(ctx_cookie, hCtx);
+}
index 7f91ecb..2abb83a 100644 (file)
@@ -23,6 +23,7 @@ extern void func_status(void);
 extern void func_subclass(void);
 extern void func_syslink(void);
 extern void func_tab(void);
+extern void func_taskdialog(void);
 extern void func_toolbar(void);
 extern void func_tooltips(void);
 extern void func_trackbar(void);
@@ -51,6 +52,7 @@ const struct test winetest_testlist[] =
     { "subclass", func_subclass },
     { "syslink", func_syslink },
     { "tab", func_tab },
+    { "taskdialog", func_taskdialog },
     { "toolbar", func_toolbar },
     { "tooltips", func_tooltips },
     { "trackbar", func_trackbar },
index a8bcd40..2d12732 100644 (file)
@@ -2276,7 +2276,8 @@ static void test_save(void)
 {
     HWND wnd = NULL;
     TBSAVEPARAMSW params;
-    static const WCHAR subkey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','T','e','s','t',0};
+    static const WCHAR subkey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
+                                   'W','i','n','e','T','e','s','t',0};
     static const WCHAR value[] = {'t','o','o','l','b','a','r','t','e','s','t',0};
     LONG res;
     HKEY key;
index 3d48683..0bbe97c 100644 (file)
@@ -442,15 +442,14 @@ static HWND create_parent_window(void){
 static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, TRACKBAR_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
index a4b4747..83ba492 100644 (file)
@@ -54,6 +54,21 @@ static BOOL g_v6;
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 static struct msg_sequence *item_sequence[1];
 
+static void flush_events(void)
+{
+    MSG msg;
+    int diff = 200;
+    int min_timeout = 100;
+    DWORD time = GetTickCount() + diff;
+
+    while (diff > 0)
+    {
+        if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
+        while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+        diff = time - GetTickCount();
+    }
+}
+
 static const struct message FillRootSeq[] = {
     { TVM_INSERTITEMA, sent },
     { TVM_INSERTITEMA, sent },
@@ -201,6 +216,13 @@ static const struct message test_get_set_unicodeformat_seq[] = {
     { 0 }
 };
 
+static const struct message test_right_click_seq[] = {
+    { WM_RBUTTONDOWN, sent|wparam, MK_RBUTTON },
+    { WM_CAPTURECHANGED, sent|defwinproc },
+    { TVM_GETNEXTITEM, sent|wparam|lparam|defwinproc, TVGN_CARET, 0 },
+    { 0 }
+};
+
 static const struct message parent_expand_seq[] = {
     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
@@ -342,6 +364,12 @@ static const struct message parent_vk_return_seq[] = {
     { 0 }
 };
 
+static const struct message parent_right_click_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, NM_RCLICK },
+    { WM_CONTEXTMENU, sent },
+    { 0 }
+};
+
 static HWND hMainWnd;
 
 static HTREEITEM hRoot, hChild;
@@ -383,15 +411,14 @@ static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LP
 {
     static LONG defwndproc_counter = 0;
     LRESULT ret;
-    struct message msg;
     WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    struct message msg = { 0 };
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
-    msg.id = 0;
     add_message(sequences, TREEVIEW_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
@@ -1099,7 +1126,7 @@ static void test_get_set_unicodeformat(void)
 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
-    struct message msg;
+    struct message msg = { 0 };
     LRESULT ret;
     RECT rect;
     HTREEITEM visibleItem;
@@ -1111,8 +1138,6 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
     msg.lParam = lParam;
     if (message == WM_NOTIFY && lParam)
         msg.id = ((NMHDR*)lParam)->code;
-    else
-        msg.id = 0;
 
     /* log system messages, except for painting */
     if (message < WM_USER &&
@@ -1299,6 +1324,13 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
                 }
                 break;
             }
+            case NM_RCLICK:
+            {
+                HTREEITEM selected = (HTREEITEM)SendMessageA(((NMHDR *)lParam)->hwndFrom,
+                                                             TVM_GETNEXTITEM, TVGN_CARET, 0);
+                ok(selected == hChild, "child item should still be selected\n");
+                break;
+            }
             }
         }
         break;
@@ -2397,6 +2429,238 @@ static void test_TVS_FULLROWSELECT(void)
     DestroyWindow(hwnd);
 }
 
+static void get_item_names_string(HWND hwnd, HTREEITEM item, char *str)
+{
+    TVITEMA tvitem = { 0 };
+    HTREEITEM child;
+    char name[16];
+
+    if (!item)
+    {
+        item = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+        str[0] = 0;
+    }
+
+    child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item);
+
+    tvitem.mask = TVIF_TEXT;
+    tvitem.hItem = item;
+    tvitem.pszText = name;
+    tvitem.cchTextMax = sizeof(name);
+    SendMessageA(hwnd, TVM_GETITEMA, 0, (LPARAM)&tvitem);
+    strcat(str, tvitem.pszText);
+
+    while (child != NULL)
+    {
+        get_item_names_string(hwnd, child, str);
+        child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)child);
+    }
+}
+
+static void fill_treeview_sort_test(HWND hwnd)
+{
+    static const char *itemnames[] =
+    {
+        "root", "Wasp", "Caribou", "Vacuum",
+        "Ocelot", "Newspaper", "Litter bin"
+    };
+
+    HTREEITEM root, children[2];
+    TVINSERTSTRUCTA ins;
+    unsigned i = 0;
+
+    SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
+
+    /* root, two children, with two children each */
+    ins.hParent = TVI_ROOT;
+    ins.hInsertAfter = TVI_ROOT;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = (char *)itemnames[i++];
+    root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    ins.hParent = root;
+    ins.hInsertAfter = TVI_LAST;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = (char *)itemnames[i++];
+    children[0] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    U(ins).item.pszText = (char *)itemnames[i++];
+    children[1] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    ins.hParent = children[0];
+    U(ins).item.pszText = (char *)itemnames[i++];
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    U(ins).item.pszText = (char *)itemnames[i++];
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    ins.hParent = children[1];
+    U(ins).item.pszText = (char *)itemnames[i++];
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    U(ins).item.pszText = (char *)itemnames[i++];
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+}
+
+static void test_TVM_SORTCHILDREN(void)
+{
+    static const char *initial_order = "rootWaspVacuumOcelotCaribouNewspaperLitter bin";
+    static const char *sorted_order = "rootCaribouNewspaperLitter binWaspVacuumOcelot";
+    TVINSERTSTRUCTA ins;
+    char buff[256];
+    HTREEITEM root;
+    HWND hwnd;
+    BOOL ret;
+
+    hwnd = create_treeview_control(0);
+
+    /* call on empty tree */
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0);
+    ok(!ret, "Unexpected ret value %d\n", ret);
+
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT);
+    ok(!ret, "Unexpected ret value %d\n", ret);
+
+    /* add only root, sort from it */
+    ins.hParent = TVI_ROOT;
+    ins.hInsertAfter = TVI_ROOT;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = (char *)"root";
+    root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+    ok(root != NULL, "Expected root node\n");
+
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root);
+    ok(!ret, "Unexpected ret value %d\n", ret);
+
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
+    ok(!ret, "Unexpected ret value %d\n", ret);
+
+    /* root, two children, with two children each */
+    fill_treeview_sort_test(hwnd);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, initial_order), "Wrong initial order %s, expected %s\n", buff, initial_order);
+
+    /* with NULL item nothing is sorted */
+    fill_treeview_sort_test(hwnd);
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0);
+todo_wine
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
+
+    /* TVI_ROOT as item */
+    fill_treeview_sort_test(hwnd);
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT);
+todo_wine
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
+
+    /* zero WPARAM, item is specified */
+    fill_treeview_sort_test(hwnd);
+    root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+    ok(root != NULL, "Failed to get root item\n");
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root);
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
+
+    /* non-zero WPARAM, NULL item */
+    fill_treeview_sort_test(hwnd);
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, 0);
+todo_wine
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
+
+    /* TVI_ROOT as item */
+    fill_treeview_sort_test(hwnd);
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)TVI_ROOT);
+todo_wine
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
+
+    /* non-zero WPARAM, item is specified */
+    fill_treeview_sort_test(hwnd);
+    root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+    ok(root != NULL, "Failed to get root item\n");
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
+
+    /* case insensitive comparison */
+    SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
+
+    ins.hParent = TVI_ROOT;
+    ins.hInsertAfter = TVI_ROOT;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = (char *)"root";
+    root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+    ok(root != NULL, "Expected root node\n");
+
+    ins.hParent = root;
+    ins.hInsertAfter = TVI_LAST;
+    U(ins).item.pszText = (char *)"I1";
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    ins.hParent = root;
+    ins.hInsertAfter = TVI_LAST;
+    U(ins).item.pszText = (char *)"i1";
+    SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
+
+    ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
+    ok(ret, "Unexpected ret value %d\n", ret);
+    get_item_names_string(hwnd, NULL, buff);
+    ok(!strcmp(buff, "rootI1i1"), "Wrong sorted order %s\n", buff);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_right_click(void)
+{
+    HWND hTree;
+    HTREEITEM selected;
+    RECT rc;
+    LRESULT result;
+    POINT pt;
+
+    hTree = create_treeview_control(0);
+    fill_tree(hTree);
+
+    SendMessageA(hTree, TVM_ENSUREVISIBLE, 0, (LPARAM)hChild);
+    SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
+    selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
+    ok(selected == hChild, "child item not selected\n");
+
+    *(HTREEITEM *)&rc = hRoot;
+    result = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
+    ok(result, "TVM_GETITEMRECT failed\n");
+
+    flush_events();
+
+    pt.x = (rc.left + rc.right) / 2;
+    pt.y = (rc.top + rc.bottom) / 2;
+    ClientToScreen(hMainWnd, &pt);
+
+    flush_events();
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    PostMessageA(hTree, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(pt.x, pt.y));
+    PostMessageA(hTree, WM_RBUTTONUP, 0, MAKELPARAM(pt.x, pt.y));
+
+    flush_events();
+
+    ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_right_click_seq, "right click sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_right_click_seq, "parent right click sequence", FALSE);
+
+    selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
+    ok(selected == hChild, "child item should still be selected\n");
+
+    DestroyWindow(hTree);
+}
+
 START_TEST(treeview)
 {
     HMODULE hComctl32;
@@ -2473,6 +2737,8 @@ START_TEST(treeview)
     test_customdraw();
     test_WM_KEYDOWN();
     test_TVS_FULLROWSELECT();
+    test_TVM_SORTCHILDREN();
+    test_right_click();
 
     if (!load_v6_module(&ctx_cookie, &hCtx))
     {
index 8a963d9..fb5ade4 100644 (file)
@@ -169,8 +169,8 @@ static const struct message test_updown_pos_nochange_seq[] = {
 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     /* log system messages, except for painting */
     if (message < WM_USER &&
@@ -187,7 +187,6 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
         if (defwndproc_counter) msg.flags |= defwinproc;
         msg.wParam = wParam;
         msg.lParam = lParam;
-        msg.id = 0;
         add_message(sequences, PARENT_SEQ_INDEX, &msg);
     }
 
@@ -232,8 +231,8 @@ static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam,
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;
@@ -272,8 +271,8 @@ static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
+    struct message msg = { 0 };
     LRESULT ret;
-    struct message msg;
 
     msg.message = message;
     msg.flags = sent|wparam|lparam;