[COMCTL32_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 14 Dec 2012 23:24:10 +0000 (23:24 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 14 Dec 2012 23:24:10 +0000 (23:24 +0000)
* Sync with Wine 1.5.19.

svn path=/trunk/; revision=57915

19 files changed:
rostests/winetests/comctl32/CMakeLists.txt
rostests/winetests/comctl32/comboex.c
rostests/winetests/comctl32/datetime.c
rostests/winetests/comctl32/imagelist.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/mru.c
rostests/winetests/comctl32/pager.c [new file with mode: 0644]
rostests/winetests/comctl32/propsheet.c
rostests/winetests/comctl32/resources.h
rostests/winetests/comctl32/rsrc.rc
rostests/winetests/comctl32/status.c
rostests/winetests/comctl32/syslink.c [new file with mode: 0644]
rostests/winetests/comctl32/tab.c
rostests/winetests/comctl32/testlist.c
rostests/winetests/comctl32/toolbar.c
rostests/winetests/comctl32/tooltips.c
rostests/winetests/comctl32/trackbar.c
rostests/winetests/comctl32/treeview.c

index b85b4df..2326087 100644 (file)
@@ -14,11 +14,13 @@ list(APPEND SOURCE
     misc.c
     monthcal.c
     mru.c
+    pager.c
     progress.c
     propsheet.c
     rebar.c
     status.c
     subclass.c
+    syslink.c
     tab.c
     toolbar.c
     tooltips.c
index 172e564..7cddbaf 100644 (file)
@@ -345,6 +345,11 @@ static void test_WM_LBUTTONDOWN(void)
        "Current Selection: expected %d, got %d\n", 4, idx);
     ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n");
 
+    SetFocus( hComboExParentWnd );
+    ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() );
+    SetFocus( hComboEx );
+    ok( GetFocus() == hEdit, "got %p\n", GetFocus() );
+
     DestroyWindow(hComboEx);
 }
 
index 171da5c..24d339f 100644 (file)
@@ -121,6 +121,18 @@ static const struct message test_dtm_set_and_get_system_time_seq[] = {
     { 0 }
 };
 
+static const struct message test_dtm_set_and_get_systime_with_limits[] = {
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { 0 }
+};
+
 static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
@@ -660,6 +672,55 @@ static void test_dtm_set_and_get_system_time(void)
     expect(4, (LRESULT)getSt.wDayOfWeek);
     st.wDayOfWeek = 4;
     expect_systime(&st, &getSt);
+}
+
+static void test_dtm_set_and_get_systemtime_with_limits(void)
+{
+    LRESULT r;
+    SYSTEMTIME st[2], getSt[2], refSt;
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* set range */
+    fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
+    fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+    expect_systime(&st[1], &getSt[1]);
+
+    /* Initially set a valid time */
+    fill_systime_struct(&refSt, 1999, 9, 4, 9, 19, 9, 9, 999);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&refSt);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    expect_systime(&refSt, &getSt[0]);
+
+    /* Now set an out-of-bounds time */
+    fill_systime_struct(&st[0], 2010, 1, 0, 1, 0, 0, 0, 0);
+
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    expect_systime(&refSt, &getSt[0]);
+
+    fill_systime_struct(&st[0], 1977, 1, 0, 1, 0, 0, 0, 0);
+
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    expect_systime(&refSt, &getSt[0]);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_systime_with_limits, "test_dtm_set_and_get_systime_with_limits", FALSE);
 
     DestroyWindow(hWnd);
 }
@@ -749,6 +810,7 @@ START_TEST(datetime)
     test_dtm_set_and_get_range();
     test_dtm_set_range_swap_min_max();
     test_dtm_set_and_get_system_time();
+    test_dtm_set_and_get_systemtime_with_limits();
     test_wm_set_get_text();
     test_dts_shownone();
 }
index b920b9a..98b84a6 100644 (file)
@@ -619,7 +619,7 @@ static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
     else
         my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
 
-    return my_is->iml_data ? TRUE : FALSE;
+    return my_is->iml_data != NULL;
 }
 
 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(IStream *iface, const void *pv, ULONG cb,
@@ -1423,7 +1423,7 @@ static void test_iimagelist(void)
 
     /* test reference counting on destruction */
     imgl = (IImageList*)createImageList(32, 32);
-    ret = IUnknown_AddRef(imgl);
+    ret = IImageList_AddRef(imgl);
     ok(ret == 2, "Expected 2, got %d\n", ret);
     ret = ImageList_Destroy((HIMAGELIST)imgl);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -1433,7 +1433,7 @@ static void test_iimagelist(void)
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
 
     imgl = (IImageList*)createImageList(32, 32);
-    ret = IUnknown_AddRef(imgl);
+    ret = IImageList_AddRef(imgl);
     ok(ret == 2, "Expected 2, got %d\n", ret);
     ret = ImageList_Destroy((HIMAGELIST)imgl);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
index b3df59e..255ef50 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2006 Mike McCormack for CodeWeavers
  * Copyright 2007 George Gov
- * Copyright 2009-2011 Nikolay Sivov
+ * Copyright 2009-2012 Nikolay Sivov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -50,11 +50,11 @@ static HWND hwndparent, hwndparentW;
 static BOOL blockEdit;
 /* return nonzero on NM_HOVER */
 static BOOL g_block_hover;
-/* dumps LVN_ITEMCHANGED message data */
-static BOOL g_dump_itemchanged;
+/* notification data for LVN_ITEMCHANGED */
+static NMLISTVIEW g_nmlistview;
 /* format reported to control:
    -1 falls to defproc, anything else returned */
-static INT  notifyFormat;
+static INT notifyFormat;
 /* indicates we're running < 5.80 version */
 static BOOL g_is_below_5;
 /* item data passed to LVN_GETDISPINFOA */
@@ -391,11 +391,9 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
               }
               break;
           case LVN_ITEMCHANGED:
-              if (g_dump_itemchanged)
               {
                   NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
-                  trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
-                         nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
+                  g_nmlistview = *nmlv;
               }
               break;
           case LVN_GETDISPINFOA:
@@ -2092,7 +2090,6 @@ static void test_multiselect(void)
         { "using VK_HOME", -1, VK_HOME, 1, -1 }
     };
 
-
     hwnd = create_listview_control(LVS_REPORT);
 
     for (i=0;i<items;i++) {
@@ -2239,6 +2236,131 @@ static void test_multiselect(void)
     r = ListView_GetSelectedCount(hwnd);
     expect(0, r);
 
+    /* 1. selection mark is update when new focused item is set */
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
+
+    r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
+    expect(-1, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(0, r);
+
+    /* it's not updated if already set */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(0, r);
+
+    r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
+    expect(0, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(-1, r);
+
+    /* need to reset focused item first */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(2, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(2, r);
+
+    /* 2. same tests, with LVM_SETITEM */
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
+
+    r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
+    expect(2, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    item.mask      = LVIF_STATE;
+    item.iItem = item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(0, r);
+
+    /* it's not updated if already set */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    item.mask      = LVIF_STATE;
+    item.iItem     = 1;
+    item.iSubItem  = 0;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(0, r);
+
+    r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
+    expect(0, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    item.mask      = LVIF_STATE;
+    item.iItem     = 1;
+    item.iSubItem  = 0;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(-1, r);
+
+    /* need to reset focused item first */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    item.mask      = LVIF_STATE;
+    item.iItem     = 2;
+    item.iSubItem  = 0;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(2, r);
+
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+    expect(2, r);
+
     DestroyWindow(hwnd);
 }
 
@@ -2629,6 +2751,8 @@ static void test_sorting(void)
 
 static void test_ownerdata(void)
 {
+    static char test_str[] = "test";
+
     HWND hwnd;
     LONG_PTR style, ret;
     DWORD res;
@@ -2713,7 +2837,7 @@ static void test_ownerdata(void)
     expect(1, res);
     DestroyWindow(hwnd);
 
-    /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
+    /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
@@ -2727,6 +2851,10 @@ static void test_ownerdata(void)
     item.state     = LVIS_SELECTED;
     res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
     expect(FALSE, res);
+    memset(&item, 0, sizeof(item));
+    item.pszText = test_str;
+    res = SendMessageA(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
+    expect(FALSE, res);
     DestroyWindow(hwnd);
 
     /* check notifications after focused/selected changed */
@@ -2768,35 +2896,68 @@ static void test_ownerdata(void)
     item.stateMask = LVIS_SELECTED;
     item.state     = LVIS_SELECTED;
 
-    g_dump_itemchanged = TRUE;
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
 
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
-                "ownerdata select all notification", TRUE);
+                "ownerdata select all notification", FALSE);
 
     /* select all again, note that all items are selected already */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_SELECTED;
     item.state     = LVIS_SELECTED;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
-                "ownerdata select all notification", TRUE);
+                "ownerdata select all notification", FALSE);
+
     /* deselect all */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_SELECTED;
     item.state     = 0;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
                 "ownerdata deselect all notification", TRUE);
 
+    /* nothing selected, deselect all again */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_SELECTED;
+    item.state     = 0;
+
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", TRUE);
+
     /* select one, then deselect all */
     item.stateMask = LVIS_SELECTED;
     item.state     = LVIS_SELECTED;
@@ -2805,10 +2966,18 @@ static void test_ownerdata(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_SELECTED;
     item.state     = 0;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
                 "ownerdata select all notification", TRUE);
 
@@ -2824,16 +2993,18 @@ static void test_ownerdata(void)
     item.stateMask = LVIS_FOCUSED;
     res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
     expect(0, res);
+
     /* setting all to focused returns failure value */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_FOCUSED;
     item.state     = LVIS_FOCUSED;
-    g_dump_itemchanged = TRUE;
+
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(FALSE, res);
-    g_dump_itemchanged = FALSE;
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                 "ownerdata focus all notification", FALSE);
+
     /* focus single item, remove all */
     item.stateMask = LVIS_FOCUSED;
     item.state     = LVIS_FOCUSED;
@@ -2842,32 +3013,58 @@ static void test_ownerdata(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_FOCUSED;
     item.state     = 0;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
                 "ownerdata remove focus all notification", TRUE);
+
     /* set all cut */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_CUT;
     item.state     = LVIS_CUT;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
-                "ownerdata cut all notification", TRUE);
+                "ownerdata cut all notification", FALSE);
+
     /* all marked cut, try again */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     item.stateMask = LVIS_CUT;
     item.state     = LVIS_CUT;
-    g_dump_itemchanged = TRUE;
+
+    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
     expect(TRUE, res);
-    g_dump_itemchanged = FALSE;
+    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
+    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
+    ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
+    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
+    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
+    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
+    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
+
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
-                "ownerdata cut all notification #2", TRUE);
+                "ownerdata cut all notification #2", FALSE);
 
     DestroyWindow(hwnd);
 
index 0585bb4..1fed831 100644 (file)
@@ -41,6 +41,8 @@
 #define PARENT_SEQ_INDEX    0
 #define MONTHCAL_SEQ_INDEX  1
 
+#define SEL_NOTIFY_TEST_ID  100
+
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
 static HWND parent_wnd;
@@ -385,6 +387,7 @@ static void test_monthcal(void)
 
     /* set both limits, then set max < min */
     GetSystemTime(&st[0]);
+    st[0].wDay = 25;
     st[1] = st[0];
     st[1].wYear++;
     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
@@ -484,6 +487,39 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
 
             return TRUE;
           }
+          case MCN_SELECT:
+          case MCN_SELCHANGE:
+          {
+            NMSELCHANGE *nmchg = (NMSELCHANGE*)lParam;
+            SYSTEMTIME st[2];
+            BOOL is_multisel = GetWindowLongPtr(nmchg->nmhdr.hwndFrom, GWL_STYLE) &
+                        MCS_MULTISELECT;
+
+            if(GetWindowLongPtr(nmchg->nmhdr.hwndFrom, GWLP_ID) != SEL_NOTIFY_TEST_ID)
+              break;
+            SendMessage(nmchg->nmhdr.hwndFrom, is_multisel ? MCM_GETSELRANGE :
+                        MCM_GETCURSEL, 0, (LPARAM)st);
+
+            expect(st[0].wYear,  nmchg->stSelStart.wYear);
+            expect(st[0].wMonth, nmchg->stSelStart.wMonth);
+            expect(0,            nmchg->stSelStart.wDayOfWeek);
+            expect(st[0].wDay,   nmchg->stSelStart.wDay);
+
+            if(is_multisel)
+            {
+              expect(st[1].wYear,  nmchg->stSelEnd.wYear);
+              expect(st[1].wMonth, nmchg->stSelEnd.wMonth);
+              expect(0,            nmchg->stSelEnd.wDayOfWeek);
+              expect(st[1].wDay,   nmchg->stSelEnd.wDay);
+            }
+            else
+              ok(!(nmchg->stSelEnd.wYear | nmchg->stSelEnd.wMonth |
+                        nmchg->stSelEnd.wDayOfWeek | nmchg->stSelEnd.wDay |
+                        nmchg->stSelEnd.wHour | nmchg->stSelEnd.wMinute |
+                        nmchg->stSelEnd.wSecond | nmchg->stSelEnd.wMilliseconds),
+                        "Non-zero member in stSelEnd\n");
+            return TRUE;
+          }
           default:
             break;
         }
@@ -1918,6 +1954,51 @@ static void test_daystate(void)
     DestroyWindow(hwnd);
 }
 
+static void test_sel_notify(void)
+{
+    typedef struct
+    {
+        DWORD       val;
+        const char* name;
+    } Monthcal_style;
+
+    HWND hwnd;
+    RECT rc;
+    MCHITTESTINFO mchit = {sizeof(MCHITTESTINFO)};
+    SYSTEMTIME st;
+    Monthcal_style styles[] = {
+        {MCS_NOTODAY,                    "MCS_NOTODAY"},
+        {MCS_NOTODAY | MCS_MULTISELECT,  "MCS_NOTODAY | MCS_MULTISELECT"},
+        {MCS_DAYSTATE,                   "MCS_DAYSTATE"},
+        {MCS_DAYSTATE | MCS_MULTISELECT, "MCS_DAYSTATE | MCS_MULTISELECT"}
+    };
+    int i;
+
+    for(i = 0; i < sizeof styles / sizeof styles[0]; i++)
+    {
+        trace("%s\n", styles[i].name);
+        hwnd = create_monthcal_control(styles[i].val);
+        SetWindowLongPtr(hwnd, GWLP_ID, SEL_NOTIFY_TEST_ID);
+        assert(hwnd);
+        SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&rc);
+        MoveWindow(hwnd, 0, 0, rc.right, rc.bottom, FALSE);
+        /* Simulate mouse click on some unselected day to generate
+            MCN_SELECT and MCN_SELCHANGE notifications */
+        mchit.pt.x = rc.right / 2;
+        mchit.pt.y = rc.bottom / 2;
+        SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
+        SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st);
+        while(st.wDay == mchit.st.wDay) /* Ensure that mchit.pt points to unselected day */
+        {
+            mchit.pt.y++;
+            SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
+        }
+        SendMessage(hwnd, WM_LBUTTONDOWN, 0, MAKELPARAM(mchit.pt.x, mchit.pt.y));
+        SendMessage(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(mchit.pt.x, mchit.pt.y));
+        DestroyWindow(hwnd);
+    }
+}
+
 START_TEST(monthcal)
 {
     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
@@ -1961,6 +2042,7 @@ START_TEST(monthcal)
     test_selrange();
     test_killfocus();
     test_daystate();
+    test_sel_notify();
 
     if (!load_v6_module(&ctx_cookie, &hCtx))
     {
index 86eddc0..1d8ad9a 100644 (file)
@@ -45,7 +45,7 @@ typedef struct tagMRUINFOA
     UINT    fFlags;
     HKEY    hKey;
     LPCSTR  lpszSubKey;
-    PROC    lpfnCompare;
+    int (CALLBACK *lpfnCompare)(LPCSTR, LPCSTR);
 } MRUINFOA;
 
 typedef struct tagMRUINFOW
@@ -55,7 +55,7 @@ typedef struct tagMRUINFOW
     UINT    fFlags;
     HKEY    hKey;
     LPCWSTR lpszSubKey;
-    PROC    lpfnCompare;
+    int (CALLBACK *lpfnCompare)(LPCWSTR, LPCWSTR);
 } MRUINFOW;
 
 #define MRU_STRING     0  /* this one's invented */
@@ -221,7 +221,7 @@ static void check_reg_entries(const char *mrulist, const char**items)
     }
 }
 
-static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
+static int CALLBACK cmp_mru_strA(LPCSTR data1, LPCSTR data2)
 {
     return lstrcmpiA(data1, data2);
 }
@@ -252,7 +252,7 @@ static void test_MRUListA(void)
     infoA.fFlags = MRU_STRING;
     infoA.hKey = NULL;
     infoA.lpszSubKey = REG_TEST_SUBKEYA;
-    infoA.lpfnCompare = (PROC)cmp_mru_strA;
+    infoA.lpfnCompare = cmp_mru_strA;
 
     SetLastError(0);
     hMRU = pCreateMRUListA(&infoA);
@@ -266,7 +266,7 @@ static void test_MRUListA(void)
     infoA.fFlags = MRU_STRING;
     infoA.hKey = NULL;
     infoA.lpszSubKey = REG_TEST_SUBKEYA;
-    infoA.lpfnCompare = (PROC)cmp_mru_strA;
+    infoA.lpfnCompare = cmp_mru_strA;
 
     SetLastError(0);
     hMRU = pCreateMRUListA(&infoA);
@@ -280,7 +280,7 @@ static void test_MRUListA(void)
     infoA.fFlags = MRU_STRING;
     infoA.hKey = NULL;
     infoA.lpszSubKey = REG_TEST_SUBKEYA;
-    infoA.lpfnCompare = (PROC)cmp_mru_strA;
+    infoA.lpfnCompare = cmp_mru_strA;
 
     SetLastError(0);
     hMRU = pCreateMRUListA(&infoA);
@@ -294,7 +294,7 @@ static void test_MRUListA(void)
     infoA.fFlags = MRU_STRING;
     infoA.hKey = NULL;
     infoA.lpszSubKey = NULL;
-    infoA.lpfnCompare = (PROC)cmp_mru_strA;
+    infoA.lpfnCompare = cmp_mru_strA;
 
     SetLastError(0);
     hMRU = pCreateMRUListA(&infoA);
@@ -312,7 +312,7 @@ static void test_MRUListA(void)
     infoA.fFlags = MRU_STRING;
     infoA.hKey = hKey;
     infoA.lpszSubKey = REG_TEST_SUBKEYA;
-    infoA.lpfnCompare = (PROC)cmp_mru_strA;
+    infoA.lpfnCompare = cmp_mru_strA;
 
     hMRU = pCreateMRUListA(&infoA);
     ok(hMRU && !GetLastError(),
@@ -447,17 +447,7 @@ static void test_MRUListA(void)
 
     /* FreeMRUList(NULL) crashes on Win98 OSR0 */
 }
-/*
-typedef struct tagMRUINFOA
-{
-    DWORD   cbSize;
-    UINT    uMax;
-    UINT    fFlags;
-    HKEY    hKey;
-    LPCSTR  lpszSubKey;
-    PROC    lpfnCompare;
-} MRUINFOA;
-*/
+
 typedef struct {
     MRUINFOA mruA;
     BOOL ret;
diff --git a/rostests/winetests/comctl32/pager.c b/rostests/winetests/comctl32/pager.c
new file mode 100644 (file)
index 0000000..8ac062d
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Unit tests for the pager control
+ *
+ * Copyright 2012 Alexandre Julliard
+ *
+ * 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 <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+#include "msg.h"
+
+#define NUM_MSG_SEQUENCES   1
+#define PAGER_SEQ_INDEX     0
+
+static HWND parent_wnd;
+
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message set_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 },
+    { 0 }
+};
+
+static const struct message set_pos_seq[] = {
+    { PGM_SETPOS, sent },
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_NCCALCSIZE, sent|wparam, TRUE },
+    { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE },
+    { WM_WINDOWPOSCHANGED, sent },
+    { WM_MOVE, sent|optional },
+    { WM_SIZE, sent|optional },
+    { 0 }
+};
+
+static const struct message set_pos_empty_seq[] = {
+    { PGM_SETPOS, sent },
+    { 0 }
+};
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static LONG defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* log system messages, except for painting */
+    if (message < WM_USER &&
+        message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam|parent;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
+        add_message(sequences, PAGER_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Pager test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_parent_window(void)
+{
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindow("Pager test parent class", "Pager test parent window",
+                        WS_OVERLAPPED | WS_VISIBLE,
+                        0, 0, 200, 200, 0, NULL, GetModuleHandleA(NULL), NULL );
+}
+
+static LRESULT WINAPI pager_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    struct message msg;
+
+    trace("pager: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    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);
+}
+
+static HWND create_pager_control( DWORD style )
+{
+    WNDPROC oldproc;
+    HWND hwnd;
+    RECT rect;
+
+    GetClientRect( parent_wnd, &rect );
+    hwnd = CreateWindowA( WC_PAGESCROLLERA, "pager", WS_CHILD | WS_BORDER | WS_VISIBLE | style,
+                          0, 0, 100, 100, parent_wnd, 0, GetModuleHandleA(0), 0 );
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)pager_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
+    return hwnd;
+}
+
+static void test_pager(void)
+{
+    HWND pager, child;
+    RECT rect;
+
+    pager = create_pager_control( PGS_HORZ );
+    if (!pager)
+    {
+        win_skip( "Pager control not supported\n" );
+        return;
+    }
+    child = CreateWindowA( "BUTTON", "button", WS_CHILD | WS_BORDER | WS_VISIBLE, 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);
+    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);
+    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_empty_seq, "set pos empty", TRUE);
+
+    flush_sequences( sequences, NUM_MSG_SEQUENCES );
+    SendMessageA( pager, PGM_SETPOS, 0, 9 );
+    ok_sequence(sequences, PAGER_SEQ_INDEX, set_pos_seq, "set pos", TRUE);
+
+    DestroyWindow( pager );
+}
+
+START_TEST(pager)
+{
+    HMODULE mod = GetModuleHandleA("comctl32.dll");
+
+    pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410);
+
+    InitCommonControls();
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    parent_wnd = create_parent_window();
+    ok(parent_wnd != NULL, "Failed to create parent window!\n");
+
+    test_pager();
+}
index 92fb1dd..992b60f 100644 (file)
@@ -750,7 +750,7 @@ static void test_messages(void)
 
 static void test_PSM_ADDPAGE(void)
 {
-    HPROPSHEETPAGE hpsp[3];
+    HPROPSHEETPAGE hpsp[5];
     PROPSHEETPAGEA psp;
     PROPSHEETHEADERA psh;
     HWND hdlg, tab;
@@ -771,6 +771,12 @@ static void test_PSM_ADDPAGE(void)
     hpsp[1] = CreatePropertySheetPageA(&psp);
     hpsp[2] = CreatePropertySheetPageA(&psp);
 
+    U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
+    hpsp[3] = CreatePropertySheetPageA(&psp);
+
+    psp.dwFlags = PSP_PREMATURE;
+    hpsp[4] = CreatePropertySheetPageA(&psp);
+
     memset(&psh, 0, sizeof(psh));
     psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
     psh.dwFlags = PSH_MODELESS;
@@ -807,6 +813,27 @@ if (0)
     r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
     ok(r == 3, "got %d\n", r);
 
+    /* add property sheet page that can't be created */
+    ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
+    ok(ret == TRUE, "got %d\n", ret);
+
+    r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
+    ok(r == 4, "got %d\n", r);
+
+    /* select page that can't be created */
+    ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 0);
+    ok(ret == TRUE, "got %d\n", ret);
+
+    r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
+    ok(r == 3, "got %d\n", r);
+
+    /* test PSP_PREMATURE flag with incorrect property sheet page */
+    ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
+    ok(ret == FALSE, "got %d\n", ret);
+
+    r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
+    ok(r == 3, "got %d\n", r);
+
     DestroyWindow(hdlg);
 }
 
index e5217f1..3a89cd7 100644 (file)
@@ -38,6 +38,7 @@
 
 #define IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON 34
 #define IDD_PROP_PAGE_MESSAGE_TEST 35
+#define IDD_PROP_PAGE_ERROR 36
 
 #define IDC_PS_EDIT1 1000
 #define IDC_PS_EDIT2 1001
index c817acd..4f7a225 100644 (file)
@@ -22,7 +22,7 @@
 #include "winuser.h"
 #include "resources.h"
 
-PROP_PAGE1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+PROP_PAGE1 DIALOG 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
 CAPTION "Page1"
 FONT 8, "MS Shell Dlg"
@@ -30,7 +30,7 @@ FONT 8, "MS Shell Dlg"
  LTEXT "Test", -1, 10, 6, 100, 8
 }
 
-IDD_PROP_PAGE_INTRO DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+IDD_PROP_PAGE_INTRO DIALOG 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
 CAPTION "Edit Control Page"
 FONT 8, "MS Shell Dlg"
@@ -38,7 +38,7 @@ FONT 8, "MS Shell Dlg"
     LTEXT "This is a test property sheet!", -1, 10, 6, 100, 8
 }
 
-IDD_PROP_PAGE_EDIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+IDD_PROP_PAGE_EDIT DIALOG 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
 CAPTION "Edit Control Page"
 FONT 8, "MS Shell Dlg"
@@ -47,7 +47,7 @@ FONT 8, "MS Shell Dlg"
     EDITTEXT IDC_PS_EDIT2, 5, 160, 150, 28, WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE
 }
 
-IDD_PROP_PAGE_RADIO DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+IDD_PROP_PAGE_RADIO DIALOG 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
 CAPTION "Edit Control Page"
 FONT 8, "MS Shell Dlg"
@@ -56,7 +56,7 @@ FONT 8, "MS Shell Dlg"
     CONTROL "Radio2", IDC_PS_RADIO2, "Button", BS_AUTORADIOBUTTON, 20, 40, 39, 10
 }
 
-IDD_PROP_PAGE_EXIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+IDD_PROP_PAGE_EXIT DIALOG 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
 CAPTION "Edit Control Page"
 FONT 8, "MS Shell Dlg"
@@ -64,6 +64,20 @@ FONT 8, "MS Shell Dlg"
     LTEXT "This has been a test property sheet!", -1, 10, 6, 170, 8
 }
 
+IDD_PROP_PAGE_MESSAGE_TEST DIALOG  0, 0, 339, 179
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_CHILD | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Message Test"
+BEGIN
+    LTEXT           "Some Text",-1,115,1,195,24
+END
+
+IDD_PROP_PAGE_ERROR DIALOG 0, 0, 100, 100
+STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CLASS "Non-existing class"
+FONT 8, "MS Shell Dlg"
+{
+}
+
 STRINGTABLE 
 {
     IDS_TBADD1           "abc"
@@ -80,7 +94,7 @@ IDB_BITMAP_128x15 BITMAP bmp128x15.bmp
 /* @makedep: bmp80x15.bmp */
 IDB_BITMAP_80x15 BITMAP bmp80x15.bmp
 
-IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON DIALOG DISCARDABLE  5, 43, 227, 215
+IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON DIALOG  5, 43, 227, 215
 STYLE WS_CHILD | WS_DISABLED
 FONT 8, "MS Shell Dlg"
 {
index 6e5a3e7..d8b3dbe 100644 (file)
@@ -267,11 +267,11 @@ static void test_status_control(void)
     /* Divide into parts and set text */
     r = SendMessage(hWndStatus, SB_SETPARTS, 3, (LPARAM)nParts);
     expect(TRUE,r);
-    r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First");
+    r = SendMessage(hWndStatus, SB_SETTEXT, SBT_POPOUT|0,    (LPARAM)"First");
     expect(TRUE,r);
-    r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"Second");
+    r = SendMessage(hWndStatus, SB_SETTEXT, SBT_OWNERDRAW|1, (LPARAM)"Second");
     expect(TRUE,r);
-    r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"Third");
+    r = SendMessage(hWndStatus, SB_SETTEXT, SBT_NOBORDERS|2, (LPARAM)"Third");
     expect(TRUE,r);
 
     /* Get RECT Information */
@@ -287,13 +287,21 @@ static void test_status_control(void)
     r = SendMessage(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc);
     expect(FALSE,r);
     /* Get text length and text */
+    r = SendMessage(hWndStatus, SB_GETTEXTLENGTH, 0, 0);
+    expect(5,LOWORD(r));
+    expect(SBT_POPOUT,HIWORD(r));
+    r = SendMessageW(hWndStatus, WM_GETTEXTLENGTH, 0, 0);
+    ok(r == 5 || broken(0x02000005 /* NT4 */), "Expected 5, got %d\n", r);
+    r = SendMessage(hWndStatus, SB_GETTEXTLENGTH, 1, 0);
+    expect(0,LOWORD(r));
+    expect(SBT_OWNERDRAW,HIWORD(r));
     r = SendMessage(hWndStatus, SB_GETTEXTLENGTH, 2, 0);
     expect(5,LOWORD(r));
-    expect(0,HIWORD(r));
+    expect(SBT_NOBORDERS,HIWORD(r));
     r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray);
     ok(strcmp(charArray,"Third") == 0, "Expected Third, got %s\n", charArray);
     expect(5,LOWORD(r));
-    expect(0,HIWORD(r));
+    expect(SBT_NOBORDERS,HIWORD(r));
 
     /* Get parts and borders */
     r = SendMessage(hWndStatus, SB_GETPARTS, 3, (LPARAM)checkParts);
diff --git a/rostests/winetests/comctl32/syslink.c b/rostests/winetests/comctl32/syslink.c
new file mode 100644 (file)
index 0000000..ea92d42
--- /dev/null
@@ -0,0 +1,257 @@
+/* Unit tests for the syslink control.
+ *
+ * Copyright 2011 Francois Gouget for CodeWeavers
+ *
+ * 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 <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+#include "v6util.h"
+#include "msg.h"
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+#define NUM_MSG_SEQUENCE 2
+#define PARENT_SEQ_INDEX 0
+#define SYSLINK_SEQ_INDEX 1
+
+static HWND hWndParent;
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
+
+static const struct message empty_wnd_seq[] = {
+    {0}
+};
+
+static const struct message parent_create_syslink_wnd_seq[] = {
+    { WM_GETFONT, sent|optional}, /* Only on XP */
+    { WM_QUERYUISTATE, sent|optional},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent|wparam, 0},
+    { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
+    {0}
+};
+
+static const struct message visible_syslink_wnd_seq[] = {
+    { WM_STYLECHANGING, sent|wparam, GWL_STYLE},
+    { WM_STYLECHANGED, sent|wparam, GWL_STYLE},
+    { WM_PAINT, sent},
+    {0}
+};
+
+static const struct message parent_visible_syslink_wnd_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent|wparam, 0},
+    {0}
+};
+
+/* Try to make sure pending X events have been processed before continuing */
+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 (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+        diff = time - GetTickCount();
+    }
+}
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static LONG defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* log system messages, except for painting */
+    if (message < WM_USER &&
+        message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcW(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static const WCHAR parentClassW[] = {'S','y','s','l','i','n','k',' ','t','e','s','t',' ','p','a','r','e','n','t',' ','c','l','a','s','s',0};
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSW cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleW(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = parentClassW;
+    return RegisterClassW(&cls);
+}
+
+static HWND create_parent_window(void)
+{
+    static const WCHAR titleW[] = {'S','y','s','l','i','n','k',' ','t','e','s','t',' ','p','a','r','e','n','t',' ','w','i','n','d','o','w',0};
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowExW(0, parentClassW, titleW,
+                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                           WS_MAXIMIZEBOX | WS_VISIBLE,
+                           0, 0, 200, 100, GetDesktopWindow(),
+                           NULL, GetModuleHandleW(NULL), NULL);
+}
+
+static WNDPROC syslink_oldproc;
+
+static LRESULT WINAPI syslink_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static LONG defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("syslink: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, SYSLINK_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcW(syslink_oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_syslink(DWORD style, HWND parent)
+{
+    HWND hWndSysLink;
+    static const WCHAR linkW[] = {'H','e','a','d',' ','<','a',' ','h','r','e','f','=','"','l','i','n','k','1','"','>','N','a','m','e','1','<','/','a','>',' ','M','i','d','d','l','e',' ','<','a',' ','h','r','e','f','=','"','l','i','n','k','2','"','>','N','a','m','e','2','<','/','a','>',' ','T','a','i','l',0};
+
+    /* Only Unicode will do here */
+    hWndSysLink = CreateWindowExW(0, WC_LINK, linkW,
+                                style, 0, 0, 150, 50,
+                                parent, NULL, GetModuleHandleW(NULL), NULL);
+    if (!hWndSysLink) return NULL;
+
+    if (GetWindowLongPtrW(hWndSysLink, GWLP_USERDATA))
+        /* On Windows XP SysLink takes GWLP_USERDATA for itself! */
+        trace("SysLink makes use of GWLP_USERDATA\n");
+
+    syslink_oldproc = (WNDPROC)SetWindowLongPtrW(hWndSysLink, GWLP_WNDPROC, (LONG_PTR)syslink_subclass_proc);
+
+    return hWndSysLink;
+}
+
+
+START_TEST(syslink)
+{
+    ULONG_PTR ctx_cookie;
+    HANDLE hCtx;
+    HMODULE hComctl32;
+    BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
+    INITCOMMONCONTROLSEX iccex;
+    BOOL rc;
+    HWND hWndSysLink;
+    LONG oldstyle;
+
+    if (!load_v6_module(&ctx_cookie, &hCtx))
+        return;
+
+    /* LoadLibrary is needed. This file has no reference to functions in comctl32 */
+    hComctl32 = LoadLibraryA("comctl32.dll");
+    pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
+    if (!pInitCommonControlsEx)
+    {
+        win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
+        return;
+    }
+    iccex.dwSize = sizeof(iccex);
+    iccex.dwICC = ICC_LINK_CLASS;
+    rc = pInitCommonControlsEx(&iccex);
+    ok(rc, "InitCommonControlsEx failed (le %u)\n", GetLastError());
+    if (!rc)
+    {
+        skip("Could not register ICC_LINK_CLASS\n");
+        return;
+    }
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* Create parent window */
+    hWndParent = create_parent_window();
+    ok(hWndParent != NULL, "Failed to create parent Window!\n");
+    if (!hWndParent)
+    {
+        skip("Parent window not present\n");
+        return;
+    }
+    flush_events();
+
+    /* Create an invisible SysLink control */
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    hWndSysLink = create_syslink(WS_CHILD | WS_TABSTOP, hWndParent);
+    ok(hWndSysLink != NULL, "Expected non NULL value (le %u)\n", GetLastError());
+    if (!hWndSysLink)
+    {
+        skip("SysLink control not present?\n");
+        return;
+    }
+    flush_events();
+    ok_sequence(sequences, SYSLINK_SEQ_INDEX, empty_wnd_seq, "create SysLink", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_syslink_wnd_seq, "create SysLink (parent)", TRUE);
+
+    /* Make the SysLink control visible */
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    oldstyle = GetWindowLong(hWndSysLink, GWL_STYLE);
+    SetWindowLong(hWndSysLink, GWL_STYLE, oldstyle | WS_VISIBLE);
+    RedrawWindow(hWndSysLink, NULL, NULL, RDW_INVALIDATE);
+    flush_events();
+    ok_sequence(sequences, SYSLINK_SEQ_INDEX, visible_syslink_wnd_seq, "visible SysLink", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_visible_syslink_wnd_seq, "visible SysLink (parent)", TRUE);
+
+    DestroyWindow(hWndSysLink);
+    DestroyWindow(hWndParent);
+    unload_v6_module(ctx_cookie, hCtx);
+}
index 36179dc..51a8a91 100644 (file)
@@ -47,15 +47,11 @@ static void CheckSize(HWND hwnd, INT width, INT height, const char *msg, int lin
 
     SendMessage(hwnd, TCM_GETITEMRECT, 0, (LPARAM)&r);
     if (width >= 0 && height < 0)
-    {
-        ok_(__FILE__,line) (width == r.right - r.left, "%s: Expected width [%d] got [%d]\n",\
-        msg, width, r.right - r.left);
-    }
+        ok_(__FILE__,line) (width == r.right - r.left, "%s: Expected width [%d] got [%d]\n",
+            msg, width, r.right - r.left);
     else if (height >= 0 && width < 0)
-    {
-        ok_(__FILE__,line) (height == r.bottom - r.top,  "%s: Expected height [%d] got [%d]\n",\
-        msg, height, r.bottom - r.top);
-    }
+        ok_(__FILE__,line) (height == r.bottom - r.top,  "%s: Expected height [%d] got [%d]\n",
+            msg, height, r.bottom - r.top);
     else
         ok_(__FILE__,line) ((width  == r.right  - r.left) && (height == r.bottom - r.top ),
            "%s: Expected [%d,%d] got [%d,%d]\n", msg, width, height,
@@ -661,7 +657,6 @@ static void test_tab(INT nMinTabWidth)
     DestroyWindow (hwTab);
 
     ImageList_Destroy(himl);
-    DeleteObject(hFont);
 }
 
 static void test_width(void)
@@ -1428,6 +1423,36 @@ static void test_WM_CONTEXTMENU(void)
     DestroyWindow(hTab);
 }
 
+struct tabcreate_style {
+    DWORD style;
+    DWORD act_style;
+};
+
+static const struct tabcreate_style create_styles[] =
+{
+    { WS_CHILD|TCS_BOTTOM|TCS_VERTICAL, WS_CHILD|WS_CLIPSIBLINGS|TCS_BOTTOM|TCS_VERTICAL|TCS_MULTILINE },
+    { WS_CHILD|TCS_VERTICAL,            WS_CHILD|WS_CLIPSIBLINGS|TCS_VERTICAL|TCS_MULTILINE },
+    { 0 }
+};
+
+static void test_create(void)
+{
+    const struct tabcreate_style *ptr = create_styles;
+    DWORD style;
+    HWND hTab;
+
+    while (ptr->style)
+    {
+        hTab = CreateWindowA(WC_TABCONTROLA, "TestTab", ptr->style,
+            10, 10, 300, 100, parent_wnd, NULL, NULL, 0);
+        style = GetWindowLongA(hTab, GWL_STYLE);
+        ok(style == ptr->act_style, "expected style 0x%08x, got style 0x%08x\n", ptr->act_style, style);
+
+        DestroyWindow(hTab);
+        ptr++;
+    }
+}
+
 START_TEST(tab)
 {
     LOGFONTA logfont;
@@ -1465,6 +1490,7 @@ START_TEST(tab)
     test_TCM_SETITEMEXTRA();
     test_TCS_OWNERDRAWFIXED();
     test_WM_CONTEXTMENU();
+    test_create();
 
     DestroyWindow(parent_wnd);
 }
index 1789e5c..d90fbad 100644 (file)
@@ -11,22 +11,24 @@ extern void func_datetime(void);
 extern void func_dpa(void);
 extern void func_header(void);
 extern void func_imagelist(void);
+extern void func_ipaddress(void);
 extern void func_listview(void);
 extern void func_misc(void);
 extern void func_monthcal(void);
 extern void func_mru(void);
+extern void func_pager(void);
 extern void func_progress(void);
 extern void func_propsheet(void);
 extern void func_rebar(void);
 extern void func_status(void);
 extern void func_subclass(void);
+extern void func_syslink(void);
 extern void func_tab(void);
 extern void func_toolbar(void);
 extern void func_tooltips(void);
 extern void func_trackbar(void);
 extern void func_treeview(void);
 extern void func_updown(void);
-extern void func_ipaddress(void);
 
 const struct test winetest_testlist[] =
 {
@@ -35,21 +37,23 @@ const struct test winetest_testlist[] =
     { "dpa", func_dpa },
     { "header", func_header },
     { "imagelist", func_imagelist },
+    { "ipaddress", func_ipaddress },
     { "listview", func_listview },
     { "misc", func_misc },
     { "monthcal", func_monthcal },
     { "mru", func_mru },
+    { "pager", func_pager },
     { "progress", func_progress },
     { "propsheet", func_propsheet },
     { "rebar", func_rebar },
     { "status", func_status },
     { "subclass", func_subclass },
+    { "syslink", func_syslink },
     { "tab", func_tab },
     { "toolbar", func_toolbar },
     { "tooltips", func_tooltips },
     { "trackbar", func_trackbar },
     { "treeview", func_treeview },
     { "updown", func_updown },
-    { "ipaddress", func_ipaddress },
     { 0, 0 }
 };
index 5049ef6..9de319f 100644 (file)
@@ -54,6 +54,24 @@ static const struct message ttgetdispinfo_parent_seq[] = {
     { 0 }
 };
 
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
 
 #define check_rect(name, val, exp, ...) ok(val.top == exp.top && val.bottom == exp.bottom && \
@@ -1610,6 +1628,7 @@ static void test_tooltip(void)
         {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
     };
     NMTTDISPINFOW nmtti;
+    HWND tooltip;
 
     rebuild_toolbar(&hToolbar);
 
@@ -1632,6 +1651,13 @@ static void test_tooltip(void)
     g_ResetDispTextPtr = FALSE;
 
     DestroyWindow(hToolbar);
+
+    /* TBSTYLE_TOOLTIPS */
+    hToolbar = CreateWindowExA(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
+        hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
+    tooltip = (HWND)SendMessageA(hToolbar, TB_GETTOOLTIPS, 0, 0);
+    ok(tooltip == NULL, "got %p\n", tooltip);
+    DestroyWindow(hToolbar);
 }
 
 static void test_get_set_style(void)
@@ -1658,6 +1684,7 @@ static void test_get_set_style(void)
 
     style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0);
     style2 = GetWindowLongA(hToolbar, GWL_STYLE);
+todo_wine
     ok(style == style2, "got 0x%08x, expected 0x%08x\n", style, style2);
 
     /* try to alter common window bits */
@@ -1681,6 +1708,208 @@ static void test_get_set_style(void)
     DestroyWindow(hToolbar);
 }
 
+static HHOOK g_tbhook;
+static HWND g_toolbar;
+
+DEFINE_EXPECT(g_hook_create);
+DEFINE_EXPECT(g_hook_WM_NCCREATE);
+DEFINE_EXPECT(g_hook_WM_CREATE);
+
+static LRESULT WINAPI toolbar_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    LRESULT ret;
+    DWORD style;
+
+    if (msg == WM_NCCREATE)
+    {
+        if (g_toolbar == hwnd)
+        {
+            CHECK_EXPECT2(g_hook_WM_NCCREATE);
+            g_toolbar = hwnd;
+            ret = CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
+
+            /* control is already set up */
+            style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
+            ok(style != 0, "got %x\n", style);
+
+            style = GetWindowLongA(hwnd, GWL_STYLE);
+            ok((style & TBSTYLE_TOOLTIPS) == 0, "got 0x%08x\n", style);
+            SetWindowLongA(hwnd, GWL_STYLE, style|TBSTYLE_TOOLTIPS);
+            style = GetWindowLongA(hwnd, GWL_STYLE);
+            ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
+
+            return ret;
+        }
+    }
+    else if (msg == WM_CREATE)
+    {
+        CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
+
+        if (g_toolbar == hwnd)
+        {
+            CHECK_EXPECT2(g_hook_WM_CREATE);
+
+            style = GetWindowLongA(hwnd, GWL_STYLE);
+            ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
+
+            /* test if toolbar-specific messages are already working before WM_CREATE */
+            style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
+            ok(style != 0, "got %x\n", style);
+            ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%x\n", style);
+            ok((cs->style & TBSTYLE_TOOLTIPS) == 0, "0x%08x\n", cs->style);
+
+            ret = CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
+
+            style = GetWindowLongA(hwnd, GWL_STYLE);
+            ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
+
+            /* test if toolbar-specific messages are already working before WM_CREATE */
+            style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
+            ok(style != 0, "got %x\n", style);
+            ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%x\n", style);
+
+            return ret;
+        }
+    }
+
+    return CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK cbt_hook_proc(int code, WPARAM wParam, LPARAM lParam)
+{
+    if (code == HCBT_CREATEWND)
+    {
+        HWND hwnd = (HWND)wParam;
+
+        if (!g_toolbar)
+        {
+            WNDPROC oldproc;
+
+            CHECK_EXPECT2(g_hook_create);
+            g_toolbar = hwnd;
+            /* subclass */
+            oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)toolbar_subclass_proc);
+            SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
+        }
+        return 0;
+    }
+
+    return CallNextHookEx(g_tbhook, code, wParam, lParam);
+}
+
+static void test_create(void)
+{
+    HWND hwnd, tooltip;
+    DWORD style;
+
+    g_tbhook = SetWindowsHookA(WH_CBT, cbt_hook_proc);
+
+    SET_EXPECT(g_hook_create);
+    SET_EXPECT(g_hook_WM_NCCREATE);
+    SET_EXPECT(g_hook_WM_CREATE);
+
+    hwnd = CreateWindowExA(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
+        hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
+
+    CHECK_CALLED(g_hook_create);
+    CHECK_CALLED(g_hook_WM_NCCREATE);
+    CHECK_CALLED(g_hook_WM_CREATE);
+
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
+
+    tooltip = (HWND)SendMessageA(hwnd, TB_GETTOOLTIPS, 0, 0);
+    ok(tooltip != NULL, "got %p\n", tooltip);
+    ok(GetParent(tooltip) == hMainWnd, "got %p, %p\n", hMainWnd, hwnd);
+
+    DestroyWindow(hwnd);
+    UnhookWindowsHook(WH_CBT, cbt_hook_proc);
+
+    /* TBSTYLE_TRANSPARENT */
+    hwnd = CreateWindowExA(0, TOOLBARCLASSNAME, NULL,
+        WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|TBSTYLE_FLAT|TBSTYLE_TOOLTIPS|TBSTYLE_GROUP,
+        0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
+
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    ok((style & TBSTYLE_TRANSPARENT) == TBSTYLE_TRANSPARENT, "got 0x%08x\n", style);
+
+    style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
+    ok((style & TBSTYLE_TRANSPARENT) == TBSTYLE_TRANSPARENT, "got 0x%08x\n", style);
+
+    DestroyWindow(hwnd);
+}
+
+typedef struct {
+    DWORD mask;
+    DWORD style;
+    DWORD style_set;
+} extended_style_t;
+
+static const extended_style_t extended_style_test[] = {
+    {
+      TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER,
+      TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER,
+      TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER
+    },
+    {
+      TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS,
+      TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS
+    },
+
+    { 0, TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS },
+    { 0, 0, 0 },
+    { 0, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS },
+    { 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS, TBSTYLE_EX_HIDECLIPPEDBUTTONS },
+
+    { 0, 0, 0 },
+    { TBSTYLE_EX_HIDECLIPPEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS, 0 },
+    { TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_HIDECLIPPEDBUTTONS, 0 },
+    { TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_MIXEDBUTTONS, 0 },
+
+    {
+      TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS,
+      TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS
+    },
+    {
+      TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS,
+      TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_DOUBLEBUFFER
+    }
+};
+
+static void test_TB_GET_SET_EXTENDEDSTYLE(void)
+{
+    DWORD style, oldstyle, oldstyle2;
+    const extended_style_t *ptr;
+    HWND hwnd = NULL;
+    int i;
+
+    rebuild_toolbar(&hwnd);
+
+    SendMessageA(hwnd, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_MIXEDBUTTONS);
+    style = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
+    if (style == TBSTYLE_EX_MIXEDBUTTONS)
+    {
+        win_skip("Some extended style bits are not supported\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    for (i = 0; i < sizeof(extended_style_test)/sizeof(extended_style_t); i++)
+    {
+        ptr = &extended_style_test[i];
+
+        oldstyle2 = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
+
+        oldstyle = SendMessageA(hwnd, TB_SETEXTENDEDSTYLE, ptr->mask, ptr->style);
+        ok(oldstyle == oldstyle2, "%d: got old style 0x%08x, expected 0x%08x\n", i, oldstyle, oldstyle2);
+        style = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
+        ok(style == ptr->style_set, "%d: got style 0x%08x, expected 0x%08x\n", i, style, ptr->style_set);
+    }
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(toolbar)
 {
     WNDCLASSA wc;
@@ -1721,6 +1950,8 @@ START_TEST(toolbar)
     test_getstring();
     test_tooltip();
     test_get_set_style();
+    test_create();
+    test_TB_GET_SET_EXTENDEDSTYLE();
 
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
index 596598f..71c66a5 100644 (file)
@@ -322,6 +322,11 @@ static void test_gettext(void)
         toolinfoA.lpszText = bufA;
         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
         ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
+
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
+        ok(toolinfoA.lpszText == NULL,
+           "expected NULL, got %p\n", toolinfoA.lpszText);
     }
     else
     {
@@ -355,6 +360,12 @@ static void test_gettext(void)
         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
         ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n");
 
+        memset(bufA, 0x1f, sizeof(bufA));
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
+        ok(strcmp(toolinfoA.lpszText, testtipA) == 0,
+           "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
+
         length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
         ok(length == 0, "Expected 0, got %d\n", length);
     }
@@ -378,6 +389,11 @@ static void test_gettext(void)
         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
         ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0,
            "lpszText should be an (%s) string\n", testcallbackA);
+
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
+        ok(toolinfoA.lpszText == LPSTR_TEXTCALLBACKA,
+           "expected LPSTR_TEXTCALLBACKA, got %p\n", toolinfoA.lpszText);
     }
 
     DestroyWindow(hwnd);
@@ -620,6 +636,128 @@ static void test_ttm_gettoolinfo(void)
     DestroyWindow(hwnd);
 }
 
+static void test_longtextA(void)
+{
+    static const char longtextA[] =
+        "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
+        "80 chars including null. In fact, the buffer is not null-terminated.";
+    HWND hwnd;
+    TTTOOLINFOA toolinfoA = { 0 };
+    CHAR bufA[256];
+    LRESULT r;
+
+    hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
+                           10, 10, 300, 100,
+                           NULL, NULL, NULL, 0);
+    toolinfoA.cbSize = sizeof(TTTOOLINFOA);
+    toolinfoA.hwnd = NULL;
+    toolinfoA.hinst = GetModuleHandleA(NULL);
+    toolinfoA.uFlags = 0;
+    toolinfoA.uId = 0x1234ABCD;
+    strcpy(bufA, longtextA);
+    toolinfoA.lpszText = bufA;
+    toolinfoA.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &toolinfoA.rect);
+    r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
+    if (r)
+    {
+        int textlen;
+        memset(bufA, 0, sizeof(bufA));
+        toolinfoA.hwnd = NULL;
+        toolinfoA.uId = 0xABCD1234;
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_ENUMTOOLSA, 0, (LPARAM)&toolinfoA);
+        textlen = lstrlenA(toolinfoA.lpszText);
+        ok(textlen == 80, "lpszText has %d chars\n", textlen);
+        ok(toolinfoA.uId == 0x1234ABCD,
+           "uId should be retrieved, got %p\n", (void*)toolinfoA.uId);
+
+        memset(bufA, 0, sizeof(bufA));
+        toolinfoA.hwnd = NULL;
+        toolinfoA.uId = 0x1234ABCD;
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
+        textlen = lstrlenA(toolinfoA.lpszText);
+        ok(textlen == 80, "lpszText has %d chars\n", textlen);
+
+        memset(bufA, 0, sizeof(bufA));
+        toolinfoA.hwnd = NULL;
+        toolinfoA.uId = 0x1234ABCD;
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
+        textlen = lstrlenA(toolinfoA.lpszText);
+        ok(textlen == 80, "lpszText has %d chars\n", textlen);
+    }
+
+    DestroyWindow(hwnd);
+}
+
+static void test_longtextW(void)
+{
+    static const char longtextA[] =
+        "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
+        "80 chars including null. Actually, this is not applied for wide version.";
+    HWND hwnd;
+    TTTOOLINFOW toolinfoW = { 0 };
+    WCHAR bufW[256];
+    LRESULT r;
+    int lenW;
+
+    hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
+                           10, 10, 300, 100,
+                           NULL, NULL, NULL, 0);
+    if(!hwnd)
+    {
+        win_skip("CreateWindowExW() not supported. Skipping.\n");
+        return;
+    }
+
+    toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE;
+    toolinfoW.hwnd = NULL;
+    toolinfoW.hinst = GetModuleHandleW(NULL);
+    toolinfoW.uFlags = 0;
+    toolinfoW.uId = 0x1234ABCD;
+    MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, sizeof(bufW)/sizeof(bufW[0]));
+    lenW = lstrlenW(bufW);
+    toolinfoW.lpszText = bufW;
+    toolinfoW.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &toolinfoW.rect);
+    r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
+    if (r)
+    {
+        int textlen;
+        memset(bufW, 0, sizeof(bufW));
+        toolinfoW.hwnd = NULL;
+        toolinfoW.uId = 0xABCD1234;
+        toolinfoW.lpszText = bufW;
+        SendMessageW(hwnd, TTM_ENUMTOOLSW, 0, (LPARAM)&toolinfoW);
+        textlen = lstrlenW(toolinfoW.lpszText);
+        ok(textlen == lenW, "lpszText has %d chars\n", textlen);
+        ok(toolinfoW.uId == 0x1234ABCD,
+           "uId should be retrieved, got %p\n", (void*)toolinfoW.uId);
+
+        memset(bufW, 0, sizeof(bufW));
+        toolinfoW.hwnd = NULL;
+        toolinfoW.uId = 0x1234ABCD;
+        toolinfoW.lpszText = bufW;
+        SendMessageW(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&toolinfoW);
+        textlen = lstrlenW(toolinfoW.lpszText);
+        ok(textlen == lenW, "lpszText has %d chars\n", textlen);
+
+        memset(bufW, 0, sizeof(bufW));
+        toolinfoW.hwnd = NULL;
+        toolinfoW.uId = 0x1234ABCD;
+        toolinfoW.lpszText = bufW;
+        SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
+        textlen = lstrlenW(toolinfoW.lpszText);
+        ok(textlen == lenW ||
+           broken(textlen == 0 && toolinfoW.lpszText == NULL), /* nt4, kb186177 */
+           "lpszText has %d chars\n", textlen);
+    }
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(tooltips)
 {
     InitCommonControls();
@@ -628,4 +766,6 @@ START_TEST(tooltips)
     test_customdraw();
     test_gettext();
     test_ttm_gettoolinfo();
+    test_longtextA();
+    test_longtextW();
 }
index 725490f..7a0e398 100644 (file)
@@ -33,11 +33,7 @@ static HWND hWndParent;
 
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
 
-static const struct message create_trackbar_wnd_seq[] = {
-    {0}
-};
-
-static const struct message parent_empty_test_seq[] = {
+static const struct message empty_seq[] = {
     {0}
 };
 
@@ -298,10 +294,20 @@ static const struct message thumb_length_test_seq[] = {
     { WM_PAINT, sent|defwinproc},
     { TBM_GETTHUMBLENGTH, sent},
     { TBM_GETTHUMBLENGTH, sent},
+    { WM_SIZE, sent},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETTHUMBLENGTH, sent},
+    { WM_SIZE, sent},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETTHUMBLENGTH, sent},
     {0}
 };
 
 static const struct message parent_thumb_length_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
     { WM_CTLCOLORSTATIC, sent},
     { WM_NOTIFY, sent},
     { WM_CTLCOLORSTATIC, sent},
@@ -535,7 +541,7 @@ static void test_line_size(HWND hWndTrackbar){
     expect(4, r);
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, line_size_test_seq, "linesize test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent line test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent line test sequence", FALSE);
 }
 
 
@@ -555,7 +561,7 @@ static void test_page_size(HWND hWndTrackbar){
     expect(20, r);
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, page_size_test_seq, "page size test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent page size test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent page size test sequence", FALSE);
 
     /* check for zero page size */
     r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, 0);
@@ -742,8 +748,17 @@ static void test_thumb_length(HWND hWndTrackbar){
     r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
     expect(20, r);
 
+    r = SendMessage(hWndTrackbar, WM_SIZE, 0,0);
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
+    expect(20, r);
+    r = SendMessage(hWndTrackbar, WM_SIZE, 0, MAKELPARAM(50, 50) );
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
+    expect(20, r);
+
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, thumb_length_test_seq, "thumb length test sequence", TRUE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_thumb_length_test_seq, "parent thumb lenth test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_thumb_length_test_seq, "parent thumb length test sequence", TRUE);
 }
 
 static void test_tic_settings(HWND hWndTrackbar){
@@ -842,7 +857,7 @@ static void test_tic_placement(HWND hWndTrackbar){
     ok(r > 0, "Expected r > 0, got %d\n", r);
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_placement_test_seq, "get tic placement test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent get tic placement test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent get tic placement test sequence", FALSE);
 }
 
 
@@ -886,7 +901,7 @@ static void test_tool_tips(HWND hWndTrackbar){
     ok(rTest == hWndTooltip, "Expected hWndTooltip\n");
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tool_tips_test_seq, "tool tips test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent tool tips test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent tool tips test sequence", FALSE);
 }
 
 
@@ -905,7 +920,7 @@ static void test_unicode(HWND hWndTrackbar){
     ok(r == FALSE, "Expected FALSE, got %d\n",r);
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, unicode_test_seq, "unicode test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent unicode test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent unicode test sequence", FALSE);
 }
 
 static void test_ignore_selection(HWND hWndTrackbar){
@@ -947,7 +962,7 @@ static void test_ignore_selection(HWND hWndTrackbar){
     expect(0, r);
 
     ok_sequence(sequences, TRACKBAR_SEQ_INDEX, ignore_selection_test_seq, "ignore selection setting test sequence", FALSE);
-    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent ignore selection setting test sequence", FALSE);
 }
 
 static void test_initial_state(void)
@@ -963,6 +978,66 @@ static void test_initial_state(void)
     expect(-1, ret);
     ret = SendMessage(hWnd, TBM_GETTICPOS, 0, 0);
     expect(-1, ret);
+    ret = SendMessage(hWnd, TBM_GETRANGEMIN, 0, 0);
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_GETRANGEMAX, 0, 0);
+    expect(100, ret);
+
+    ret = SendMessage(hWnd, TBM_SETRANGEMAX, TRUE, 200);
+    expect(0, ret);
+
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(2, ret);
+
+    ret = SendMessage(hWnd, TBM_SETRANGEMIN, TRUE, 10);
+    expect(0, ret);
+
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(2, ret);
+
+    DestroyWindow(hWnd);
+}
+
+static void test_TBS_AUTOTICKS(void)
+{
+    HWND hWnd;
+    int ret;
+
+    hWnd = create_trackbar(TBS_AUTOTICKS, hWndParent);
+
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(2, ret);
+    ret = SendMessage(hWnd, TBM_GETTIC, 0, 0);
+    expect(-1, ret);
+    ret = SendMessage(hWnd, TBM_GETTICPOS, 0, 0);
+    expect(-1, ret);
+    ret = SendMessage(hWnd, TBM_GETRANGEMIN, 0, 0);
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_GETRANGEMAX, 0, 0);
+    expect(100, ret);
+
+    /* TBM_SETRANGEMAX rebuilds tics */
+    ret = SendMessage(hWnd, TBM_SETRANGEMAX, TRUE, 200);
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(201, ret);
+
+    /* TBM_SETRANGEMIN rebuilds tics */
+    ret = SendMessage(hWnd, TBM_SETRANGEMAX, TRUE, 100);
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_SETRANGEMIN, TRUE, 10);
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(91, ret);
+
+    ret = SendMessage(hWnd, TBM_SETRANGEMIN, TRUE, 0);
+    expect(0, ret);
+
+    /* TBM_SETRANGE rebuilds tics */
+    ret = SendMessage(hWnd, TBM_SETRANGE, TRUE, MAKELONG(10, 200));
+    expect(0, ret);
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(191, ret);
 
     DestroyWindow(hWnd);
 }
@@ -996,7 +1071,7 @@ START_TEST(trackbar)
         return;
     }
 
-    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, create_trackbar_wnd_seq, "create Trackbar Window", FALSE);
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, empty_seq, "create Trackbar Window", FALSE);
     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_trackbar_wnd_seq, "parent trackbar window", TRUE);
     flush_sequences(sequences, NUM_MSG_SEQUENCE);
 
@@ -1012,6 +1087,7 @@ START_TEST(trackbar)
     test_tic_placement(hWndTrackbar);
     test_tool_tips(hWndTrackbar);
     test_unicode(hWndTrackbar);
+    test_TBS_AUTOTICKS();
 
     flush_sequences(sequences, NUM_MSG_SEQUENCE);
     DestroyWindow(hWndTrackbar);
index 51d4bc4..2fe468b 100644 (file)
 #include "v6util.h"
 #include "msg.h"
 
-// Hack wine! Not in Sdk CommCtrl.h!
-#define TVIS_FOCUSED          0x0001
-//
-
 static const char *TEST_CALLBACK_TEXT = "callback_text";
 
 static TVITEMA g_item_expanding, g_item_expanded;
@@ -208,6 +204,27 @@ static const struct message parent_expand_seq[] = {
     { 0 }
 };
 
+static const struct message parent_expand_kb_seq[] = {
+    { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
+    { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
+    { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
+    { WM_CHANGEUISTATE, sent|optional },
+    { 0 }
+};
+
+static const struct message parent_collapse_2nd_kb_seq[] = {
+    { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
+    { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
+    { WM_CHANGEUISTATE, sent|optional },
+    { 0 }
+};
+
+static const struct message parent_expand_empty_kb_seq[] = {
+    { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
+    { WM_CHANGEUISTATE, sent|optional },
+    { 0 }
+};
+
 static const struct message parent_singleexpand_seq[] = {
     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
@@ -736,8 +753,8 @@ static void test_get_set_item(void)
     TVITEMA tviRoot = {0};
     int nBufferSize = 80;
     char szBuffer[80] = {0};
+    HWND hTree, hTree2;
     DWORD ret;
-    HWND hTree;
 
     hTree = create_treeview_control(0);
     fill_tree(hTree);
@@ -781,7 +798,18 @@ static void test_get_set_item(void)
     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
         "test get set item", FALSE);
 
+    /* get item from a different tree */
+    hTree2 = create_treeview_control(0);
+
+    tviRoot.hItem = hRoot;
+    tviRoot.mask = TVIF_STATE;
+    tviRoot.state = 0;
+    ret = SendMessage( hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot );
+    expect(TRUE, ret);
+    ok(tviRoot.state == TVIS_FOCUSED, "got state 0x%0x\n", tviRoot.state);
+
     DestroyWindow(hTree);
+    DestroyWindow(hTree2);
 }
 
 static void test_get_set_itemheight(void)
@@ -935,6 +963,10 @@ static void test_get_set_unicodeformat(void)
     hTree = create_treeview_control(0);
     fill_tree(hTree);
 
+    /* Check that an invalid format returned by NF_QUERY defaults to ANSI */
+    bPreviousSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
+    ok(bPreviousSetting == 0, "Format should be ANSI.\n");
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set to Unicode */
@@ -986,10 +1018,17 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
     }
 
     switch(message) {
+    case WM_NOTIFYFORMAT:
+    {
+        /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */
+        if (lParam == NF_QUERY) return 0;
+        break;
+    }
+
     case WM_NOTIFY:
     {
         NMHDR *pHdr = (NMHDR *)lParam;
-    
+
         ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n");
         if (pHdr->idFrom == 100)
         {
@@ -1050,8 +1089,6 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
                 ok(pTreeView->itemNew.mask ==
                    (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE),
                    "got wrong mask %x\n", pTreeView->itemNew.mask);
-                ok((pTreeView->itemNew.state & TVIS_EXPANDED) == 0,
-                   "got wrong state %x\n", pTreeView->itemNew.state);
                 ok(pTreeView->itemOld.mask == 0,
                    "got wrong mask %x\n", pTreeView->itemOld.mask);
 
@@ -1361,6 +1398,11 @@ static void test_expandnotify(void)
     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
     expect(TRUE, ret);
 
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "no collapse notifications", FALSE);
+
     g_get_from_expand = TRUE;
     /* expand */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
@@ -1427,6 +1469,67 @@ static void test_expandnotify(void)
     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node (collapse)", FALSE);
 
     DestroyWindow(hTree);
+
+    /* some keyboard events are also translated to expand */
+    hTree = create_treeview_control(0);
+    fill_tree(hTree);
+
+    /* preselect root node here */
+    ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
+    expect(TRUE, ret);
+
+    g_get_from_expand = TRUE;
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE);
+    ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
+       g_item_expanding.state);
+    ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
+       g_item_expanded.state);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node again", FALSE);
+    ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
+       g_item_expanding.state);
+    ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
+       g_item_expanded.state);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "collapse node", FALSE);
+    ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
+       g_item_expanding.state);
+    ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
+       g_item_expanded.state);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "collapse node again", FALSE);
+    ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
+       g_item_expanding.state);
+    g_get_from_expand = FALSE;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE);
+
+    /* go to child */
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_RIGHT, 0);
+    expect(FALSE, ret);
+
+    /* try to expand child that doesn't have children itself */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
+    expect(FALSE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_empty_kb_seq, "expand node with no children", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 static void test_expandedimage(void)
@@ -1556,6 +1659,55 @@ static void test_delete_items(void)
     DestroyWindow(hTree);
 }
 
+static void test_cchildren(void)
+{
+    HWND hTree;
+    INT ret;
+    TVITEMA item;
+
+    hTree = create_treeview_control(0);
+    fill_tree(hTree);
+
+    ret = SendMessage(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
+    expect(TRUE, ret);
+
+    /* check cChildren - automatic mode */
+    item.hItem = hRoot;
+    item.mask = TVIF_CHILDREN;
+
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    expect(0, item.cChildren);
+
+    DestroyWindow(hTree);
+
+    /* start over */
+    hTree = create_treeview_control(0);
+    fill_tree(hTree);
+
+    /* turn off automatic mode by setting cChildren explicitly */
+    item.hItem = hRoot;
+    item.mask = TVIF_CHILDREN;
+
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    expect(1, item.cChildren);
+
+    ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    ret = SendMessage(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
+    expect(TRUE, ret);
+
+    /* check cChildren */
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+todo_wine
+    expect(1, item.cChildren);
+
+    DestroyWindow(hTree);
+}
+
 struct _ITEM_DATA
 {
     HTREEITEM  parent; /* for root value of parent field is unidetified */
@@ -1611,9 +1763,9 @@ static void test_htreeitem_layout(void)
 
 static void test_TVS_CHECKBOXES(void)
 {
-    HIMAGELIST himl;
+    HIMAGELIST himl, himl2;
+    HWND hTree, hTree2;
     TVITEMA item;
-    HWND hTree;
     DWORD ret;
 
     hTree = create_treeview_control(0);
@@ -1643,6 +1795,10 @@ static void test_TVS_CHECKBOXES(void)
     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
     ok(himl != NULL, "got %p\n", himl);
 
+    himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
+    ok(himl2 != NULL, "got %p\n", himl2);
+    ok(himl2 == himl, "got %p, expected %p\n", himl2, himl);
+
     item.hItem = hRoot;
     item.mask = TVIF_STATE;
     item.state = 0;
@@ -1659,6 +1815,25 @@ static void test_TVS_CHECKBOXES(void)
     expect(TRUE, ret);
     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
 
+    /* create another control and check its checkbox list */
+    hTree2 = create_treeview_control(0);
+    fill_tree(hTree2);
+
+    /* set some index for a child */
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    item.state = INDEXTOSTATEIMAGEMASK(4);
+    item.stateMask = TVIS_STATEIMAGEMASK;
+    ret = SendMessageA(hTree2, TVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    /* enabling check boxes set all items to 1 state image index */
+    SetWindowLongA(hTree2, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
+    himl2 = (HIMAGELIST)SendMessageA(hTree2, TVM_GETIMAGELIST, TVSIL_STATE, 0);
+    ok(himl2 != NULL, "got %p\n", himl2);
+    ok(himl != himl2, "got %p, expected %p\n", himl2, himl);
+
+    DestroyWindow(hTree2);
     DestroyWindow(hTree);
 
     /* the same, but initially created with TVS_CHECKBOXES */
@@ -1730,6 +1905,47 @@ static void test_TVM_GETNEXTITEM(void)
     DestroyWindow(hTree);
 }
 
+static void test_TVM_HITTEST(void)
+{
+    HWND hTree;
+    LRESULT ret;
+    RECT rc;
+    TVHITTESTINFO ht;
+
+    hTree = create_treeview_control(0);
+    fill_tree(hTree);
+
+    *(HTREEITEM*)&rc = hRoot;
+    ret = SendMessage(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
+    expect(TRUE, (BOOL)ret);
+
+    ht.pt.x = rc.left-1;
+    ht.pt.y = rc.top;
+
+    ret = SendMessage(hTree, TVM_HITTEST, 0, (LPARAM)&ht);
+    ok((HTREEITEM)ret == hRoot, "got %p, expected %p\n", (HTREEITEM)ret, hRoot);
+    ok(ht.hItem == hRoot, "got %p, expected %p\n", ht.hItem, hRoot);
+    ok(ht.flags == TVHT_ONITEMBUTTON, "got %d, expected %d\n", ht.flags, TVHT_ONITEMBUTTON);
+
+    ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
+    expect(TRUE, (BOOL)ret);
+
+    *(HTREEITEM*)&rc = hChild;
+    ret = SendMessage(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
+    expect(TRUE, (BOOL)ret);
+
+    ht.pt.x = rc.left-1;
+    ht.pt.y = rc.top;
+
+    ret = SendMessage(hTree, TVM_HITTEST, 0, (LPARAM)&ht);
+    ok((HTREEITEM)ret == hChild, "got %p, expected %p\n", (HTREEITEM)ret, hChild);
+    ok(ht.hItem == hChild, "got %p, expected %p\n", ht.hItem, hChild);
+    /* Wine returns item button here, but this item has no button */
+    todo_wine ok(ht.flags == TVHT_ONITEMINDENT, "got %d, expected %d\n", ht.flags, TVHT_ONITEMINDENT);
+
+    DestroyWindow(hTree);
+}
+
 START_TEST(treeview)
 {
     HMODULE hComctl32;
@@ -1798,9 +2014,11 @@ START_TEST(treeview)
     test_TVS_SINGLEEXPAND();
     test_WM_PAINT();
     test_delete_items();
+    test_cchildren();
     test_htreeitem_layout();
     test_TVS_CHECKBOXES();
     test_TVM_GETNEXTITEM();
+    test_TVM_HITTEST();
 
     if (!load_v6_module(&ctx_cookie, &hCtx))
     {