diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c index 1e741924ce8..f9a42dfe604 100644 --- a/rostests/winetests/comctl32/comboex.c +++ b/rostests/winetests/comctl32/comboex.c @@ -22,11 +22,23 @@ #include #include "wine/test.h" +#include "msg.h" + +#define EDITBOX_SEQ_INDEX 0 +#define NUM_MSG_SEQUENCES 1 + +#define EDITBOX_ID 0 + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) + +static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; static HWND hComboExParentWnd; static HINSTANCE hMainHinst; static const char ComboExTestClass[] = "ComboExTestClass"; +static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); + #define MAX_CHARS 100 static char *textBuffer = NULL; @@ -42,7 +54,7 @@ static LONG addItem(HWND cbex, int idx, LPTSTR text) { cbexItem.iItem = idx; cbexItem.pszText = text; cbexItem.cchTextMax = 0; - return (LONG)SendMessage(cbex, CBEM_INSERTITEM, 0,(LPARAM)&cbexItem); + return SendMessage(cbex, CBEM_INSERTITEM, 0, (LPARAM)&cbexItem); } static LONG setItem(HWND cbex, int idx, LPTSTR text) { @@ -52,11 +64,11 @@ static LONG setItem(HWND cbex, int idx, LPTSTR text) { cbexItem.iItem = idx; cbexItem.pszText = text; cbexItem.cchTextMax = 0; - return (LONG)SendMessage(cbex, CBEM_SETITEM, 0,(LPARAM)&cbexItem); + return SendMessage(cbex, CBEM_SETITEM, 0, (LPARAM)&cbexItem); } static LONG delItem(HWND cbex, int idx) { - return (LONG)SendMessage(cbex, CBEM_DELETEITEM, (LPARAM)idx, 0); + return SendMessage(cbex, CBEM_DELETEITEM, idx, 0); } static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) { @@ -65,7 +77,51 @@ static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) { cbItem->pszText = textBuffer; cbItem->iItem = idx; cbItem->cchTextMax = 100; - return (LONG)SendMessage(cbex, CBEM_GETITEM, 0, (LPARAM)cbItem); + return SendMessage(cbex, CBEM_GETITEM, 0, (LPARAM)cbItem); +} + +static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static LONG defwndproc_counter = 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 = EDITBOX_ID; + + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + add_message(sequences, EDITBOX_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND subclass_editbox(HWND hwndComboEx) +{ + WNDPROC oldproc; + HWND hwnd; + + hwnd = (HWND)SendMessage(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)editbox_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + return hwnd; } static void test_comboboxex(void) { @@ -288,6 +344,41 @@ static void test_WM_LBUTTONDOWN(void) DestroyWindow(hComboEx); } +static void test_CB_GETLBTEXT(void) +{ + HWND hCombo; + CHAR buff[1]; + COMBOBOXEXITEMA item; + LRESULT ret; + + hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + /* set text to null */ + addItem(hCombo, 0, NULL); + + buff[0] = 'a'; + item.mask = CBEIF_TEXT; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = 1; + ret = SendMessage(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item); + ok(ret != 0, "CBEM_GETITEM failed\n"); + ok(buff[0] == 0, "\n"); + + ret = SendMessage(hCombo, CB_GETLBTEXTLEN, 0, 0); + ok(ret == 0, "Expected zero length\n"); + + ret = SendMessage(hCombo, CB_GETLBTEXTLEN, 0, 0); + ok(ret == 0, "Expected zero length\n"); + + buff[0] = 'a'; + ret = SendMessage(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff); + ok(ret == 0, "Expected zero length\n"); + ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff); + + DestroyWindow(hCombo); +} + static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { @@ -321,6 +412,8 @@ static int init(void) iccex.dwICC = ICC_USEREX_CLASSES; pInitCommonControlsEx(&iccex); + pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410); + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -355,13 +448,87 @@ static void cleanup(void) UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); } +static void test_comboboxex_subclass(void) +{ + HWND hComboEx, hCombo, hEdit; + + hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + hCombo = (HWND)SendMessage(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); + ok(hCombo != NULL, "Failed to get internal combo\n"); + hEdit = (HWND)SendMessage(hComboEx, CBEM_GETEDITCONTROL, 0, 0); + ok(hEdit != NULL, "Failed to get internal edit\n"); + + if (pSetWindowSubclass) + { + ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); + ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); + } + + DestroyWindow(hComboEx); +} + +static const struct message test_setitem_edit_seq[] = { + { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID }, + { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID }, + { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID }, + { 0 } +}; + +static void test_get_set_item(void) +{ + char textA[] = "test"; + HWND hComboEx; + COMBOBOXEXITEMA item; + BOOL ret; + + hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + subclass_editbox(hComboEx); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.mask = CBEIF_TEXT; + item.pszText = textA; + item.iItem = -1; + ret = SendMessage(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + + ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE); + + /* get/set lParam */ + item.mask = CBEIF_LPARAM; + item.iItem = -1; + item.lParam = 0xdeadbeef; + ret = SendMessage(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + ok(item.lParam == 0, "Expected zero, got %ld\n", item.lParam); + + item.lParam = 0xdeadbeef; + ret = SendMessage(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + + item.lParam = 0; + ret = SendMessage(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + ok(item.lParam == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", item.lParam); + + DestroyWindow(hComboEx); +} + START_TEST(comboex) { if (!init()) return; + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + test_comboboxex(); test_WM_LBUTTONDOWN(); + test_CB_GETLBTEXT(); + test_comboboxex_subclass(); + test_get_set_item(); cleanup(); } diff --git a/rostests/winetests/comctl32/comctl32.rbuild b/rostests/winetests/comctl32/comctl32.rbuild index 94804620870..d1e44b5de16 100644 --- a/rostests/winetests/comctl32/comctl32.rbuild +++ b/rostests/winetests/comctl32/comctl32.rbuild @@ -4,6 +4,8 @@ . + 0x0600 + 0x0500 comboex.c datetime.c dpa.c @@ -14,7 +16,6 @@ misc.c monthcal.c mru.c - msg.c progress.c propsheet.c rebar.c diff --git a/rostests/winetests/comctl32/comctl32_ros.diff b/rostests/winetests/comctl32/comctl32_ros.diff deleted file mode 100644 index d8b962d3ae0..00000000000 --- a/rostests/winetests/comctl32/comctl32_ros.diff +++ /dev/null @@ -1,37 +0,0 @@ -Index: dpa.c -=================================================================== ---- dpa.c (revision 25766) -+++ dpa.c (working copy) -@@ -25,6 +25,7 @@ - - #include "windef.h" - #include "winbase.h" -+#include "wingdi.h" - #include "winuser.h" - #include "commctrl.h" - #include "objidl.h" -Index: monthcal.c -=================================================================== ---- monthcal.c (revision 25766) -+++ monthcal.c (working copy) -@@ -23,6 +23,7 @@ - - #include "windef.h" - #include "winbase.h" -+#include "wingdi.h" - #include "winuser.h" - - #include "commctrl.h" -Index: mru.c -=================================================================== ---- mru.c (revision 25766) -+++ mru.c (working copy) -@@ -75,7 +75,7 @@ - - - /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */ --static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) -+static LONG mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) - { - LONG ret; - DWORD dwMaxSubkeyLen, dwMaxValueLen; diff --git a/rostests/winetests/comctl32/datetime.c b/rostests/winetests/comctl32/datetime.c index 8fdbbe53608..a97ab342dae 100644 --- a/rostests/winetests/comctl32/datetime.c +++ b/rostests/winetests/comctl32/datetime.c @@ -33,113 +33,97 @@ static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; static const struct message test_dtm_set_format_seq[] = { - { DTM_SETFORMATA, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { DTM_SETFORMATA, sent|wparam, 0x00000000 }, + { DTM_SETFORMATA, sent|wparam|lparam, 0, 0 }, + { DTM_SETFORMATA, sent|wparam, 0 }, { 0 } }; static const struct message test_dtm_set_and_get_mccolor_seq[] = { - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00ffffff }, - { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00dcb464 }, - { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255, 255, 255) }, + { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(100, 180, 220) }, + { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 }, { 0 } }; static const struct message test_dtm_set_and_get_mcfont_seq[] = { - { DTM_SETMCFONT, sent|lparam, 0, 0x00000001 }, - { DTM_GETMCFONT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { DTM_SETMCFONT, sent|lparam, 0, 1 }, + { DTM_GETMCFONT, sent|wparam|lparam, 0, 0 }, { 0 } }; static const struct message test_dtm_get_monthcal_seq[] = { - { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { DTM_GETMONTHCAL, sent|wparam|lparam, 0, 0 }, { 0 } }; static const struct message test_dtm_set_and_get_range_seq[] = { - { DTM_SETRANGE, sent|wparam, 0x00000001 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000002 }, - { DTM_SETRANGE, sent|wparam, 0x00000002 }, - { DTM_GETRANGE, sent|wparam, 0x00000000}, - { DTM_SETRANGE, sent|wparam, 0x00000001 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MAX }, + { DTM_SETRANGE, sent|wparam, GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, { 0 } }; static const struct message test_dtm_set_range_swap_min_max_seq[] = { - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, - { DTM_SETRANGE, sent|wparam, 0x00000003 }, - { DTM_GETRANGE, sent|wparam, 0x00000000 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, + { DTM_GETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, + { DTM_GETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, + { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, + { DTM_GETRANGE, sent|wparam, 0 }, { 0 } }; static const struct message test_dtm_set_and_get_system_time_seq[] = { - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 }, - { 0x0090, sent|optional }, /* Vista */ - { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 }, - { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 }, - { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 }, + { DTM_SETSYSTEMTIME, sent|wparam, GDT_NONE }, + { DTM_GETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, + { DTM_GETSYSTEMTIME, sent|wparam, 0 }, + { DTM_SETSYSTEMTIME, sent|wparam, 0 }, { 0 } }; -static const struct message destroy_window_seq[] = { - { 0x0090, sent|optional }, /* Vista */ - { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { 0 } -}; - -struct subclass_info -{ - WNDPROC oldproc; -}; - static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -154,21 +138,17 @@ static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wPa add_message(sequences, DATETIME_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } -static HWND create_datetime_control(DWORD style, DWORD exstyle) +static HWND create_datetime_control(DWORD style) { - struct subclass_info *info; + WNDPROC oldproc; HWND hWndDateTime = NULL; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - hWndDateTime = CreateWindowEx(0, DATETIMEPICK_CLASS, NULL, @@ -179,44 +159,47 @@ static HWND create_datetime_control(DWORD style, DWORD exstyle) NULL, NULL); - if (!hWndDateTime) { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!hWndDateTime) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC, - (LONG_PTR)datetime_subclass_proc); - SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC, + (LONG_PTR)datetime_subclass_proc); + SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc); return hWndDateTime; } -static void test_dtm_set_format(HWND hWndDateTime) +static void test_dtm_set_format(void) { + HWND hWnd; CHAR txt[256]; SYSTEMTIME systime; LRESULT r; - r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, 0); + hWnd = create_datetime_control(DTS_SHOWNONE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + r = SendMessage(hWnd, DTM_SETFORMAT, 0, 0); expect(1, r); - r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, + r = SendMessage(hWnd, DTM_SETFORMAT, 0, (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy"); expect(1, r); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE); - r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, + r = SendMessage(hWnd, DTM_SETFORMAT, 0, (LPARAM)"'hh' hh"); expect(1, r); ZeroMemory(&systime, sizeof(systime)); systime.wYear = 2000; systime.wMonth = systime.wDay = 1; - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime); expect(1, r); - GetWindowText(hWndDateTime, txt, 256); - todo_wine ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + GetWindowText(hWnd, txt, 256); + ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt); + + DestroyWindow(hWnd); } static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name) @@ -239,43 +222,60 @@ static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r); } -static void test_dtm_set_and_get_mccolor(HWND hWndDateTime) +static void test_dtm_set_and_get_mccolor(void) { - test_mccolor_types(hWndDateTime, MCSC_BACKGROUND, "MCSC_BACKGROUND"); - test_mccolor_types(hWndDateTime, MCSC_MONTHBK, "MCSC_MONTHBK"); - test_mccolor_types(hWndDateTime, MCSC_TEXT, "MCSC_TEXT"); - test_mccolor_types(hWndDateTime, MCSC_TITLEBK, "MCSC_TITLEBK"); - test_mccolor_types(hWndDateTime, MCSC_TITLETEXT, "MCSC_TITLETEXT"); - test_mccolor_types(hWndDateTime, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT"); + HWND hWnd; + + hWnd = create_datetime_control(DTS_SHOWNONE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND"); + test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK"); + test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT"); + test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK"); + test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT"); + test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT"); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + + DestroyWindow(hWnd); } -static void test_dtm_set_and_get_mcfont(HWND hWndDateTime) +static void test_dtm_set_and_get_mcfont(void) { HFONT hFontOrig, hFontNew; + HWND hWnd; + + hWnd = create_datetime_control(DTS_SHOWNONE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); hFontOrig = GetStockObject(DEFAULT_GUI_FONT); - SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE); - hFontNew = (HFONT)SendMessage(hWndDateTime, DTM_GETMCFONT, 0, 0); + SendMessage(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE); + hFontNew = (HFONT)SendMessage(hWnd, DTM_GETMCFONT, 0, 0); ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hWnd); } -static void test_dtm_get_monthcal(HWND hWndDateTime) +static void test_dtm_get_monthcal(void) { LRESULT r; + HWND hWnd; + + hWnd = create_datetime_control(DTS_SHOWNONE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); todo_wine { - r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0); + r = SendMessage(hWnd, DTM_GETMONTHCAL, 0, 0); ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r); } ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hWnd); } static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds) @@ -318,24 +318,29 @@ static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2) #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n") #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n") -static void test_dtm_set_and_get_range(HWND hWndDateTime) +static void test_dtm_set_and_get_range(void) { LRESULT r; SYSTEMTIME st[2]; SYSTEMTIME getSt[2]; + HWND hWnd; + + hWnd = create_datetime_control(DTS_SHOWNONE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); /* initialize st[0] to lowest possible value */ fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); /* initialize st[1] to all invalid numbers */ fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); ok(r == GDTR_MIN, "Expected %x, not %x(GDTR_MAX) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MIN, GDTR_MAX, GDTR_MIN | GDTR_MAX, r); expect_systime(&st[0], &getSt[0]); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); expect_unsuccess(0, r); /* set st[0] to all invalid numbers */ @@ -343,25 +348,25 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime) /* set st[1] to highest possible value */ fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); todo_wine { ok(r == GDTR_MAX, "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MAX, GDTR_MIN, GDTR_MIN | GDTR_MAX, r); } expect_systime(&st[1], &getSt[1]); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); expect_unsuccess(0, r); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect_unsuccess(0, r); /* set st[0] to highest possible value */ fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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]); @@ -371,9 +376,9 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime) /* set st[1] to highest possible value */ fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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]); @@ -383,32 +388,37 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime) /* set st[1] to value lower than maximum */ fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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]); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + + DestroyWindow(hWnd); } /* when maxmax, min and max values should be swapped by DTM_SETRANGE automatically */ - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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); todo_wine { - expect_systime(&st[0], &getSt[0]); - } - todo_wine { - expect_systime(&st[1], &getSt[1]); + ok(compare_systime(&st[0], &getSt[0]) == 1 || + broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version <= 5.80 */ + "ST1 != ST2\n"); + + ok(compare_systime(&st[1], &getSt[1]) == 1 || + broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ + "ST1 != ST2\n"); } fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]); + 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); /* the time part seems to not change after swapping the min and max values and doing DTM_SETSYSTEMTIME */ expect_systime_date(&st[0], &getSt[0]); todo_wine { - expect_systime_time(&origSt, &getSt[0]); + ok(compare_systime_time(&origSt, &getSt[0]) == 1 || + broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ + "ST1.time != ST2.time\n"); } /* set st[0] to value higher than minimum */ @@ -447,18 +462,21 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime) /* set st[1] to value lower than maximum */ fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); /* for some reason after we swapped the min and max values before, whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values swapped*/ - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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); todo_wine { - expect_systime(&st[0], &getSt[1]); - } - todo_wine { - expect_systime(&st[1], &getSt[0]); + ok(compare_systime(&st[0], &getSt[1]) == 1 || + broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ + "ST1 != ST2\n"); + + ok(compare_systime(&st[1], &getSt[0]) == 1 || + broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */ + "ST1 != ST2\n"); } /* set st[0] to value higher than st[1] */ @@ -467,9 +485,9 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime) /* set min>max again, so that the return values of DTM_GETRANGE are no longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/ - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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[1]); expect_systime(&st[1], &getSt[0]); @@ -479,25 +497,25 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime) /* set st[1] to highest possible value */ fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt); + 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]); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + + DestroyWindow(hWnd); } -static void test_dtm_set_and_get_system_time(HWND hWndDateTime) +static void test_dtm_set_and_get_system_time(void) { LRESULT r; - SYSTEMTIME st; - SYSTEMTIME getSt; - HWND hWndDateTime_test_gdt_none; + SYSTEMTIME st, getSt, ref; + HWND hWnd, hWndDateTime_test_gdt_none; - hWndDateTime_test_gdt_none = create_datetime_control(0, 0); + hWndDateTime_test_gdt_none = create_datetime_control(0); ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none); if(hWndDateTime_test_gdt_none) { @@ -513,64 +531,175 @@ static void test_dtm_set_and_get_system_time(HWND hWndDateTime) DestroyWindow(hWndDateTime_test_gdt_none); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); + hWnd = create_datetime_control(DTS_SHOWNONE); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r); /* set st to lowest possible value */ fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); expect(1, r); /* set st to highest possible value */ fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); expect(1, r); /* set st to value between min and max */ fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); expect(1, r); - r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 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(&st, &getSt); /* set st to invalid value */ fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000); - r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); expect_unsuccess(0, r); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* set to some valid value */ + GetSystemTime(&ref); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref); + expect(1, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + + /* year invalid */ + st = ref; + st.wYear = 0; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + todo_wine expect(1, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* month invalid */ + st = ref; + st.wMonth = 13; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* day invalid */ + st = ref; + st.wDay = 32; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* day of week isn't validated */ + st = ref; + st.wDayOfWeek = 10; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(1, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* hour invalid */ + st = ref; + st.wHour = 25; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* minute invalid */ + st = ref; + st.wMinute = 60; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* sec invalid */ + st = ref; + st.wSecond = 60; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + /* msec invalid */ + st = ref; + st.wMilliseconds = 1000; + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(0, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + expect_systime(&ref, &getSt); + + /* day of week should be calculated automatically, + actual day of week for this date is 4 */ + fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200); + r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); + expect(1, r); + r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); + expect(GDT_VALID, r); + /* 01.10.2009 is Thursday */ + expect(4, (LRESULT)getSt.wDayOfWeek); + st.wDayOfWeek = 4; + expect_systime(&st, &getSt); + + DestroyWindow(hWnd); } -static void test_datetime_control(void) +static void test_wm_set_get_text(void) { - HWND hWndDateTime; + static const CHAR a_str[] = "a"; + char buff[16], time[16]; + HWND hWnd; + LRESULT ret; - hWndDateTime = create_datetime_control(DTS_SHOWNONE, 0); + hWnd = create_datetime_control(0); - ok(hWndDateTime != NULL, "Expected non NULL, got %p\n", hWndDateTime); - if(hWndDateTime!=NULL) { - test_dtm_set_format(hWndDateTime); - test_dtm_set_and_get_mccolor(hWndDateTime); - test_dtm_set_and_get_mcfont(hWndDateTime); - test_dtm_get_monthcal(hWndDateTime); - test_dtm_set_and_get_range(hWndDateTime); - test_dtm_set_range_swap_min_max(hWndDateTime); - test_dtm_set_and_get_system_time(hWndDateTime); - } - else { - skip("hWndDateTime is NULL\n"); - } + ret = SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)a_str); + ok(CB_ERR == ret || + broken(0 == ret) || /* comctl32 <= 4.72 */ + broken(1 == ret), /* comctl32 <= 4.70 */ + "Expected CB_ERR, got %ld\n", ret); - DestroyWindow(hWndDateTime); - ok_sequence(sequences, DATETIME_SEQ_INDEX, destroy_window_seq, "test_dtm_set_and_get_system_time", TRUE); + buff[0] = 0; + ret = SendMessage(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff); + ok(strcmp(buff, a_str) != 0, "Expected text not to change, got %s\n", buff); + + GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time)); + ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff); + + DestroyWindow(hWnd); +} + +static void test_dts_shownone(void) +{ + HWND hwnd; + DWORD style; + + /* it isn't allowed to change DTS_SHOWNONE after creation */ + hwnd = create_datetime_control(0); + style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style | DTS_SHOWNONE); + style = GetWindowLong(hwnd, GWL_STYLE); + ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n"); + DestroyWindow(hwnd); + + hwnd = create_datetime_control(DTS_SHOWNONE); + style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE); + style = GetWindowLong(hwnd, GWL_STYLE); + ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n"); + DestroyWindow(hwnd); } START_TEST(datetime) @@ -592,5 +721,13 @@ START_TEST(datetime) init_msg_sequences(sequences, NUM_MSG_SEQUENCES); - test_datetime_control(); + test_dtm_set_format(); + test_dtm_set_and_get_mccolor(); + test_dtm_set_and_get_mcfont(); + test_dtm_get_monthcal(); + test_dtm_set_and_get_range(); + test_dtm_set_range_swap_min_max(); + test_dtm_set_and_get_system_time(); + test_wm_set_get_text(); + test_dts_shownone(); } diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c index 221bcba1678..419c1b14d0e 100644 --- a/rostests/winetests/comctl32/dpa.c +++ b/rostests/winetests/comctl32/dpa.c @@ -31,17 +31,14 @@ #include "wine/test.h" -#define DPAM_NOSORT 0x1 -#define DPAM_INSERT 0x4 -#define DPAM_DELETE 0x8 +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) -typedef struct _ITEMDATA +typedef struct _STREAMDATA { - INT iPos; - PVOID pvData; -} ITEMDATA, *LPITEMDATA; - -typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM); + DWORD dwSize; + DWORD dwData2; + DWORD dwItems; +} STREAMDATA, *PSTREAMDATA; static HDPA (WINAPI *pDPA_Clone)(const HDPA,const HDPA); static HDPA (WINAPI *pDPA_Create)(INT); @@ -55,9 +52,9 @@ static INT (WINAPI *pDPA_GetPtr)(const HDPA,INT); static INT (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID); static BOOL (WINAPI *pDPA_Grow)(HDPA,INT); static INT (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID); -static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTM,IStream*,LPARAM); +static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPVOID); static BOOL (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM); -static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTM,IStream*,LPARAM); +static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPVOID); static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT); static BOOL (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID); static BOOL (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM); @@ -109,14 +106,22 @@ static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp) return p1 > p2 ? -1 : p1 < p2 ? 1 : 0; } +/* merge callback messages counter + DPAMM_MERGE 1 + DPAMM_DELETE 2 + DPAMM_INSERT 3 */ +static INT nMessages[4]; + static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) { + nMessages[op]++; ok(lp == 0xdeadbeef, "lp=%ld\n", lp); return p1; } static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) { + nMessages[op]++; ok(lp == 0xdeadbeef, "lp=%ld\n", lp); return ((PCHAR)p2)+1; } @@ -134,30 +139,30 @@ static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp) return pItem != (PVOID)3; } -static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) +static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp) { HRESULT hRes; - - ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + + ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp); hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); - hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); + expect(S_OK, hRes); + hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL); + expect(S_OK, hRes); return S_OK; } -static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) +static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp) { HRESULT hRes; INT iOldPos; iOldPos = pInfo->iPos; - ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp); hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); + expect(S_OK, hRes); ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos); - hRes = IStream_Read(pStm, &pInfo->pvData, sizeof(PVOID), NULL); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); + hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL); + expect(S_OK, hRes); return S_OK; } @@ -200,7 +205,6 @@ static void test_dpa(void) INT ret, i; PVOID p; DWORD dw, dw2, dw3; - HRESULT hRes; BOOL rc; GetSystemInfo(&si); @@ -209,9 +213,9 @@ static void test_dpa(void) dpa3 = pDPA_CreateEx(0, hHeap); ok(dpa3 != NULL, "\n"); ret = pDPA_Grow(dpa3, si.dwPageSize + 1); - todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "ret=%d error=%d\n", ret, GetLastError()); - + dpa = pDPA_Create(0); ok(dpa != NULL, "\n"); @@ -288,9 +292,9 @@ static void test_dpa(void) ok(j == DPA_ERR, "j=%d\n", j); /* ... but for a binary search it's ignored */ j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); - todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i); + ok(j+1 == i, "j=%d i=%d\n", j, i); } - + /* Try to get the index of a nonexistent item */ i = pDPA_GetPtrIndex(dpa, (PVOID)7); ok(i == DPA_ERR, "i=%d\n", i); @@ -335,49 +339,6 @@ static void test_dpa(void) ok(j != i, "i=%d\n", i); } - if(pDPA_Merge) - { - /* Delete all even entries from dpa */ - p = pDPA_DeletePtr(dpa, 1); - p = pDPA_DeletePtr(dpa, 2); - p = pDPA_DeletePtr(dpa, 3); - rc=CheckDPA(dpa, 0x135, &dw); - ok(rc, "dw=0x%x\n", dw); - - /* Delete all odd entries from dpa2 */ - pDPA_Merge(dpa2, dpa, DPAM_DELETE, - CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef); - todo_wine - { - rc=CheckDPA(dpa2, 0x246, &dw2); - ok(rc, "dw=0x%x\n", dw2); - } - - /* Merge dpa3 into dpa2 and dpa */ - pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT, - CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); - pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, - CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); - - rc=CheckDPA(dpa, 0x123456, &dw); - ok(rc, "dw=0x%x\n", dw); - rc=CheckDPA(dpa2, 0x123456, &dw2); - ok(rc || - broken(!rc), /* win98 */ - "dw2=0x%x\n", dw2); - rc=CheckDPA(dpa3, 0x123456, &dw3); - ok(rc, "dw3=0x%x\n", dw3); - } - - if(pDPA_EnumCallback) - { - nEnum = 0; - pDPA_EnumCallback(dpa2, CB_EnumFirstThree, dpa2); - rc=CheckDPA(dpa2, 0x777456, &dw2); - ok(rc, "dw=0x%x\n", dw2); - ok(nEnum == 3, "nEnum=%d\n", nEnum); - } - /* Setting item with huge index should work */ ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n"); ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef); @@ -386,62 +347,397 @@ static void test_dpa(void) pDPA_DeleteAllPtrs(dpa2); rc=CheckDPA(dpa2, 0, &dw2); ok(rc, "dw2=0x%x\n", dw2); + + pDPA_Destroy(dpa); pDPA_Destroy(dpa2); + pDPA_Destroy(dpa3); +} - if(pDPA_DestroyCallback) +static void test_DPA_Merge(void) +{ + HDPA dpa, dpa2, dpa3; + INT ret, i; + DWORD dw; + BOOL rc; + + if(!pDPA_Merge) { - nEnum = 0; - pDPA_DestroyCallback(dpa3, CB_EnumFirstThree, dpa3); - ok(nEnum == 3, "nEnum=%d\n", nEnum); + win_skip("DPA_Merge() not available\n"); + return; } - else pDPA_Destroy(dpa3); - if(!pDPA_SaveStream) - goto skip_stream_tests; + dpa = pDPA_Create(0); + dpa2 = pDPA_Create(0); + dpa3 = pDPA_Create(0); + + ret = pDPA_InsertPtr(dpa, 0, (PVOID)1); + ok(ret == 0, "ret=%d\n", ret); + ret = pDPA_InsertPtr(dpa, 1, (PVOID)3); + ok(ret == 1, "ret=%d\n", ret); + ret = pDPA_InsertPtr(dpa, 2, (PVOID)5); + ok(ret == 2, "ret=%d\n", ret); + + rc = CheckDPA(dpa, 0x135, &dw); + ok(rc, "dw=0x%x\n", dw); + + for (i = 0; i < 6; i++) + { + ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i)); + ok(ret == i, "ret=%d\n", ret); + ret = pDPA_InsertPtr(dpa3, i, (PVOID)(INT_PTR)(i+1)); + ok(ret == i, "ret=%d\n", ret); + } + + rc = CheckDPA(dpa2, 0x654321, &dw); + ok(rc, "dw=0x%x\n", dw); + rc = CheckDPA(dpa3, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + + /* Delete all odd entries from dpa2 */ + memset(nMessages, 0, sizeof(nMessages)); + pDPA_Merge(dpa2, dpa, DPAM_INTERSECT, + CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef); + rc = CheckDPA(dpa2, 0x246, &dw); + ok(rc, "dw=0x%x\n", dw); + + expect(3, nMessages[DPAMM_MERGE]); + expect(3, nMessages[DPAMM_DELETE]); + expect(0, nMessages[DPAMM_INSERT]); + + for (i = 0; i < 6; i++) + { + ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i)); + ok(ret == i, "ret=%d\n", ret); + } + + /* DPAM_INTERSECT - returning source while merging */ + memset(nMessages, 0, sizeof(nMessages)); + pDPA_Merge(dpa2, dpa, DPAM_INTERSECT, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + rc = CheckDPA(dpa2, 0x135, &dw); + ok(rc, "dw=0x%x\n", dw); + + expect(3, nMessages[DPAMM_MERGE]); + expect(6, nMessages[DPAMM_DELETE]); + expect(0, nMessages[DPAMM_INSERT]); + + /* DPAM_UNION */ + pDPA_DeleteAllPtrs(dpa); + pDPA_InsertPtr(dpa, 0, (PVOID)1); + pDPA_InsertPtr(dpa, 1, (PVOID)3); + pDPA_InsertPtr(dpa, 2, (PVOID)5); + pDPA_DeleteAllPtrs(dpa2); + pDPA_InsertPtr(dpa2, 0, (PVOID)2); + pDPA_InsertPtr(dpa2, 1, (PVOID)4); + pDPA_InsertPtr(dpa2, 2, (PVOID)6); + + memset(nMessages, 0, sizeof(nMessages)); + pDPA_Merge(dpa2, dpa, DPAM_UNION, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + rc = CheckDPA(dpa2, 0x123456, &dw); + ok(rc || + broken(!rc && dw == 0x23456), /* 4.7x */ + "dw=0x%x\n", dw); + + expect(0, nMessages[DPAMM_MERGE]); + expect(0, nMessages[DPAMM_DELETE]); + ok(nMessages[DPAMM_INSERT] == 3 || + broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */ + "Expected 3, got %d\n", nMessages[DPAMM_INSERT]); + + /* Merge dpa3 into dpa2 and dpa */ + memset(nMessages, 0, sizeof(nMessages)); + pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + expect(3, nMessages[DPAMM_MERGE]); + expect(0, nMessages[DPAMM_DELETE]); + expect(3, nMessages[DPAMM_INSERT]); + + + pDPA_DeleteAllPtrs(dpa2); + pDPA_InsertPtr(dpa2, 0, (PVOID)2); + pDPA_InsertPtr(dpa2, 1, (PVOID)4); + pDPA_InsertPtr(dpa2, 2, (PVOID)6); + + memset(nMessages, 0, sizeof(nMessages)); + pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + expect(3, nMessages[DPAMM_MERGE]); + expect(0, nMessages[DPAMM_DELETE]); + ok(nMessages[DPAMM_INSERT] == 3 || + broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */ + "Expected 3, got %d\n", nMessages[DPAMM_INSERT]); + + rc = CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + rc = CheckDPA(dpa2, 0x123456, &dw); + ok(rc || + broken(!rc), /* win98 */ + "dw=0x%x\n", dw); + rc = CheckDPA(dpa3, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + + pDPA_Destroy(dpa); + pDPA_Destroy(dpa2); + pDPA_Destroy(dpa3); +} + +static void test_DPA_EnumCallback(void) +{ + HDPA dpa; + BOOL rc; + DWORD dw; + INT i, ret; + + if(!pDPA_EnumCallback) + { + win_skip("DPA_EnumCallback() not available\n"); + return; + } + + dpa = pDPA_Create(0); + + for (i = 0; i < 6; i++) + { + ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); + ok(ret == i, "ret=%d\n", ret); + } + + rc = CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + + nEnum = 0; + /* test callback sets first 3 items to 7 */ + pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa); + rc = CheckDPA(dpa, 0x777456, &dw); + ok(rc, "dw=0x%x\n", dw); + ok(nEnum == 3, "nEnum=%d\n", nEnum); + + pDPA_Destroy(dpa); +} + +static void test_DPA_DestroyCallback(void) +{ + HDPA dpa; + INT i, ret; + + if(!pDPA_DestroyCallback) + { + win_skip("DPA_DestroyCallback() not available\n"); + return; + } + + dpa = pDPA_Create(0); + + for (i = 0; i < 3; i++) + { + ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); + ok(ret == i, "ret=%d\n", ret); + } + + nEnum = 0; + pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa); + ok(nEnum == 3, "nEnum=%d\n", nEnum); +} + +static void test_DPA_LoadStream(void) +{ + static const WCHAR szStg[] = { 'S','t','g',0 }; + IStorage* pStg = NULL; + IStream* pStm = NULL; + LARGE_INTEGER li; + ULARGE_INTEGER uli; + DWORD dwMode; + HRESULT hRes; + STREAMDATA header; + ULONG written, ret; + HDPA dpa; + + if(!pDPA_LoadStream) + { + win_skip("DPA_LoadStream() not available. Skipping stream tests.\n"); + return; + } hRes = CoInitialize(NULL); - if(hRes == S_OK) + if (hRes != S_OK) { - static const WCHAR szStg[] = { 'S','t','g',0 }; - IStorage* pStg = NULL; - IStream* pStm = NULL; - LARGE_INTEGER liZero; - DWORD dwMode; - liZero.QuadPart = 0; - - dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE; - hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); - - hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); - - hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef); - todo_wine ok(hRes == S_OK, "hRes=0x%x\n", hRes); - pDPA_Destroy(dpa); - - hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL); - ok(hRes == S_OK, "hRes=0x%x\n", hRes); - hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef); - todo_wine - { - ok(hRes == S_OK, "hRes=0x%x\n", hRes); - rc=CheckDPA(dpa, 0x123456, &dw); - ok(rc, "dw=0x%x\n", dw); - } - - ret = IStream_Release(pStm); - ok(!ret, "ret=%d\n", ret); - - ret = IStorage_Release(pStg); - ok(!ret, "ret=%d\n", ret); - - CoUninitialize(); + ok(0, "hResult: %d\n", hRes); + return; } - else ok(0, "hResult: %d\n", hRes); -skip_stream_tests: + dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE; + hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg); + expect(S_OK, hRes); + + hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); + expect(S_OK, hRes); + + /* write less than header size */ + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + memset(&header, 0, sizeof(header)); + written = 0; + uli.QuadPart = sizeof(header)-1; + hRes = IStream_SetSize(pStm, uli); + expect(S_OK, hRes); + hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written); + expect(S_OK, hRes); + written -= sizeof(header)-1; + expect(0, written); + + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL); + expect(E_FAIL, hRes); + + /* check stream position after header read failed */ + li.QuadPart = 0; + uli.QuadPart = 1; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli); + expect(S_OK, hRes); + ok(uli.QuadPart == 0, "Expected to position reset\n"); + + /* write valid header for empty DPA */ + header.dwSize = sizeof(header); + header.dwData2 = 1; + header.dwItems = 0; + written = 0; + + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + uli.QuadPart = sizeof(header); + hRes = IStream_SetSize(pStm, uli); + expect(S_OK, hRes); + + hRes = IStream_Write(pStm, &header, sizeof(header), &written); + expect(S_OK, hRes); + written -= sizeof(header); + expect(0, written); + + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + dpa = NULL; + hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL); + expect(S_OK, hRes); + DPA_Destroy(dpa); + + /* try with altered dwData2 field */ + header.dwSize = sizeof(header); + header.dwData2 = 2; + header.dwItems = 0; + + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + hRes = IStream_Write(pStm, &header, sizeof(header), &written); + expect(S_OK, hRes); + written -= sizeof(header); + expect(0, written); + + li.QuadPart = 0; + hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef); + expect(E_FAIL, hRes); + + ret = IStream_Release(pStm); + ok(!ret, "ret=%d\n", ret); + + ret = IStorage_Release(pStg); + ok(!ret, "ret=%d\n", ret); + + CoUninitialize(); +} + +static void test_DPA_SaveStream(void) +{ + HDPA dpa; + static const WCHAR szStg[] = { 'S','t','g',0 }; + IStorage* pStg = NULL; + IStream* pStm = NULL; + DWORD dwMode, dw; + HRESULT hRes; + ULONG ret; + INT i; + BOOL rc; + LARGE_INTEGER liZero; + + if(!pDPA_SaveStream) + { + win_skip("DPA_SaveStream() not available. Skipping stream tests.\n"); + return; + } + + hRes = CoInitialize(NULL); + if (hRes != S_OK) + { + ok(0, "hResult: %d\n", hRes); + return; + } + + dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE; + hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg); + expect(S_OK, hRes); + + hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); + expect(S_OK, hRes); + + dpa = pDPA_Create(0); + + /* simple parameter check */ + hRes = pDPA_SaveStream(dpa, NULL, pStm, NULL); + ok(hRes == E_INVALIDARG || + broken(hRes == S_OK) /* XP and below */, "Wrong result, %d\n", hRes); +if (0) { + /* crashes on XP */ + hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL); + expect(E_INVALIDARG, hRes); + + hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL); + expect(E_INVALIDARG, hRes); +} + + /* saving/loading */ + for (i = 0; i < 6; i++) + { + ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1)); + ok(ret == i, "ret=%d\n", ret); + } + + liZero.QuadPart = 0; + hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + + hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef); + expect(S_OK, hRes); pDPA_Destroy(dpa); + + liZero.QuadPart = 0; + hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL); + expect(S_OK, hRes); + hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef); + expect(S_OK, hRes); + rc = CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + pDPA_Destroy(dpa); + + ret = IStream_Release(pStm); + ok(!ret, "ret=%d\n", ret); + + ret = IStorage_Release(pStg); + ok(!ret, "ret=%d\n", ret); + + CoUninitialize(); } START_TEST(dpa) @@ -450,8 +746,16 @@ START_TEST(dpa) hcomctl32 = GetModuleHandleA("comctl32.dll"); - if(InitFunctionPtrs(hcomctl32)) - test_dpa(); - else + if(!InitFunctionPtrs(hcomctl32)) + { win_skip("Needed functions are not available\n"); + return; + } + + test_dpa(); + test_DPA_Merge(); + test_DPA_EnumCallback(); + test_DPA_DestroyCallback(); + test_DPA_LoadStream(); + test_DPA_SaveStream(); } diff --git a/rostests/winetests/comctl32/header.c b/rostests/winetests/comctl32/header.c index 76612530c98..d9b4a7329ff 100644 --- a/rostests/winetests/comctl32/header.c +++ b/rostests/winetests/comctl32/header.c @@ -24,6 +24,7 @@ #include #include "wine/test.h" +#include "v6util.h" #include "msg.h" typedef struct tagEXPECTEDNOTIFY @@ -121,7 +122,6 @@ static const struct message deleteItem_getItemCount_seq[] = { }; static const struct message orderArray_seq[] = { - { HDM_GETITEMCOUNT, sent }, { HDM_SETORDERARRAY, sent|wparam, 2 }, { HDM_GETORDERARRAY, sent|wparam, 2 }, { 0 } @@ -244,7 +244,7 @@ static LONG addItem(HWND hdex, int idx, LPSTR text) hdItem.cxy = 100; hdItem.pszText = text; hdItem.cchTextMax = 0; - return (LONG)SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)idx, (LPARAM)&hdItem); + return SendMessage(hdex, HDM_INSERTITEMA, idx, (LPARAM)&hdItem); } static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies) @@ -259,7 +259,7 @@ static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies) expect_notify(HDN_ITEMCHANGINGA, FALSE, &hdexItem); expect_notify(HDN_ITEMCHANGEDA, FALSE, &hdexItem); } - ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem); + ret = SendMessage(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem); if (fCheckNotifies) ok(notifies_received(), "setItem(): not all expected notifies were received\n"); return ret; @@ -279,19 +279,19 @@ static LONG setItemUnicodeNotify(HWND hdex, int idx, LPSTR text, LPWSTR wText) expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify); expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify); - ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem); + ret = SendMessage(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem); ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n"); return ret; } static LONG delItem(HWND hdex, int idx) { - return (LONG)SendMessage(hdex, HDM_DELETEITEM, (WPARAM)idx, 0); + return SendMessage(hdex, HDM_DELETEITEM, idx, 0); } static LONG getItemCount(HWND hdex) { - return (LONG)SendMessage(hdex, HDM_GETITEMCOUNT, 0, 0); + return SendMessage(hdex, HDM_GETITEMCOUNT, 0, 0); } static LONG getItem(HWND hdex, int idx, LPSTR textBuffer) @@ -300,7 +300,7 @@ static LONG getItem(HWND hdex, int idx, LPSTR textBuffer) hdItem.mask = HDI_TEXT; hdItem.pszText = textBuffer; hdItem.cchTextMax = MAX_CHARS; - return (LONG)SendMessage(hdex, HDM_GETITEMA, (WPARAM)idx, (LPARAM)&hdItem); + return SendMessage(hdex, HDM_GETITEMA, idx, (LPARAM)&hdItem); } static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead) @@ -396,14 +396,9 @@ static WCHAR pszUniTestW[] = {'T','S','T',0}; ok(res == i, "Got Item Count as %d\n", res);\ } -struct subclass_info -{ - WNDPROC oldproc; -}; - static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -417,7 +412,7 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara add_message(sequences, HEADER_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; @@ -487,7 +482,7 @@ static HWND create_custom_parent_window(void) static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems) { - struct subclass_info *info; + WNDPROC oldproc; HWND childHandle; HDLAYOUT hlayout; RECT rectwin; @@ -505,9 +500,6 @@ static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems) flush_sequences(sequences, NUM_MSG_SEQUENCES); - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; childHandle = CreateWindowEx(0, WC_HEADER, NULL, WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ, @@ -534,9 +526,9 @@ static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems) SetWindowPos(childHandle, winpos.hwndInsertAfter, winpos.x, winpos.y, winpos.cx, winpos.cy, 0); - info->oldproc = (WNDPROC)SetWindowLongPtrA(childHandle, GWLP_WNDPROC, - (LONG_PTR)header_subclass_proc); - SetWindowLongPtrA(childHandle, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(childHandle, GWLP_WNDPROC, + (LONG_PTR)header_subclass_proc); + SetWindowLongPtrA(childHandle, GWLP_USERDATA, (LONG_PTR)oldproc); return childHandle; } @@ -756,10 +748,10 @@ static void test_header_control (void) TEST_GET_ITEM(i, 4); TEST_GET_ITEMCOUNT(6); } - - SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, 0); + + SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, TRUE, 0); setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW); - SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, (LPARAM)NF_REQUERY); + SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, NF_REQUERY); setItem(hWndHeader, 3, str_items[4], TRUE); dont_expect_notify(HDN_GETDISPINFOA); @@ -820,10 +812,8 @@ static void test_hdm_getitemrect(HWND hParent) expect(80, rect.left); expect(0, rect.top); expect(160, rect.right); - todo_wine - { - expect(g_customheight, rect.bottom); - } + expect(g_customheight, rect.bottom); + retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect); ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal); @@ -832,10 +822,8 @@ static void test_hdm_getitemrect(HWND hParent) expect(0, rect.top); expect(80, rect.right); - todo_wine - { - expect(g_customheight, rect.bottom); - } + expect(g_customheight, rect.bottom); + retVal = SendMessage(hChild, HDM_GETITEMRECT, 10, (LPARAM) &rect); ok(retVal == 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal); @@ -907,30 +895,25 @@ static void test_hdm_hittest(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); - todo_wine - { - expect(0, retVal); - expect(0, hdHitTestInfo.iItem); - } + expect(0, retVal); + expect(0, hdHitTestInfo.iItem); + expect(HHT_ONDIVIDER, hdHitTestInfo.flags); pt.x = secondItemRightBoundary - 1; pt.y = bottomBoundary - 1; hdHitTestInfo.pt = pt; retVal = SendMessage(hChild, HDM_HITTEST, 1, (LPARAM) &hdHitTestInfo); - todo_wine - { - expect(1, retVal); - } + expect(1, retVal); expect(1, hdHitTestInfo.iItem); + expect(HHT_ONDIVIDER, hdHitTestInfo.flags); pt.x = secondItemRightBoundary; pt.y = bottomBoundary + 1; hdHitTestInfo.pt = pt; - todo_wine - { - retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); - expect(-1, retVal); - } + retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); + expect(-1, retVal); + expect(-1, hdHitTestInfo.iItem); + expect(HHT_BELOW, hdHitTestInfo.flags); ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE); @@ -951,11 +934,9 @@ static void test_hdm_sethotdivider(HWND hParent) "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); - todo_wine - { - retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, 0X00050005); - expect(0, retVal); - } + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, MAKELPARAM(5, 5)); + expect(0, retVal); + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100); expect(100, retVal); retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 1); @@ -973,7 +954,7 @@ static void test_hdm_sethotdivider(HWND hParent) static void test_hdm_imageMessages(HWND hParent) { HIMAGELIST hImageList = ImageList_Create (4, 4, 0, 1, 0); - HIMAGELIST hImageListRetVal; + HIMAGELIST hIml; HWND hChild; flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -983,14 +964,15 @@ static void test_hdm_imageMessages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); - hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList); - ok(hImageListRetVal == NULL, "Expected NULL, got %p\n", hImageListRetVal); + hIml = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList); + ok(hIml == NULL, "Expected NULL, got %p\n", hIml); - hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0); - ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal); + hIml = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0); + ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml); - hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0); - ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal); + hIml = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0); + ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml); + ImageList_Destroy(hIml); ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE); @@ -1025,9 +1007,16 @@ static void test_hdm_filterMessages(HWND hParent) todo_wine { retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1); - expect(1, retVal); + if (retVal == 0) + win_skip("HDM_CLEARFILTER needs 5.80\n"); + else + expect(1, retVal); + retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0); - expect(1, retVal); + if (retVal == 0) + win_skip("HDM_EDITFILTER needs 5.80\n"); + else + expect(1, retVal); } if (winetest_interactive) ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive, @@ -1076,7 +1065,10 @@ static void test_hdm_bitmapmarginMessages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0); - expect(6, retVal); + if (retVal == 0) + win_skip("HDM_GETBITMAPMARGIN needs 5.80\n"); + else + expect(6, retVal); ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq, "bitmapmarginMessages sequence testing", FALSE); @@ -1085,7 +1077,6 @@ static void test_hdm_bitmapmarginMessages(HWND hParent) static void test_hdm_index_messages(HWND hParent) { - HWND hChild; int retVal; int loopcnt; @@ -1098,6 +1089,7 @@ static void test_hdm_index_messages(HWND hParent) static char thirdHeaderItem[] = "Type"; static char fourthHeaderItem[] = "Date Modified"; static char *items[] = {firstHeaderItem, secondHeaderItem, thirdHeaderItem, fourthHeaderItem}; + RECT rect; HDITEM hdItem; hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT; hdItem.fmt = HDF_LEFT; @@ -1125,17 +1117,17 @@ static void test_hdm_index_messages(HWND hParent) retVal = SendMessage(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem); ok(retVal == TRUE, "Deleting item 3 should return TRUE, got %d\n", retVal); - retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); + retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0); ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal); retVal = SendMessage(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem); ok(retVal == FALSE, "Deleting already-deleted item should return FALSE, got %d\n", retVal); - retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); + retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0); ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal); retVal = SendMessage(hChild, HDM_DELETEITEM, 2, (LPARAM) &hdItem); ok(retVal == TRUE, "Deleting item 2 should return TRUE, got %d\n", retVal); - retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); + retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0); ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal); ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq, @@ -1156,9 +1148,19 @@ static void test_hdm_index_messages(HWND hParent) expect(0, strcmpResult); expect(80, hdItem.cxy); + iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0); + + /* item should be updated just after accepting new array */ + ShowWindow(hChild, SW_HIDE); + retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray); + expect(TRUE, retVal); + rect.left = 0; + retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect); + expect(TRUE, retVal); + ok(rect.left != 0, "Expected updated rectangle\n"); + flush_sequences(sequences, NUM_MSG_SEQUENCES); - iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray); ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal); @@ -1187,12 +1189,156 @@ static void test_hdm_index_messages(HWND hParent) DestroyWindow(hChild); } +static void test_hdf_fixedwidth(HWND hParent) +{ + HWND hChild; + HDITEM hdItem; + DWORD ret; + RECT rect; + HDHITTESTINFO ht; + + hChild = create_custom_header_control(hParent, FALSE); + + hdItem.mask = HDI_WIDTH | HDI_FORMAT; + hdItem.fmt = HDF_FIXEDWIDTH; + hdItem.cxy = 80; + + ret = SendMessage(hChild, HDM_INSERTITEM, 0, (LPARAM)&hdItem); + expect(0, ret); + + /* try to change width */ + rect.right = rect.bottom = 0; + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + ok(rect.right != 0, "Expected not zero width\n"); + ok(rect.bottom != 0, "Expected not zero height\n"); + + SendMessage(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2)); + SendMessage(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2)); + SendMessage(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2)); + + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + + if (hdItem.cxy != rect.right) + { + win_skip("HDF_FIXEDWIDTH format not supported\n"); + DestroyWindow(hChild); + return; + } + + /* try to adjust with message */ + hdItem.mask = HDI_WIDTH; + hdItem.cxy = 90; + + ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem); + expect(TRUE, ret); + + rect.right = 0; + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + expect(90, rect.right); + + /* hittesting doesn't report ondivider flag for HDF_FIXEDWIDTH */ + ht.pt.x = rect.right - 1; + ht.pt.y = rect.bottom / 2; + SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht); + expect(HHT_ONHEADER, ht.flags); + + /* try to adjust with message */ + hdItem.mask = HDI_FORMAT; + hdItem.fmt = 0; + + ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem); + expect(TRUE, ret); + + ht.pt.x = 90; + ht.pt.y = rect.bottom / 2; + SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht); + expect(HHT_ONDIVIDER, ht.flags); + + DestroyWindow(hChild); +} + +static void test_hds_nosizing(HWND hParent) +{ + HWND hChild; + HDITEM hdItem; + DWORD ret; + RECT rect; + HDHITTESTINFO ht; + + hChild = create_custom_header_control(hParent, FALSE); + + memset(&hdItem, 0, sizeof(hdItem)); + hdItem.mask = HDI_WIDTH; + hdItem.cxy = 80; + + ret = SendMessage(hChild, HDM_INSERTITEM, 0, (LPARAM)&hdItem); + expect(0, ret); + + /* HDS_NOSIZING only blocks hittesting */ + ret = GetWindowLong(hChild, GWL_STYLE); + SetWindowLong(hChild, GWL_STYLE, ret | HDS_NOSIZING); + + /* try to change width with mouse gestures */ + rect.right = rect.bottom = 0; + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + ok(rect.right != 0, "Expected not zero width\n"); + ok(rect.bottom != 0, "Expected not zero height\n"); + + SendMessage(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2)); + SendMessage(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2)); + SendMessage(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2)); + + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + + if (hdItem.cxy != rect.right) + { + win_skip("HDS_NOSIZING style not supported\n"); + DestroyWindow(hChild); + return; + } + + /* this style doesn't set HDF_FIXEDWIDTH for items */ + hdItem.mask = HDI_FORMAT; + ret = SendMessage(hChild, HDM_GETITEM, 0, (LPARAM)&hdItem); + expect(TRUE, ret); + ok(!(hdItem.fmt & HDF_FIXEDWIDTH), "Unexpected HDF_FIXEDWIDTH\n"); + + /* try to adjust with message */ + hdItem.mask = HDI_WIDTH; + hdItem.cxy = 90; + + ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem); + expect(TRUE, ret); + + rect.right = 0; + SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect); + expect(90, rect.right); + + /* hittesting doesn't report ondivider flags for HDS_NOSIZING */ + ht.pt.x = rect.right - 1; + ht.pt.y = rect.bottom / 2; + SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht); + expect(HHT_ONHEADER, ht.flags); + + /* try to adjust with message */ + ret = GetWindowLong(hChild, GWL_STYLE); + SetWindowLong(hChild, GWL_STYLE, ret & ~HDS_NOSIZING); + + ht.pt.x = 90; + ht.pt.y = rect.bottom / 2; + SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht); + expect(HHT_ONDIVIDER, ht.flags); + + DestroyWindow(hChild); +} + #define TEST_NMCUSTOMDRAW(draw_stage, item_spec, lparam, _left, _top, _right, _bottom) \ ok(nm->dwDrawStage == draw_stage, "Invalid dwDrawStage %d vs %d\n", draw_stage, nm->dwDrawStage); \ if (item_spec != -1) \ ok(nm->dwItemSpec == item_spec, "Invalid dwItemSpec %d vs %ld\n", item_spec, nm->dwItemSpec); \ ok(nm->lItemlParam == lparam, "Invalid lItemlParam %d vs %ld\n", lparam, nm->lItemlParam); \ - ok(nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right, \ + ok((nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right) || \ + broken(draw_stage != CDDS_ITEMPREPAINT), /* comctl32 < 5.80 */ \ "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", _left, _top, _right, _bottom, \ nm->rc.left, nm->rc.top, nm->rc.right, nm->rc.bottom); @@ -1545,15 +1691,139 @@ static int init(void) return 1; } +/* maximum 8 items allowed */ +static void check_orderarray(HWND hwnd, DWORD start, DWORD set, DWORD expected, + int todo, int line) +{ + int count, i; + INT order[8]; + DWORD ret, array = 0; + + count = SendMessage(hwnd, HDM_GETITEMCOUNT, 0, 0); + + /* initial order */ + for(i = 1; i<=count; i++) + order[i-1] = start>>(4*(count-i)) & 0xf; + + ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret); + + /* new order */ + for(i = 1; i<=count; i++) + order[i-1] = set>>(4*(count-i)) & 0xf; + ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret); + + /* check actual order */ + ret = SendMessage(hwnd, HDM_GETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_GETORDERARAY to succeed, got %d\n", ret); + for(i = 1; i<=count; i++) + array |= order[i-1]<<(4*(count-i)); + + if (todo) { + todo_wine + ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array); + } + else + ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array); +} + +static void test_hdm_orderarray(void) +{ + HWND hwnd; + INT order[5]; + DWORD ret; + + hwnd = create_header_control(); + + /* three items */ + addItem(hwnd, 0, NULL); + addItem(hwnd, 1, NULL); + addItem(hwnd, 2, NULL); + + ret = SendMessage(hwnd, HDM_GETORDERARRAY, 3, (LPARAM)order); + if (!ret) + { + win_skip("HDM_GETORDERARRAY not implemented.\n"); + DestroyWindow(hwnd); + return; + } + + expect(0, order[0]); + expect(1, order[1]); + expect(2, order[2]); + +if (0) +{ + /* null pointer, crashes native */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 3, 0); + expect(FALSE, ret); +} + /* count out of limits */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 5, (LPARAM)order); + expect(FALSE, ret); + /* count out of limits */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 2, (LPARAM)order); + expect(FALSE, ret); + + /* try with out of range item index */ + /* (0,1,2)->(1,0,3) => (1,0,2) */ + check_orderarray(hwnd, 0x120, 0x103, 0x102, FALSE, __LINE__); + /* (1,0,2)->(3,0,1) => (0,2,1) */ + check_orderarray(hwnd, 0x102, 0x301, 0x021, TRUE, __LINE__); + /* (0,2,1)->(2,3,1) => (2,0,1) */ + check_orderarray(hwnd, 0x021, 0x231, 0x201, FALSE, __LINE__); + + /* (0,1,2)->(0,2,2) => (0,1,2) */ + check_orderarray(hwnd, 0x012, 0x022, 0x012, FALSE, __LINE__); + + addItem(hwnd, 3, NULL); + + /* (0,1,2,3)->(0,1,2,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x0122, 0x0132, FALSE, __LINE__); + /* (0,1,2,3)->(0,1,3,3) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0133, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(0,4,2,3) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0423, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(4,0,1,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4012, 0x0132, TRUE, __LINE__); + /* (0,1,3,2)->(4,0,1,4) => (0,3,1,2) */ + check_orderarray(hwnd, 0x0132, 0x4014, 0x0312, TRUE, __LINE__); + /* (0,1,2,3)->(4,1,0,2) => (1,0,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4102, 0x1032, TRUE, __LINE__); + /* (0,1,2,3)->(0,1,4,2) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0142, 0x0132, FALSE, __LINE__); + /* (0,1,2,3)->(4,4,4,4) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x4444, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(4,4,1,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4412, 0x0132, TRUE, __LINE__); + /* (0,1,2,3)->(4,4,4,1) => (0,2,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4441, 0x0231, TRUE, __LINE__); + /* (0,1,2,3)->(1,4,4,4) => (1,0,2,3) */ + check_orderarray(hwnd, 0x0123, 0x1444, 0x1023, FALSE, __LINE__); + /* (0,1,2,3)->(4,2,4,1) => (0,2,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4241, 0x0231, FALSE, __LINE__); + /* (0,1,2,3)->(4,2,0,1) => (2,0,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4201, 0x2031, TRUE, __LINE__); + /* (3,2,1,0)->(4,2,0,1) => (3,2,0,1) */ + check_orderarray(hwnd, 0x3210, 0x4201, 0x3201, FALSE, __LINE__); + + DestroyWindow(hwnd); +} + START_TEST(header) { HWND parent_hwnd; + ULONG_PTR ctx_cookie; + HANDLE hCtx; + HWND hwnd; if (!init()) return; test_header_control(); test_header_order(); + test_hdm_orderarray(); test_customdraw(); DestroyWindow(hHeaderParentWnd); @@ -1573,6 +1843,33 @@ START_TEST(header) test_hdm_unicodeformatMessages(parent_hwnd); test_hdm_bitmapmarginMessages(parent_hwnd); - DestroyWindow(parent_hwnd); + if (!load_v6_module(&ctx_cookie, &hCtx)) + { + DestroyWindow(parent_hwnd); + return; + } + /* this is a XP SP3 failure workaround */ + hwnd = CreateWindowExA(0, WC_HEADER, NULL, + WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ, + 0, 0, 100, 100, + parent_hwnd, NULL, GetModuleHandleA(NULL), NULL); + + if (!IsWindow(hwnd)) + { + win_skip("FIXME: failed to create Header window.\n"); + unload_v6_module(ctx_cookie, hCtx); + DestroyWindow(parent_hwnd); + return; + } + else + DestroyWindow(hwnd); + + /* comctl32 version 6 tests start here */ + test_hdf_fixedwidth(parent_hwnd); + test_hds_nosizing(parent_hwnd); + + unload_v6_module(ctx_cookie, hCtx); + + DestroyWindow(parent_hwnd); } diff --git a/rostests/winetests/comctl32/imagelist.c b/rostests/winetests/comctl32/imagelist.c index 3fe249f3ad5..cf749c82732 100644 --- a/rostests/winetests/comctl32/imagelist.c +++ b/rostests/winetests/comctl32/imagelist.c @@ -4,6 +4,7 @@ * Copyright 2004 Michael Stefaniuc * Copyright 2002 Mike McCormack for CodeWeavers * Copyright 2007 Dmitry Timoshkov + * Copyright 2009 Owen Rudge for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,8 +34,12 @@ #include "winuser.h" #include "objbase.h" #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */ +#include "initguid.h" +#include "commoncontrols.h" +#include "shellapi.h" #include "wine/test.h" +#include "v6util.h" #undef VISIBLE @@ -65,10 +70,14 @@ typedef struct _ILHEAD } ILHEAD; #include "poppack.h" +static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int); +static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP); static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*); static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT); +static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *, + REFIID,void **); +static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **); -static HDC desktopDC; static HINSTANCE hinst; /* These macros build cursor/bitmap data in 4x4 pixel blocks */ @@ -327,7 +336,7 @@ static BOOL DoTest1(void) HICON hicon3 ; /* create an imagelist to play with */ - himl = ImageList_Create(84,84,0x10,0,3); + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -393,7 +402,7 @@ static BOOL DoTest2(void) HICON hicon3 ; /* create an imagelist to play with */ - himl = ImageList_Create(84,84,0x10,0,3); + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -442,7 +451,7 @@ static BOOL DoTest3(void) ok(hdc!=NULL, "couldn't get DC\n"); /* create an imagelist to play with */ - himl = ImageList_Create(48,48,0x10,0,3); + himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -824,7 +833,7 @@ static void check_bitmap_data(const char *bm_data, ULONG bm_data_size, static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max) { - ILHEAD *ilh = (ILHEAD *)ilh_data; + const ILHEAD *ilh = (const ILHEAD *)ilh_data; ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC); ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion); @@ -981,13 +990,639 @@ static void test_imagelist_storage(void) iml_clear_stream_data(); } +static void test_shell_imagelist(void) +{ + BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**); + IImageList *iml = NULL; + HMODULE hShell32; + HRESULT hr; + int out = 0; + RECT rect; + int cx, cy; + + /* Try to load function from shell32 */ + hShell32 = LoadLibrary("shell32.dll"); + pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727); + + if (!pSHGetImageList) + { + win_skip("SHGetImageList not available, skipping test\n"); + return; + } + + /* Get system image list */ + hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml); + + ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr); + + if (hr != S_OK) + return; + + IImageList_GetImageCount(iml, &out); + ok(out > 0, "IImageList_GetImageCount returned out <= 0\n"); + + /* Fetch the small icon size */ + cx = GetSystemMetrics(SM_CXSMICON); + cy = GetSystemMetrics(SM_CYSMICON); + + /* Check icon size matches */ + IImageList_GetImageRect(iml, 0, &rect); + ok(((rect.right == cx) && (rect.bottom == cy)), + "IImageList_GetImageRect returned r:%d,b:%d\n", + rect.right, rect.bottom); + + IImageList_Release(iml); + FreeLibrary(hShell32); +} + +static HBITMAP create_test_bitmap(HDC hdc, int bpp, UINT32 pixel1, UINT32 pixel2) +{ + HBITMAP hBitmap; + UINT32 *buffer = NULL; + BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, bpp, BI_RGB, + 0, 0, 0, 0, 0}}; + + hBitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0); + ok(hBitmap != NULL && buffer != NULL, "CreateDIBSection failed.\n"); + + if(!hBitmap || !buffer) + { + DeleteObject(hBitmap); + return NULL; + } + + buffer[0] = pixel1; + buffer[1] = pixel2; + + return hBitmap; +} + +static BOOL colour_match(UINT32 x, UINT32 y) +{ + const INT32 tolerance = 8; + + const INT32 dr = abs((INT32)(x & 0x000000FF) - (INT32)(y & 0x000000FF)); + const INT32 dg = abs((INT32)((x & 0x0000FF00) >> 8) - (INT32)((y & 0x0000FF00) >> 8)); + const INT32 db = abs((INT32)((x & 0x00FF0000) >> 16) - (INT32)((y & 0x00FF0000) >> 16)); + + return (dr <= tolerance && dg <= tolerance && db <= tolerance); +} + +static void check_ImageList_DrawIndirect(IMAGELISTDRAWPARAMS *ildp, UINT32 *bits, + UINT32 expected, int line) +{ + bits[0] = 0x00FFFFFF; + pImageList_DrawIndirect(ildp); + ok(colour_match(bits[0], expected), + "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n", + bits[0] & 0x00FFFFFF, expected, line); +} + + +static void check_ImageList_DrawIndirect_fStyle(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, + UINT fStyle, UINT32 expected, int line) +{ + IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc, + 0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, ILS_NORMAL, 0, 0x00000000}; + check_ImageList_DrawIndirect(&ildp, bits, expected, line); +} + +static void check_ImageList_DrawIndirect_ILD_ROP(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, + DWORD dwRop, UINT32 expected, int line) +{ + IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc, + 0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, ILD_IMAGE | ILD_ROP, dwRop, ILS_NORMAL, 0, 0x00000000}; + check_ImageList_DrawIndirect(&ildp, bits, expected, line); +} + +static void check_ImageList_DrawIndirect_fState(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, UINT fStyle, + UINT fState, DWORD Frame, UINT32 expected, int line) +{ + IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc, + 0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000}; + check_ImageList_DrawIndirect(&ildp, bits, expected, line); +} + +static void check_ImageList_DrawIndirect_broken(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, + UINT fStyle, UINT fState, DWORD Frame, UINT32 expected, + UINT32 broken_expected, int line) +{ + IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc, + 0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000}; + bits[0] = 0x00FFFFFF; + pImageList_DrawIndirect(&ildp); + ok(colour_match(bits[0], expected) || + broken(colour_match(bits[0], broken_expected)), + "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n", + bits[0] & 0x00FFFFFF, expected, line); +} + +static void test_ImageList_DrawIndirect(void) +{ + HIMAGELIST himl = NULL; + int ret; + HDC hdcDst = NULL; + HBITMAP hbmOld = NULL, hbmDst = NULL; + HBITMAP hbmMask = NULL, hbmInverseMask = NULL; + HBITMAP hbmImage = NULL, hbmAlphaImage = NULL, hbmTransparentImage = NULL; + int iImage = -1, iAlphaImage = -1, iTransparentImage = -1; + UINT32 *bits = 0; + UINT32 maskBits = 0x00000000, inverseMaskBits = 0xFFFFFFFF; + + BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB, + 0, 0, 0, 0, 0}}; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + hbmMask = CreateBitmap(2, 1, 1, 1, &maskBits); + ok(hbmMask != 0, "CreateBitmap failed\n"); + if(!hbmMask) goto cleanup; + + hbmInverseMask = CreateBitmap(2, 1, 1, 1, &inverseMaskBits); + ok(hbmInverseMask != 0, "CreateBitmap failed\n"); + if(!hbmInverseMask) goto cleanup; + + himl = pImageList_Create(2, 1, ILC_COLOR32, 0, 1); + ok(himl != 0, "ImageList_Create failed\n"); + if(!himl) goto cleanup; + + /* Add a no-alpha image */ + hbmImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x00ABCDEF); + if(!hbmImage) goto cleanup; + + iImage = pImageList_Add(himl, hbmImage, hbmMask); + ok(iImage != -1, "ImageList_Add failed\n"); + if(iImage == -1) goto cleanup; + + /* Add an alpha image */ + hbmAlphaImage = create_test_bitmap(hdcDst, 32, 0x89ABCDEF, 0x89ABCDEF); + if(!hbmAlphaImage) goto cleanup; + + iAlphaImage = pImageList_Add(himl, hbmAlphaImage, hbmMask); + ok(iAlphaImage != -1, "ImageList_Add failed\n"); + if(iAlphaImage == -1) goto cleanup; + + /* Add a transparent alpha image */ + hbmTransparentImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x89ABCDEF); + if(!hbmTransparentImage) goto cleanup; + + iTransparentImage = pImageList_Add(himl, hbmTransparentImage, hbmMask); + ok(iTransparentImage != -1, "ImageList_Add failed\n"); + if(iTransparentImage == -1) goto cleanup; + + /* 32-bit Tests */ + bitmapInfo.bmiHeader.biBitCount = 32; + hbmDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (hbmDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!hbmDst || !bits) + goto cleanup; + hbmOld = SelectObject(hdcDst, hbmDst); + + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_NORMAL, 0x00ABCDEF, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_TRANSPARENT, 0x00ABCDEF, __LINE__); + todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x00D4D9DD, __LINE__); + todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, 0x00B4BDC4, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_MASK, 0x00ABCDEF, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_IMAGE, 0x00ABCDEF, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_PRESERVEALPHA, 0x00ABCDEF, __LINE__); + + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, 0x00D3E5F7, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_TRANSPARENT, 0x00D3E5F7, __LINE__); + todo_wine + { + check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x009DA8B1, __LINE__); + check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, 0x008C99A3, __LINE__); + + } + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_MASK, 0x00D3E5F7, __LINE__); + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_IMAGE, 0x00D3E5F7, __LINE__); + todo_wine check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_PRESERVEALPHA, 0x005D6F81, __LINE__); + + check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iTransparentImage, ILD_NORMAL, 0x00FFFFFF, __LINE__); + + check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCCOPY, 0x00ABCDEF, __LINE__); + check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCINVERT, 0x00543210, __LINE__); + + /* ILD_ROP is ignored when the image has an alpha channel */ + check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCCOPY, 0x00D3E5F7, __LINE__); + check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCINVERT, 0x00D3E5F7, __LINE__); + + todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00CCCCCC, __LINE__); + todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00AFAFAF, 0x00F0F0F0, __LINE__); + + check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__); + check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__); + + check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__); + check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__); + todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__); + +cleanup: + + if(hbmOld) + SelectObject(hdcDst, hbmOld); + if(hbmDst) + DeleteObject(hbmDst); + + if(hdcDst) + DeleteDC(hdcDst); + + if(hbmMask) + DeleteObject(hbmMask); + if(hbmInverseMask) + DeleteObject(hbmInverseMask); + + if(hbmImage) + DeleteObject(hbmImage); + if(hbmAlphaImage) + DeleteObject(hbmAlphaImage); + if(hbmTransparentImage) + DeleteObject(hbmTransparentImage); + + if(himl) + { + ret = ImageList_Destroy(himl); + ok(ret, "ImageList_Destroy failed\n"); + } +} + +static void test_iimagelist(void) +{ + IImageList *imgl; + HIMAGELIST himl; + HRESULT hr; + ULONG ret; + + if (!pHIMAGELIST_QueryInterface) + { + win_skip("XP imagelist functions not available\n"); + return; + } + + /* test reference counting on destruction */ + imgl = (IImageList*)createImageList(32, 32); + ret = IUnknown_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); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + imgl = (IImageList*)createImageList(32, 32); + ret = IUnknown_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); + ret = IImageList_Release(imgl); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + if (!pImageList_CoCreateInstance) + { + win_skip("Vista imagelist functions not available\n"); + return; + } + + hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList, (void **) &imgl); + ok(SUCCEEDED(hr), "ImageList_CoCreateInstance failed, hr=%x\n", hr); + + if (hr == S_OK) + IImageList_Release(imgl); + + himl = createImageList(32, 32); + + if (!himl) + return; + + hr = (pHIMAGELIST_QueryInterface)(himl, &IID_IImageList, (void **) &imgl); + ok(SUCCEEDED(hr), "HIMAGELIST_QueryInterface failed, hr=%x\n", hr); + + if (hr == S_OK) + IImageList_Release(imgl); + + ImageList_Destroy(himl); +} + +static void testHotspot_v6(void) +{ + struct hotspot { + int dx; + int dy; + }; + +#define SIZEX1 47 +#define SIZEY1 31 +#define SIZEX2 11 +#define SIZEY2 17 +#define HOTSPOTS_MAX 4 /* Number of entries in hotspots */ + static const struct hotspot hotspots[HOTSPOTS_MAX] = { + { 10, 7 }, + { SIZEX1, SIZEY1 }, + { -9, -8 }, + { -7, 35 } + }; + int i, j; + HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1); + HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2); + IImageList *imgl1, *imgl2; + HRESULT hr; + + /* cast to IImageList */ + imgl1 = (IImageList *) himl1; + imgl2 = (IImageList *) himl2; + + for (i = 0; i < HOTSPOTS_MAX; i++) { + for (j = 0; j < HOTSPOTS_MAX; j++) { + int dx1 = hotspots[i].dx; + int dy1 = hotspots[i].dy; + int dx2 = hotspots[j].dx; + int dy2 = hotspots[j].dy; + int correctx, correcty, newx, newy; + char loc[256]; + IImageList *imglNew; + POINT ppt; + + hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1); + ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1); + sprintf(loc, "BeginDrag (%d,%d)\n", i, j); + + /* check merging the dragged image with a second image */ + hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2); + ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n", + dx1, dy1, dx2, dy2); + sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j); + + /* check new hotspot, it should be the same like the old one */ + hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew); + ok(SUCCEEDED(hr), "GetDragImage failed\n"); + ok(ppt.x == dx1 && ppt.y == dy1, + "Expected drag hotspot [%d,%d] got [%d,%d]\n", + dx1, dy1, ppt.x, ppt.y); + /* check size of new dragged image */ + IImageList_GetIconSize(imglNew, &newx, &newy); + correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2)); + correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2)); + ok(newx == correctx && newy == correcty, + "Expected drag image size [%d,%d] got [%d,%d]\n", + correctx, correcty, newx, newy); + sprintf(loc, "GetDragImage (%d,%d)\n", i, j); + IImageList_EndDrag(imgl2); + } + } +#undef SIZEX1 +#undef SIZEY1 +#undef SIZEX2 +#undef SIZEY2 +#undef HOTSPOTS_MAX + IImageList_Release(imgl2); + IImageList_Release(imgl1); +} + +static void DoTest1_v6(void) +{ + IImageList *imgl; + HIMAGELIST himl; + HRESULT hr; + + HICON hicon1; + HICON hicon2; + HICON hicon3; + + int ret = 0; + + /* create an imagelist to play with */ + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); + ok(himl != 0,"failed to create imagelist\n"); + + imgl = (IImageList *) himl; + + /* load the icons to add to the image list */ + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != 0, "no hicon1\n"); + hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon2 != 0, "no hicon2\n"); + hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon3 != 0, "no hicon3\n"); + + /* remove when nothing exists */ + hr = IImageList_Remove(imgl, 0); + ok(!(SUCCEEDED(hr)), "removed nonexistent icon\n"); + + /* removing everything from an empty imagelist should succeed */ + hr = IImageList_Remove(imgl, -1); + ok(SUCCEEDED(hr), "removed nonexistent icon\n"); + + /* add three */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon1, &ret)) && (ret == 0),"failed to add icon1\n"); + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon2, &ret)) && (ret == 1),"failed to add icon2\n"); + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon3, &ret)) && (ret == 2),"failed to add icon3\n"); + + /* remove an index out of range */ + ok(FAILED(IImageList_Remove(imgl, 4711)),"removed nonexistent icon\n"); + + /* remove three */ + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + + /* remove one extra */ + ok(FAILED(IImageList_Remove(imgl, 0)),"removed nonexistent icon\n"); + + /* check SetImageCount/GetImageCount */ + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "couldn't increase image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 3), "invalid image count after increase\n"); + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 1)), "couldn't decrease image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 1), "invalid image count after decrease to 1\n"); + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 0)), "couldn't decrease image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 0), "invalid image count after decrease to 0\n"); + + /* destroy it */ + ok(SUCCEEDED(IImageList_Release(imgl)),"release imagelist failed\n"); + + ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n"); + ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n"); + ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n"); +} + +static void DoTest3_v6(void) +{ + IImageList *imgl; + HIMAGELIST himl; + + HBITMAP hbm1; + HBITMAP hbm2; + HBITMAP hbm3; + + IMAGELISTDRAWPARAMS imldp; + HWND hwndfortest; + HDC hdc; + int ret; + + hwndfortest = create_a_window(); + hdc = GetDC(hwndfortest); + ok(hdc!=NULL, "couldn't get DC\n"); + + /* create an imagelist to play with */ + himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3); + ok(himl!=0,"failed to create imagelist\n"); + + imgl = (IImageList *) himl; + + /* load the icons to add to the image list */ + hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm1 != 0, "no bitmap 1\n"); + hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm2 != 0, "no bitmap 2\n"); + hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm3 != 0, "no bitmap 3\n"); + + /* add three */ + ok(SUCCEEDED(IImageList_Add(imgl, hbm1, 0, &ret)) && (ret == 0), "failed to add bitmap 1\n"); + ok(SUCCEEDED(IImageList_Add(imgl, hbm2, 0, &ret)) && (ret == 1), "failed to add bitmap 2\n"); + + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "Setimage count failed\n"); + ok(SUCCEEDED(IImageList_Replace(imgl, 2, hbm3, 0)), "failed to replace bitmap 3\n"); + + memset(&imldp, 0, sizeof (imldp)); + ok(FAILED(IImageList_Draw(imgl, &imldp)), "zero data succeeded!\n"); + + imldp.cbSize = sizeof (imldp); + imldp.hdcDst = hdc; + imldp.himl = himl; + + if (FAILED(IImageList_Draw(imgl, &imldp))) + { + /* Earlier versions of native comctl32 use a smaller structure */ + imldp.cbSize -= 3 * sizeof(DWORD); + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + } + + REDRAW(hwndfortest); + WAIT; + + imldp.fStyle = SRCCOPY; + imldp.rgbBk = CLR_DEFAULT; + imldp.rgbFg = CLR_DEFAULT; + imldp.y = 100; + imldp.x = 100; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(FAILED(IImageList_Draw(imgl, &imldp)), "should fail\n"); + + /* remove three */ + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 1st bitmap\n"); + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 2nd bitmap\n"); + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 3rd bitmap\n"); + + /* destroy it */ + ok(SUCCEEDED(IImageList_Release(imgl)), "release imagelist failed\n"); + + /* bitmaps should not be deleted by the imagelist */ + ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n"); + ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n"); + ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n"); + + ReleaseDC(hwndfortest, hdc); + DestroyWindow(hwndfortest); +} + +static void testMerge_v6(void) +{ + HIMAGELIST himl1, himl2; + IImageList *imgl1, *imgl2, *merge; + HICON hicon1; + HWND hwnd = create_a_window(); + HRESULT hr; + int ret; + + himl1 = ImageList_Create(32,32,0,0,3); + ok(himl1 != NULL,"failed to create himl1\n"); + + himl2 = ImageList_Create(32,32,0,0,3); + ok(himl2 != NULL,"failed to create himl2\n"); + + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != NULL, "failed to create hicon1\n"); + + if (!himl1 || !himl2 || !hicon1) + return; + + /* cast to IImageList */ + imgl1 = (IImageList *) himl1; + imgl2 = (IImageList *) himl2; + + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl2 failed\n"); + + /* If himl1 has no images, merge still succeeds */ + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1,-1 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1,0 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Same happens if himl2 is empty */ + IImageList_Release(imgl2); + himl2 = ImageList_Create(32,32,0,0,3); + ok(himl2 != NULL,"failed to recreate himl2\n"); + + imgl2 = (IImageList *) himl2; + + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2,-1 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2,0 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Now try merging an image with itself */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"re-add icon1 to himl2 failed\n"); + + hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2 with itself failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Try merging 2 different image lists */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl1 failed\n"); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1 with himl2 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1 with himl2 8,16 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + IImageList_Release(imgl1); + IImageList_Release(imgl2); + + DestroyIcon(hicon1); + DestroyWindow(hwnd); +} + START_TEST(imagelist) { + ULONG_PTR ctx_cookie; + HANDLE hCtx; + HMODULE hComCtl32 = GetModuleHandle("comctl32.dll"); + pImageList_Create = NULL; /* These are not needed for non-v6.0 tests*/ + pImageList_Add = NULL; pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect"); pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount"); - desktopDC=GetDC(NULL); hinst = GetModuleHandleA(NULL); InitCommonControls(); @@ -998,4 +1633,36 @@ START_TEST(imagelist) DoTest3(); testMerge(); test_imagelist_storage(); + + FreeLibrary(hComCtl32); + + /* Now perform v6 tests */ + + if (!load_v6_module(&ctx_cookie, &hCtx)) + return; + + /* Reload comctl32 */ + hComCtl32 = LoadLibraryA("comctl32.dll"); + pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create"); + pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add"); + pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect"); + pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount"); + pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance"); + pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface"); + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + /* Do v6.0 tests */ + test_ImageList_DrawIndirect(); + test_shell_imagelist(); + test_iimagelist(); + + testHotspot_v6(); + DoTest1_v6(); + DoTest3_v6(); + testMerge_v6(); + + CoUninitialize(); + + unload_v6_module(ctx_cookie, hCtx); } diff --git a/rostests/winetests/comctl32/ipaddress.c b/rostests/winetests/comctl32/ipaddress.c index d04223cb4fc..85f92b1d582 100644 --- a/rostests/winetests/comctl32/ipaddress.c +++ b/rostests/winetests/comctl32/ipaddress.c @@ -33,8 +33,6 @@ static HWND create_ipaddress_control (void) handle = CreateWindowEx(0, WC_IPADDRESS, NULL, WS_BORDER|WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, NULL, NULL); - assert(handle); - return handle; } @@ -45,6 +43,11 @@ static void test_get_set_text(void) INT r; hwnd = create_ipaddress_control(); + if (!hwnd) + { + win_skip("IPAddress control not implemented\n"); + return; + } /* check text just after creation */ r = GetWindowText(hwnd, ip, sizeof(ip)/sizeof(CHAR)); diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index e94bdaaabd0..6ef82bb359a 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -3,6 +3,7 @@ * * Copyright 2006 Mike McCormack for CodeWeavers * Copyright 2007 George Gov + * Copyright 2009 Nikolay Sivov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,12 +25,15 @@ #include #include "wine/test.h" +#include "v6util.h" #include "msg.h" #define PARENT_SEQ_INDEX 0 #define PARENT_FULL_SEQ_INDEX 1 #define LISTVIEW_SEQ_INDEX 2 -#define NUM_MSG_SEQUENCES 3 +#define EDITBOX_SEQ_INDEX 3 +#define COMBINED_SEQ_INDEX 4 +#define NUM_MSG_SEQUENCES 5 #define LISTVIEW_ID 0 #define HEADER_ID 1 @@ -38,32 +42,33 @@ #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \ "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2) -HWND hwndparent; +static const WCHAR testparentclassW[] = + {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0}; + +static HWND hwndparent, hwndparentW; +/* prevents edit box creation, LVN_BEGINLABELEDIT return value */ +static BOOL blockEdit; +/* return nonzero on NM_HOVER */ +static BOOL g_block_hover; +/* dumps LVN_ITEMCHANGED message data */ +static BOOL g_dump_itemchanged; +/* format reported to control: + -1 falls to defproc, anything else returned */ +static INT notifyFormat; +/* indicates we're running < 5.80 version */ +static BOOL g_is_below_5; +/* item data passed to LVN_GETDISPINFOA */ +static LVITEMA g_itema; + +static HWND subclass_editbox(HWND hwndListview); static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; -static const struct message create_parent_wnd_seq[] = { - { WM_GETMINMAXINFO, sent }, - { WM_NCCREATE, sent }, - { WM_NCCALCSIZE, sent|wparam, 0 }, - { WM_CREATE, sent }, - { WM_SHOWWINDOW, sent|wparam, 1 }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_QUERYNEWPALETTE, sent|optional }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGED, sent|optional }, - { WM_NCCALCSIZE, sent|wparam|optional, 1 }, - { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, - { WM_ACTIVATE, sent|wparam, 1 }, - { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, - { WM_IME_NOTIFY, sent|defwinproc|optional }, - { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, - /* Win9x adds SWP_NOZORDER below */ - { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, - { WM_NCCALCSIZE, sent|wparam|optional, 1 }, - { WM_SIZE, sent }, - { WM_MOVE, sent }, +static const struct message create_ownerdrawfixed_parent_seq[] = { + { WM_NOTIFYFORMAT, sent }, + { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */ + { WM_MEASUREITEM, sent }, + { WM_PARENTNOTIFY, sent }, { 0 } }; @@ -71,10 +76,10 @@ static const struct message redraw_listview_seq[] = { { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID }, { WM_PAINT, sent|id, 0, 0, HEADER_ID }, { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID }, - { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, HEADER_ID }, + { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID }, { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID }, { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID }, - { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID }, + { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID }, { 0 } }; @@ -123,6 +128,8 @@ static const struct message listview_item_count_seq[] = { { LVM_INSERTITEM, sent }, { LVM_GETITEMCOUNT, sent }, { LVM_DELETEITEM, sent|wparam, 2 }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, { LVM_GETITEMCOUNT, sent }, { LVM_DELETEALLITEMS, sent }, { LVM_GETITEMCOUNT, sent }, @@ -139,6 +146,8 @@ static const struct message listview_itempos_seq[] = { { LVM_INSERTITEM, sent }, { LVM_INSERTITEM, sent }, { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, { LVM_GETITEMPOSITION, sent|wparam, 1 }, { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) }, { LVM_GETITEMPOSITION, sent|wparam, 2 }, @@ -168,9 +177,128 @@ static const struct message forward_erasebkgnd_parent_seq[] = { { 0 } }; -struct subclass_info -{ - WNDPROC oldproc; +static const struct message ownderdata_select_focus_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA }, + { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */ + { 0 } +}; + +static const struct message ownerdata_setstate_all_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { 0 } +}; + +static const struct message ownerdata_defocus_all_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA }, + { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { 0 } +}; + +static const struct message ownerdata_deselect_all_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { 0 } +}; + +static const struct message select_all_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { 0 } +}; + +static const struct message textcallback_set_again_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED }, + { 0 } +}; + +static const struct message single_getdispinfo_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA }, + { 0 } +}; + +static const struct message getitemposition_seq1[] = { + { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID }, + { 0 } +}; + +static const struct message getitemposition_seq2[] = { + { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID }, + { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID }, + { 0 } +}; + +static const struct message editbox_create_pos[] = { + /* sequence sent after LVN_BEGINLABELEDIT */ + /* next two are 4.7x specific */ + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGED, sent|optional }, + + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_NCCALCSIZE, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + /* the rest is todo, skipped in 4.7x */ + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { 0 } +}; + +static const struct message scroll_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL }, + { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL }, + { 0 } +}; + +static const struct message setredraw_seq[] = { + { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID }, + { 0 } +}; + +static const struct message lvs_ex_transparentbkgnd_seq[] = { + { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND }, + { 0 } +}; + +static const struct message edit_end_nochange[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA }, + { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */ + { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS }, + { 0 } +}; + +static const struct message hover_parent[] = { + { WM_GETDLGCODE, sent }, /* todo_wine */ + { WM_NOTIFY, sent|id, 0, 0, NM_HOVER }, + { 0 } +}; + +static const struct message listview_destroy[] = { + { 0x0090, sent|optional }, /* Vista */ + { WM_PARENTNOTIFY, sent }, + { WM_SHOWWINDOW, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_DESTROY, sent }, + { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS }, + { WM_NCDESTROY, sent }, + { 0 } }; static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -184,6 +312,7 @@ 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; + if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code; /* log system messages, except for painting */ if (message < WM_USER && @@ -198,9 +327,67 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); add_message(sequences, PARENT_SEQ_INDEX, &msg); + add_message(sequences, COMBINED_SEQ_INDEX, &msg); } add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg); + switch (message) + { + case WM_NOTIFY: + { + switch (((NMHDR*)lParam)->code) + { + case LVN_BEGINLABELEDIT: + /* subclass edit box */ + if (!blockEdit) + subclass_editbox(((NMHDR*)lParam)->hwndFrom); + + return blockEdit; + + case LVN_ENDLABELEDIT: + { + /* always accept new item text */ + NMLVDISPINFO *di = (NMLVDISPINFO*)lParam; + trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText); + return TRUE; + } + case LVN_BEGINSCROLL: + case LVN_ENDSCROLL: + { + NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam; + + trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ? + "BEGIN" : "END", pScroll->dx, pScroll->dy); + } + 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); + } + break; + case LVN_GETDISPINFOA: + { + NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam; + g_itema = dispinfo->item; + } + break; + case NM_HOVER: + if (g_block_hover) return 1; + break; + } + break; + } + case WM_NOTIFYFORMAT: + { + /* force to return format */ + if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat; + break; + } + } + defwndproc_counter++; ret = DefWindowProcA(hwnd, message, wParam, lParam); defwndproc_counter--; @@ -208,39 +395,72 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP return ret; } -static BOOL register_parent_wnd_class(void) +static BOOL register_parent_wnd_class(BOOL Unicode) { - WNDCLASSA cls; + WNDCLASSA clsA; + WNDCLASSW clsW; - 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 = "Listview test parent class"; - return RegisterClassA(&cls); + if (Unicode) + { + clsW.style = 0; + clsW.lpfnWndProc = parent_wnd_proc; + clsW.cbClsExtra = 0; + clsW.cbWndExtra = 0; + clsW.hInstance = GetModuleHandleW(NULL); + clsW.hIcon = 0; + clsW.hCursor = LoadCursorA(0, IDC_ARROW); + clsW.hbrBackground = GetStockObject(WHITE_BRUSH); + clsW.lpszMenuName = NULL; + clsW.lpszClassName = testparentclassW; + } + else + { + clsA.style = 0; + clsA.lpfnWndProc = parent_wnd_proc; + clsA.cbClsExtra = 0; + clsA.cbWndExtra = 0; + clsA.hInstance = GetModuleHandleA(NULL); + clsA.hIcon = 0; + clsA.hCursor = LoadCursorA(0, IDC_ARROW); + clsA.hbrBackground = GetStockObject(WHITE_BRUSH); + clsA.lpszMenuName = NULL; + clsA.lpszClassName = "Listview test parent class"; + } + + return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA); } -static HWND create_parent_window(void) +static HWND create_parent_window(BOOL Unicode) { - if (!register_parent_wnd_class()) + static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0}; + HWND hwnd; + + if (!register_parent_wnd_class(Unicode)) return NULL; - return CreateWindowEx(0, "Listview test parent class", - "Listview test parent window", - WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | - WS_MAXIMIZEBOX | WS_VISIBLE, - 0, 0, 100, 100, - GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); + blockEdit = FALSE; + notifyFormat = -1; + + if (Unicode) + hwnd = CreateWindowExW(0, testparentclassW, nameW, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL); + else + hwnd = CreateWindowExA(0, "Listview test parent class", + "Listview test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); + SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); + return hwnd; } static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -262,53 +482,20 @@ static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wPa msg.lParam = lParam; msg.id = LISTVIEW_ID; add_message(sequences, LISTVIEW_SEQ_INDEX, &msg); + add_message(sequences, COMBINED_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } static HWND create_listview_control(DWORD style) { - struct subclass_info *info; + WNDPROC oldproc; HWND hwnd; RECT rect; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - - GetClientRect(hwndparent, &rect); - hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo", - WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style, - 0, 0, rect.right, rect.bottom, - hwndparent, NULL, GetModuleHandleA(NULL), NULL); - ok(hwnd != NULL, "gle=%d\n", GetLastError()); - - if (!hwnd) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } - - info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, - (LONG_PTR)listview_subclass_proc); - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info); - - return hwnd; -} - -static HWND create_custom_listview_control(DWORD style) -{ - struct subclass_info *info; - HWND hwnd; - RECT rect; - - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - GetClientRect(hwndparent, &rect); hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo", WS_CHILD | WS_BORDER | WS_VISIBLE | style, @@ -316,22 +503,42 @@ static HWND create_custom_listview_control(DWORD style) hwndparent, NULL, GetModuleHandleA(NULL), NULL); ok(hwnd != NULL, "gle=%d\n", GetLastError()); - if (!hwnd) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!hwnd) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, - (LONG_PTR)listview_subclass_proc); - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)listview_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + return hwnd; +} + +/* unicode listview window with specified parent */ +static HWND create_listview_controlW(DWORD style, HWND parent) +{ + WNDPROC oldproc; + HWND hwnd; + RECT rect; + static const WCHAR nameW[] = {'f','o','o',0}; + + GetClientRect(parent, &rect); + hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW, + WS_CHILD | WS_BORDER | WS_VISIBLE | style, + 0, 0, rect.right, rect.bottom, + parent, NULL, GetModuleHandleW(NULL), NULL); + ok(hwnd != NULL, "gle=%d\n", GetLastError()); + + if (!hwnd) return NULL; + + oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, + (LONG_PTR)listview_subclass_proc); + SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); return hwnd; } static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -347,28 +554,156 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara add_message(sequences, LISTVIEW_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } static HWND subclass_header(HWND hwndListview) { - struct subclass_info *info; + WNDPROC oldproc; HWND hwnd; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - hwnd = ListView_GetHeader(hwndListview); - info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, - (LONG_PTR)header_subclass_proc); - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)header_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); return hwnd; } +static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static LONG defwndproc_counter = 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; + + /* all we need is sizing */ + if (message == WM_WINDOWPOSCHANGING || + message == WM_NCCALCSIZE || + message == WM_WINDOWPOSCHANGED || + message == WM_MOVE || + message == WM_SIZE) + { + add_message(sequences, EDITBOX_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND subclass_editbox(HWND hwndListview) +{ + WNDPROC oldproc; + HWND hwnd; + + hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)editbox_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + return hwnd; +} + +/* Performs a single LVM_HITTEST test */ +static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags, + BOOL todo_item, BOOL todo_flags, int line) +{ + LVHITTESTINFO lpht; + DWORD ret; + + lpht.pt.x = x; + lpht.pt.y = y; + lpht.iSubItem = 10; + + trace("hittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y); + ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht); + + if (todo_item) + { + todo_wine + { + ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret); + ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem); + ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n"); + } + } + else + { + ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret); + ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem); + ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n"); + } + + if (todo_flags) + { + todo_wine + ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags); + } + else if (broken_flags) + ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags), + "Expected flags %x, got %x\n", flags, lpht.flags); + else + ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags); +} + +#define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__) + +/* Performs a single LVM_SUBITEMHITTEST test */ +static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags, + BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line) +{ + LVHITTESTINFO lpht; + DWORD ret; + + lpht.pt.x = x; + lpht.pt.y = y; + + trace("subhittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y); + ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht); + + if (todo_item) + { + todo_wine + { + ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret); + ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem); + } + } + else + { + ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret); + ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem); + } + + if (todo_subitem) + { + todo_wine + ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem); + } + else + ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem); + + if (todo_flags) + { + todo_wine + ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags); + } + else + ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags); +} + +#define test_lvm_subitemhittest(a,b,c,d,e,f,g,h,i) test_lvm_subitemhittest_(a,b,c,d,e,f,g,h,i,__LINE__) + static void test_images(void) { HWND hwnd; @@ -392,7 +727,9 @@ static void test_images(void) 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); ok(hwnd != NULL, "failed to create listview window\n"); - r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940); + r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, + LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE); + ok(r == 0, "should return zero\n"); r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl); @@ -491,7 +828,12 @@ static void test_checkboxes(void) item.mask = LVIF_STATE; item.stateMask = 0xffff; r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); - ok(item.state == 0x1ccc, "state %x\n", item.state); + if (item.state != 0x1ccc) + { + win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n"); + DestroyWindow(hwnd); + return; + } /* Now add an item without specifying a state and check that its state goes to 0x1000 */ item.iItem = 2; @@ -827,59 +1169,99 @@ static void test_items(void) r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); ok(r != 0, "ret %d\n", r); + /* set text to callback value already having it */ + r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0); + expect(TRUE, r); + memset (&item, 0, sizeof (item)); + item.mask = LVIF_TEXT; + item.pszText = LPSTR_TEXTCALLBACK; + item.iItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + memset (&item, 0, sizeof (item)); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + item.pszText = LPSTR_TEXTCALLBACK; + r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item); + expect(TRUE, r); + + ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq, + "check callback text comparison rule", FALSE); + DestroyWindow(hwnd); } static void test_columns(void) { - HWND hwnd, hwndheader; - LVCOLUMN column; - DWORD rc; + HWND hwnd; + LVCOLUMNA column; + LVITEMA item; INT order[2]; + CHAR buff[5]; + DWORD rc; - hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, + hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT, 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); ok(hwnd != NULL, "failed to create listview window\n"); /* Add a column with no mask */ memset(&column, 0xcc, sizeof(column)); column.mask = 0; - rc = ListView_InsertColumn(hwnd, 0, &column); - ok(rc==0, "Inserting column with no mask failed with %d\n", rc); + rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column); + ok(rc == 0, "Inserting column with no mask failed with %d\n", rc); /* Check its width */ - rc = ListView_GetColumnWidth(hwnd, 0); - ok(rc==10 || - broken(rc==0), /* win9x */ + rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); + ok(rc == 10 || broken(rc == 0) /* win9x */, "Inserting column with no mask failed to set width to 10 with %d\n", rc); DestroyWindow(hwnd); /* LVM_GETCOLUMNORDERARRAY */ - hwnd = create_listview_control(0); - hwndheader = subclass_header(hwnd); + hwnd = create_listview_control(LVS_REPORT); + subclass_header(hwnd); memset(&column, 0, sizeof(column)); column.mask = LVCF_WIDTH; column.cx = 100; - rc = ListView_InsertColumn(hwnd, 0, &column); + rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column); ok(rc == 0, "Inserting column failed with %d\n", rc); column.cx = 200; - rc = ListView_InsertColumn(hwnd, 1, &column); + rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column); ok(rc == 1, "Inserting column failed with %d\n", rc); flush_sequences(sequences, NUM_MSG_SEQUENCES); - rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order); - ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n"); + rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order); + ok(rc == 1, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n"); ok(order[0] == 0, "Expected order 0, got %d\n", order[0]); ok(order[1] == 1, "Expected order 1, got %d\n", order[1]); ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE); + /* after column added subitem is considered as present */ + insert_item(hwnd, 0); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + item.pszText = buff; + item.cchTextMax = sizeof(buff); + item.iItem = 0; + item.iSubItem = 1; + item.mask = LVIF_TEXT; + memset(&g_itema, 0, sizeof(g_itema)); + rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(rc == 1, "got %d\n", rc); + ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem); + + ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, + "get subitem text after column added", FALSE); + DestroyWindow(hwnd); } + /* test setting imagelist between WM_NCCREATE and WM_CREATE */ static WNDPROC listviewWndProc; static HIMAGELIST test_create_imagelist; @@ -907,6 +1289,8 @@ static void test_create(void) LVCOLUMNA col; RECT rect; WNDCLASSEX cls; + DWORD style; + cls.cbSize = sizeof(WNDCLASSEX); ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n"); listviewWndProc = cls.lpfnWndProc; @@ -918,6 +1302,15 @@ static void test_create(void) hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0); ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n"); hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + + if (!IsWindow(hHeader)) + { + /* version 4.0 */ + win_skip("LVM_GETHEADER not implemented. Skipping.\n"); + DestroyWindow(hList); + return; + } + ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n"); ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); DestroyWindow(hList); @@ -937,6 +1330,8 @@ static void test_create(void) hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); ok(IsWindow(hHeader), "Header should be created\n"); ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + style = GetWindowLong(hHeader, GWL_STYLE); + ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n"); DestroyWindow(hList); hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL, @@ -1033,12 +1428,14 @@ static void test_create(void) ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP); hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); - ok(IsWindow(hHeader), "Header should be created\n"); + ok(IsWindow(hHeader) || + broken(!IsWindow(hHeader)), /* 4.7x common controls */ + "Header should be created\n"); ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); DestroyWindow(hList); /* not report style accepts LVS_EX_HEADERDRAGDROP too */ - hList = create_custom_listview_control(0); + hList = create_listview_control(LVS_ICON); SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP); r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n"); @@ -1061,17 +1458,24 @@ static void test_create(void) ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); DestroyWindow(hList); + + /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT); + ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq, + "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE); + DestroyWindow(hList); } static void test_redraw(void) { - HWND hwnd, hwndheader; + HWND hwnd; HDC hdc; BOOL res; DWORD r; - hwnd = create_listview_control(0); - hwndheader = subclass_header(hwnd); + hwnd = create_listview_control(LVS_REPORT); + subclass_header(hwnd); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -1167,7 +1571,7 @@ static void test_customdraw(void) HWND hwnd; WNDPROC oldwndproc; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); insert_column(hwnd, 0); insert_column(hwnd, 1); @@ -1193,10 +1597,10 @@ static void test_icon_spacing(void) WORD w, h; DWORD r; - hwnd = create_custom_listview_control(LVS_ICON); + hwnd = create_listview_control(LVS_ICON); ok(hwnd != NULL, "failed to create a listview window\n"); - r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY); + r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY); expect(NFR_ANSI, r); /* reset the icon spacing to defaults */ @@ -1217,6 +1621,13 @@ static void test_icon_spacing(void) "Expected %d, got %d\n", MAKELONG(w, h), r); r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35)); + if (r == 0) + { + /* version 4.0 */ + win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n"); + DestroyWindow(hwnd); + return; + } expect(MAKELONG(20,30), r); r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1)); @@ -1239,7 +1650,7 @@ static void test_color(void) COLORREF color; COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)}; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -1277,6 +1688,11 @@ static void test_item_count(void) HWND hwnd; DWORD r; + HDC hdc; + HFONT hOldFont; + TEXTMETRICA tm; + RECT rect; + INT height; LVITEM item0; LVITEM item1; @@ -1285,9 +1701,22 @@ static void test_item_count(void) static CHAR item1text[] = "item1"; static CHAR item2text[] = "item2"; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); + /* resize in dpiaware manner to fit all 3 items added */ + hdc = GetDC(0); + hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT)); + GetTextMetricsA(hdc, &tm); + /* 2 extra pixels for bounds and header border */ + height = tm.tmHeight + 2; + SelectObject(hdc, hOldFont); + ReleaseDC(0, hdc); + + GetWindowRect(hwnd, &rect); + /* 3 items + 1 header + 1 to be sure */ + MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE); + flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test item count\n"); @@ -1375,7 +1804,7 @@ static void test_item_position(void) static CHAR item1text[] = "item1"; static CHAR item2text[] = "item2"; - hwnd = create_custom_listview_control(LVS_ICON); + hwnd = create_listview_control(LVS_ICON); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -1440,7 +1869,7 @@ static void test_getorigin(void) position.x = position.y = 0; - hwnd = create_custom_listview_control(LVS_ICON); + hwnd = create_listview_control(LVS_ICON); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test get origin results\n"); @@ -1449,7 +1878,7 @@ static void test_getorigin(void) flush_sequences(sequences, NUM_MSG_SEQUENCES); DestroyWindow(hwnd); - hwnd = create_custom_listview_control(LVS_SMALLICON); + hwnd = create_listview_control(LVS_SMALLICON); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test get origin results\n"); @@ -1458,7 +1887,7 @@ static void test_getorigin(void) flush_sequences(sequences, NUM_MSG_SEQUENCES); DestroyWindow(hwnd); - hwnd = create_custom_listview_control(LVS_LIST); + hwnd = create_listview_control(LVS_LIST); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test get origin results\n"); @@ -1467,7 +1896,7 @@ static void test_getorigin(void) flush_sequences(sequences, NUM_MSG_SEQUENCES); DestroyWindow(hwnd); - hwnd = create_custom_listview_control(LVS_REPORT); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test get origin results\n"); @@ -1496,6 +1925,7 @@ static void test_multiselect(void) BYTE kstate[256]; select_task task; LONG_PTR style; + LVITEMA item; static struct t_select_task task_list[] = { { "using VK_DOWN", 0, VK_DOWN, -1, -1 }, @@ -1505,7 +1935,7 @@ static void test_multiselect(void) }; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); for (i=0;i rect2.top, "expected not zero height\n"); +} + + arr[0] = 1; arr[1] = 0; arr[2] = 2; + r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr); + expect(TRUE, r); + + rect.left = LVIR_BOUNDS; + rect.top = 0; + rect.right = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect); + ok(r == TRUE, "got %d\n", r); + expect(0, rect.left); + expect(600, rect.right); + + rect.left = LVIR_BOUNDS; + rect.top = 1; + rect.right = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect); + ok(r == TRUE, "got %d\n", r); + expect(0, rect.left); + expect(200, rect.right); + + rect2.left = LVIR_BOUNDS; + rect2.top = 1; + rect2.right = rect2.bottom = -1; + r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2); + ok(r == TRUE, "got %d\n", r); + expect(0, rect2.left); + expect(200, rect2.right); + /* items are of the same height */ + ok(rect2.top > 0, "expected positive item height\n"); + expect(rect.bottom, rect2.top); + expect(rect.bottom * 2 - rect.top, rect2.bottom); + + rect.left = LVIR_BOUNDS; + rect.top = 2; + rect.right = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect); + ok(r == TRUE, "got %d\n", r); + expect(300, rect.left); + expect(600, rect.right); + DestroyWindow(hwnd); /* try it for non LVS_REPORT style */ @@ -1696,7 +2300,7 @@ static void test_sorting(void) static CHAR names[][5] = {"A", "B", "C", "D", "0"}; CHAR buff[10]; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); /* insert some items */ @@ -1746,7 +2350,7 @@ static void test_sorting(void) DestroyWindow(hwnd); /* switch to LVS_SORTASCENDING when some items added */ - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); item.mask = LVIF_TEXT; @@ -1873,24 +2477,31 @@ static void test_ownerdata(void) LVITEMA item; /* it isn't possible to set LVS_OWNERDATA after creation */ - hwnd = create_listview_control(0); - ok(hwnd != NULL, "failed to create a listview window\n"); - style = GetWindowLongPtrA(hwnd, GWL_STYLE); - ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n"); + if (g_is_below_5) + { + win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n"); + } + else + { + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n"); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + flush_sequences(sequences, NUM_MSG_SEQUENCES); - ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA); - ok(ret == style, "Expected set GWL_STYLE to succeed\n"); - ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, + ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA); + ok(ret == style, "Expected set GWL_STYLE to succeed\n"); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, "try to switch to LVS_OWNERDATA seq", FALSE); - style = GetWindowLongPtrA(hwnd, GWL_STYLE); - ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n"); - DestroyWindow(hwnd); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n"); + DestroyWindow(hwnd); + } /* try to set LVS_OWNERDATA after creation just having it */ - hwnd = create_listview_control(LVS_OWNERDATA); + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); style = GetWindowLongPtrA(hwnd, GWL_STYLE); ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); @@ -1904,23 +2515,30 @@ static void test_ownerdata(void) DestroyWindow(hwnd); /* try to remove LVS_OWNERDATA after creation just having it */ - hwnd = create_listview_control(LVS_OWNERDATA); - ok(hwnd != NULL, "failed to create a listview window\n"); - style = GetWindowLongPtrA(hwnd, GWL_STYLE); - ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); + if (g_is_below_5) + { + win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n"); + } + else + { + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + flush_sequences(sequences, NUM_MSG_SEQUENCES); - ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA); - ok(ret == style, "Expected set GWL_STYLE to succeed\n"); - ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, + ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA); + ok(ret == style, "Expected set GWL_STYLE to succeed\n"); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, "try to switch to LVS_OWNERDATA seq", FALSE); - style = GetWindowLongPtrA(hwnd, GWL_STYLE); - ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); - DestroyWindow(hwnd); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); + DestroyWindow(hwnd); + } /* try select an item */ - hwnd = create_listview_control(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); ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); @@ -1938,7 +2556,7 @@ static void test_ownerdata(void) DestroyWindow(hwnd); /* LVM_SETITEM is unsupported on LVS_OWNERDATA */ - hwnd = create_listview_control(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); ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); @@ -1952,6 +2570,224 @@ static void test_ownerdata(void) res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item); expect(FALSE, res); DestroyWindow(hwnd); + + /* check notifications after focused/selected changed */ + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0); + ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + + ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq, + "ownerdata select notification", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_FOCUSED; + item.state = LVIS_FOCUSED; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + + ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq, + "ownerdata focus notification", TRUE); + + /* select all, check notifications */ + item.stateMask = LVIS_SELECTED; + item.state = 0; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + + g_dump_itemchanged = TRUE; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq, + "ownerdata select all notification", TRUE); + + /* 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; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq, + "ownerdata select all notification", TRUE); + /* deselect all */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + item.stateMask = LVIS_SELECTED; + item.state = 0; + g_dump_itemchanged = TRUE; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq, + "ownerdata deselect all notification", TRUE); + + /* select one, then deselect all */ + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + item.stateMask = LVIS_SELECTED; + item.state = 0; + g_dump_itemchanged = TRUE; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq, + "ownerdata select all notification", TRUE); + + /* remove focused, try to focus all */ + item.stateMask = LVIS_FOCUSED; + item.state = LVIS_FOCUSED; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + item.stateMask = LVIS_FOCUSED; + item.state = 0; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + 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; + res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + item.stateMask = LVIS_FOCUSED; + item.state = 0; + g_dump_itemchanged = TRUE; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + 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; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq, + "ownerdata cut all notification", TRUE); + /* all marked cut, try again */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + item.stateMask = LVIS_CUT; + item.state = LVIS_CUT; + g_dump_itemchanged = TRUE; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item); + expect(TRUE, res); + g_dump_itemchanged = FALSE; + ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq, + "ownerdata cut all notification #2", TRUE); + + DestroyWindow(hwnd); + + /* check notifications on LVM_GETITEM */ + /* zero callback mask */ + 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); + ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_SELECTED; + item.mask = LVIF_STATE; + res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, res); + + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "ownerdata getitem selected state 1", FALSE); + + /* non zero callback mask but not we asking for */ + res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0); + expect(TRUE, res); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_SELECTED; + item.mask = LVIF_STATE; + res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, res); + + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "ownerdata getitem selected state 2", FALSE); + + /* LVIS_OVERLAYMASK callback mask, asking for index */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_OVERLAYMASK; + item.mask = LVIF_STATE; + res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, res); + + ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, + "ownerdata getitem selected state 2", FALSE); + + DestroyWindow(hwnd); + + /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */ + hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n"); + ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n"); + SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n"); + DestroyWindow(hwnd); + /* apparently it's allowed to switch these style on after creation */ + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n"); + SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n"); + DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n"); + SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n"); + DestroyWindow(hwnd); } static void test_norecompute(void) @@ -1963,7 +2799,7 @@ static void test_norecompute(void) DWORD res; /* self containing control */ - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); memset(&item, 0, sizeof(item)); item.mask = LVIF_TEXT | LVIF_STATE; @@ -2003,7 +2839,7 @@ static void test_norecompute(void) DestroyWindow(hwnd); /* LVS_OWNERDATA */ - hwnd = create_listview_control(LVS_OWNERDATA); + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); item.mask = LVIF_STATE; @@ -2032,7 +2868,7 @@ static void test_nosortheader(void) HWND hwnd, header; LONG_PTR style; - hwnd = create_listview_control(0); + hwnd = create_listview_control(LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); @@ -2050,7 +2886,7 @@ static void test_nosortheader(void) DestroyWindow(hwnd); /* create with LVS_NOSORTHEADER */ - hwnd = create_listview_control(LVS_NOSORTHEADER); + hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT); ok(hwnd != NULL, "failed to create a listview window\n"); header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); @@ -2068,11 +2904,1626 @@ static void test_nosortheader(void) DestroyWindow(hwnd); } +static void test_setredraw(void) +{ + HWND hwnd; + DWORD_PTR style; + DWORD ret; + HDC hdc; + RECT rect; + + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE. + ListView seems to handle it internally without DefWinProc */ + + /* default value first */ + ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + expect(0, ret); + /* disable */ + style = GetWindowLongPtr(hwnd, GWL_STYLE); + ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n"); + ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + expect(0, ret); + style = GetWindowLongPtr(hwnd, GWL_STYLE); + ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n"); + ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + expect(0, ret); + + /* check update rect after redrawing */ + ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + expect(0, ret); + InvalidateRect(hwnd, NULL, FALSE); + RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW); + rect.right = rect.bottom = 1; + GetUpdateRect(hwnd, &rect, FALSE); + expect(0, rect.right); + expect(0, rect.bottom); + + /* WM_ERASEBKGND */ + hdc = GetWindowDC(hwndparent); + ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + expect(TRUE, ret); + ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + expect(0, ret); + ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + expect(TRUE, ret); + ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + expect(0, ret); + ReleaseDC(hwndparent, hdc); + + /* check notification messages to show that repainting is disabled */ + ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0); + expect(TRUE, ret); + ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + expect(0, ret); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "redraw after WM_SETREDRAW (FALSE)", FALSE); + + ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE); + expect(TRUE, ret); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE); + + /* message isn't forwarded to header */ + subclass_header(hwnd); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + expect(0, ret); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq, + "WM_SETREDRAW: not forwarded to header", FALSE); + + DestroyWindow(hwnd); +} + +static void test_hittest(void) +{ + HWND hwnd; + DWORD r; + RECT bounds; + LVITEMA item; + static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST"; + POINT pos; + INT x, y; + HIMAGELIST himl, himl2; + HBITMAP hbmp; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* LVS_REPORT with a single subitem (2 columns) */ + insert_column(hwnd, 0); + insert_column(hwnd, 1); + insert_item(hwnd, 0); + + item.iSubItem = 0; + /* the only purpose of that line is to be as long as a half item rect */ + item.pszText = text; + r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item); + expect(TRUE, r); + + r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0)); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0)); + expect(TRUE, r); + + memset(&bounds, 0, sizeof(bounds)); + bounds.left = LVIR_BOUNDS; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds); + ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n"); + ok(bounds.right - bounds.left > 0, "Expected non zero item width\n"); + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos); + expect(TRUE, r); + + /* LVS_EX_FULLROWSELECT not set, no icons attached */ + + /* outside columns by x position - valid is [0, 199] */ + x = -1; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + + x = pos.x + 50; /* column half width */ + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + x = pos.x + 150; /* outside column */ + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + /* outside possible client rectangle (to right) */ + x = pos.x + 500; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE); + test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + /* subitem returned with -1 item too */ + x = pos.x + 150; + y = -10; + test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + /* parent client area is 100x100 by default */ + MoveWindow(hwnd, 0, 0, 300, 100, FALSE); + x = pos.x + 150; /* outside column */ + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + /* the same with LVS_EX_FULLROWSELECT */ + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); + x = pos.x + 150; /* outside column */ + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + MoveWindow(hwnd, 0, 0, 100, 100, FALSE); + x = pos.x + 150; /* outside column */ + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE); + test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE); + /* outside possible client rectangle (to right) */ + x = pos.x + 500; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE); + test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE); + /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */ + himl = ImageList_Create(16, 16, 0, 4, 4); + ok(himl != NULL, "failed to create imagelist\n"); + hbmp = CreateBitmap(16, 16, 1, 1, NULL); + ok(hbmp != NULL, "failed to create bitmap\n"); + r = ImageList_Add(himl, hbmp, 0); + ok(r == 0, "should be zero\n"); + hbmp = CreateBitmap(16, 16, 1, 1, NULL); + ok(hbmp != NULL, "failed to create bitmap\n"); + r = ImageList_Add(himl, hbmp, 0); + ok(r == 1, "should be one\n"); + + r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl); + ok(r == 0, "should return zero\n"); + + item.mask = LVIF_IMAGE; + item.iImage = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + /* on state icon */ + x = pos.x + 8; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE); + + /* state icons indices are 1 based, check with valid index */ + item.mask = LVIF_STATE; + item.state = INDEXTOSTATEIMAGEMASK(1); + item.stateMask = LVIS_STATEIMAGEMASK; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + /* on state icon */ + x = pos.x + 8; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE); + + himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0); + ok(himl2 == himl, "should return handle\n"); + + r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl); + ok(r == 0, "should return zero\n"); + /* on item icon */ + x = pos.x + 8; + y = pos.y + (bounds.bottom - bounds.top) / 2; + test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE); + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE); + y = (bounds.bottom - bounds.top) / 2; + test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE); + + DestroyWindow(hwnd); +} + +static void test_getviewrect(void) +{ + HWND hwnd; + DWORD r; + RECT rect; + LVITEMA item; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* empty */ + r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + + insert_column(hwnd, 0); + insert_column(hwnd, 1); + + memset(&item, 0, sizeof(item)); + item.iItem = 0; + item.iSubItem = 0; + SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + + r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0)); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0)); + expect(TRUE, r); + + rect.left = rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* left is set to (2e31-1) - XP SP2 */ + expect(0, rect.right); + expect(0, rect.top); + expect(0, rect.bottom); + + /* switch to LVS_ICON */ + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT); + + rect.left = rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + expect(0, rect.left); + expect(0, rect.top); + /* precise value differs for 2k, XP and Vista */ + ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom); + ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right); + + DestroyWindow(hwnd); +} + +static void test_getitemposition(void) +{ + HWND hwnd, header; + DWORD r; + POINT pt; + RECT rect; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = subclass_header(hwnd); + + /* LVS_REPORT, single item, no columns added */ + insert_item(hwnd, 0); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + pt.x = pt.y = -1; + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt); + expect(TRUE, r); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE); + + /* LVS_REPORT, single item, single column */ + insert_column(hwnd, 0); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + pt.x = pt.y = -1; + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt); + expect(TRUE, r); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE); + + memset(&rect, 0, sizeof(rect)); + SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect); + /* some padding? */ + expect(2, pt.x); + /* offset by header height */ + expect(rect.bottom - rect.top, pt.y); + + DestroyWindow(hwnd); +} + +static void test_columnscreation(void) +{ + HWND hwnd, header; + DWORD r; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + insert_item(hwnd, 0); + + /* headers columns aren't created automatically */ + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header handle\n"); + r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0); + expect(0, r); + + DestroyWindow(hwnd); +} + +static void test_getitemrect(void) +{ + HWND hwnd; + HIMAGELIST himl; + HBITMAP hbm; + RECT rect; + DWORD r; + LVITEMA item; + LVCOLUMNA col; + INT order[2]; + POINT pt; + + /* rectangle isn't empty for empty text items */ + hwnd = create_listview_control(LVS_LIST); + memset(&item, 0, sizeof(item)); + item.mask = 0; + item.iItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + expect(0, r); + rect.left = LVIR_LABEL; + SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(0, rect.left); + expect(0, rect.top); + todo_wine expect(96, rect.right); + DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* empty item */ + memset(&item, 0, sizeof(item)); + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + expect(0, r); + + rect.left = LVIR_BOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + + /* zero width rectangle with no padding */ + expect(0, rect.left); + expect(0, rect.right); + + insert_column(hwnd, 0); + insert_column(hwnd, 1); + + col.mask = LVCF_WIDTH; + col.cx = 50; + r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col); + expect(TRUE, r); + + col.mask = LVCF_WIDTH; + col.cx = 100; + r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col); + expect(TRUE, r); + + rect.left = LVIR_BOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + + /* still no left padding */ + expect(0, rect.left); + expect(150, rect.right); + + rect.left = LVIR_SELECTBOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding */ + expect(2, rect.left); + + rect.left = LVIR_LABEL; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding, column width */ + expect(2, rect.left); + expect(50, rect.right); + + /* no icons attached */ + rect.left = LVIR_ICON; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding */ + expect(2, rect.left); + expect(2, rect.right); + + /* change order */ + order[0] = 1; order[1] = 0; + r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order); + expect(TRUE, r); + pt.x = -1; + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt); + expect(TRUE, r); + /* 1 indexed column width + padding */ + expect(102, pt.x); + /* rect is at zero too */ + rect.left = LVIR_BOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + expect(0, rect.left); + /* just width sum */ + expect(150, rect.right); + + rect.left = LVIR_SELECTBOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* column width + padding */ + expect(102, rect.left); + + /* back to initial order */ + order[0] = 0; order[1] = 1; + r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order); + expect(TRUE, r); + + /* state icons */ + himl = ImageList_Create(16, 16, 0, 2, 2); + ok(himl != NULL, "failed to create imagelist\n"); + hbm = CreateBitmap(16, 16, 1, 1, NULL); + ok(hbm != NULL, "failed to create bitmap\n"); + r = ImageList_Add(himl, hbm, 0); + ok(r == 0, "should be zero\n"); + hbm = CreateBitmap(16, 16, 1, 1, NULL); + ok(hbm != NULL, "failed to create bitmap\n"); + r = ImageList_Add(himl, hbm, 0); + ok(r == 1, "should be one\n"); + + r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl); + ok(r == 0, "should return zero\n"); + + item.mask = LVIF_STATE; + item.state = INDEXTOSTATEIMAGEMASK(1); + item.stateMask = LVIS_STATEIMAGEMASK; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + + /* icon bounds */ + rect.left = LVIR_ICON; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + stateicon width */ + expect(18, rect.left); + expect(18, rect.right); + /* label bounds */ + rect.left = LVIR_LABEL; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + stateicon width -> column width */ + expect(18, rect.left); + expect(50, rect.right); + + r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0); + ok(r != 0, "should return current list handle\n"); + + r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl); + ok(r == 0, "should return zero\n"); + + item.mask = LVIF_STATE | LVIF_IMAGE; + item.iImage = 1; + item.state = 0; + item.stateMask = ~0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + + /* icon bounds */ + rect.left = LVIR_ICON; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding, icon width */ + expect(2, rect.left); + expect(18, rect.right); + /* label bounds */ + rect.left = LVIR_LABEL; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + icon width -> column width */ + expect(18, rect.left); + expect(50, rect.right); + + /* select bounds */ + rect.left = LVIR_SELECTBOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding, column width */ + expect(2, rect.left); + expect(50, rect.right); + + /* try with indentation */ + item.mask = LVIF_INDENT; + item.iIndent = 1; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + + /* bounds */ + rect.left = LVIR_BOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + 1 icon width, column width */ + expect(0, rect.left); + expect(150, rect.right); + + /* select bounds */ + rect.left = LVIR_SELECTBOUNDS; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + 1 icon width, column width */ + expect(2 + 16, rect.left); + expect(50, rect.right); + + /* label bounds */ + rect.left = LVIR_LABEL; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + 2 icon widths, column width */ + expect(2 + 16*2, rect.left); + expect(50, rect.right); + + /* icon bounds */ + rect.left = LVIR_ICON; + rect.right = rect.top = rect.bottom = -1; + r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect); + expect(TRUE, r); + /* padding + 1 icon width indentation, icon width */ + expect(2 + 16, rect.left); + expect(34, rect.right); + + DestroyWindow(hwnd); +} + +static void test_editbox(void) +{ + static CHAR testitemA[] = "testitem"; + static CHAR testitem1A[] = "testitem_quitelongname"; + static CHAR buffer[25]; + HWND hwnd, hwndedit, hwndedit2, header; + LVITEMA item; + DWORD r; + + hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + insert_column(hwnd, 0); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_TEXT; + item.pszText = testitemA; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + expect(0, r); + + /* test notifications without edit created */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE); + /* same thing but with valid window */ + hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20, + 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE); + DestroyWindow(hwndedit); + + /* setting focus is necessary */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + + /* test children Z-order after Edit box created */ + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header to be created\n"); + ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n"); + ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT)); + + /* modify initial string */ + r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A); + expect(TRUE, r); + + /* edit window is resized and repositioned, + check again for Z-order - it should be preserved */ + ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n"); + ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT)); + + /* return focus to listview */ + SetFocus(hwnd); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_TEXT; + item.pszText = buffer; + item.cchTextMax = sizeof(buffer); + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, r); + + ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n"); + + /* send LVM_EDITLABEL on already created edit */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + /* focus will be set to edit */ + ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n"); + hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit2), "Expected Edit window to be created\n"); + + /* creating label disabled when control isn't focused */ + SetFocus(0); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n"); + + /* check EN_KILLFOCUS handling */ + memset(&item, 0, sizeof(item)); + item.pszText = testitemA; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item); + expect(TRUE, r); + + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + /* modify edit and notify control that it lost focus */ + r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A); + expect(TRUE, r); + r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit); + expect(0, r); + memset(&item, 0, sizeof(item)); + item.pszText = buffer; + item.cchTextMax = sizeof(buffer); + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item); + expect(lstrlen(item.pszText), r); + ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n"); + ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n"); + /* end edit without saving */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box - end edit, no change, escape", TRUE); + /* end edit with saving */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box - end edit, no change, return", TRUE); + + memset(&item, 0, sizeof(item)); + item.pszText = buffer; + item.cchTextMax = sizeof(buffer); + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item); + expect(lstrlen(item.pszText), r); + ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n"); + + /* LVM_EDITLABEL with -1 destroys current edit */ + hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0); + ok(hwndedit == NULL, "Expected Edit window not to be created\n"); + /* no edit present */ + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0); + ok(hwndedit == NULL, "Expected Edit window not to be created\n"); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + /* edit present */ + ok(GetFocus() == hwndedit, "Expected Edit to be focused\n"); + hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0); + ok(hwndedit2 == NULL, "Expected Edit window not to be created\n"); + ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n"); + ok(GetFocus() == hwnd, "Expected List to be focused\n"); + /* check another negative value */ + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + ok(GetFocus() == hwndedit, "Expected Edit to be focused\n"); + hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0); + ok(hwndedit2 == NULL, "Expected Edit window not to be created\n"); + ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n"); + ok(GetFocus() == hwnd, "Expected List to be focused\n"); + /* and value greater than max item index */ + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + ok(GetFocus() == hwndedit, "Expected Edit to be focused\n"); + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0); + ok(hwndedit2 == NULL, "Expected Edit window not to be created\n"); + ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n"); + ok(GetFocus() == hwnd, "Expected List to be focused\n"); + + /* messaging tests */ + SetFocus(hwnd); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + blockEdit = FALSE; + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + /* testing only sizing messages */ + ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos, + "edit box create - sizing", FALSE); + + /* WM_COMMAND with EN_KILLFOCUS isn't forwared to parent */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE); + + DestroyWindow(hwnd); +} + +static void test_notifyformat(void) +{ + HWND hwnd, header; + DWORD r; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT, + CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */ + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY); + /* set */ + r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0); + expect(0, r); + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + if (r == 1) + { + r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0); + expect(1, r); + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + } + else + { + win_skip("LVM_GETUNICODEFORMAT is unsupported\n"); + DestroyWindow(hwnd); + return; + } + + DestroyWindow(hwnd); + + /* test failure in parent WM_NOTIFYFORMAT */ + notifyFormat = 0; + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r ); + r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY); + ok(r != 0, "Expected valid format\n"); + + notifyFormat = NFR_UNICODE; + r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY); + expect(NFR_UNICODE, r); + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r ); + + notifyFormat = NFR_ANSI; + r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY); + expect(NFR_ANSI, r); + r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r ); + + DestroyWindow(hwnd); + + /* try different unicode window combination and defaults */ + if (!GetModuleHandleW(NULL)) + { + win_skip("Additional notify format tests are incompatible with Win9x\n"); + return; + } + + hwndparentW = create_parent_window(TRUE); + ok(IsWindow(hwndparentW), "Unicode parent creation failed\n"); + if (!IsWindow(hwndparentW)) return; + + notifyFormat = -1; + hwnd = create_listview_controlW(LVS_REPORT, hwndparentW); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + DestroyWindow(hwnd); + /* receiving error code defaulting to ansi */ + notifyFormat = 0; + hwnd = create_listview_controlW(LVS_REPORT, hwndparentW); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + DestroyWindow(hwnd); + /* receiving ansi code from unicode window, use it */ + notifyFormat = NFR_ANSI; + hwnd = create_listview_controlW(LVS_REPORT, hwndparentW); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + DestroyWindow(hwnd); + /* unicode listview with ansi parent window */ + notifyFormat = -1; + hwnd = create_listview_controlW(LVS_REPORT, hwndparent); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + DestroyWindow(hwnd); + /* unicode listview with ansi parent window, return error code */ + notifyFormat = 0; + hwnd = create_listview_controlW(LVS_REPORT, hwndparent); + ok(hwnd != NULL, "failed to create a listview window\n"); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "expected header to be created\n"); + r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0); + expect(0, r); + r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, r); + DestroyWindow(hwnd); + + DestroyWindow(hwndparentW); +} + +static void test_indentation(void) +{ + HWND hwnd; + LVITEMA item; + DWORD r; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_INDENT; + item.iItem = 0; + item.iIndent = I_INDENTCALLBACK; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + expect(0, r); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + item.iItem = 0; + item.mask = LVIF_INDENT; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + + ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, + "get indent dispinfo", FALSE); + + DestroyWindow(hwnd); +} + +static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param) +{ + return 0; +} + +static BOOL is_below_comctl_5(void) +{ + HWND hwnd; + BOOL ret; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + insert_item(hwnd, 0); + + ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx); + + DestroyWindow(hwnd); + + return !ret; +} + +static void test_get_set_view(void) +{ + HWND hwnd; + DWORD ret; + DWORD_PTR style; + + /* test style->view mapping */ + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0); + expect(LV_VIEW_DETAILS, ret); + + style = GetWindowLongPtr(hwnd, GWL_STYLE); + /* LVS_ICON == 0 */ + SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT); + ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0); + expect(LV_VIEW_ICON, ret); + + style = GetWindowLongPtr(hwnd, GWL_STYLE); + SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON); + ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0); + expect(LV_VIEW_SMALLICON, ret); + + style = GetWindowLongPtr(hwnd, GWL_STYLE); + SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST); + ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0); + expect(LV_VIEW_LIST, ret); + + /* switching view doesn't touch window style */ + ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0); + expect(1, ret); + style = GetWindowLongPtr(hwnd, GWL_STYLE); + ok(style & LVS_LIST, "Expected style to be preserved\n"); + ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0); + expect(1, ret); + style = GetWindowLongPtr(hwnd, GWL_STYLE); + ok(style & LVS_LIST, "Expected style to be preserved\n"); + ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0); + expect(1, ret); + style = GetWindowLongPtr(hwnd, GWL_STYLE); + ok(style & LVS_LIST, "Expected style to be preserved\n"); + + DestroyWindow(hwnd); +} + +static void test_canceleditlabel(void) +{ + HWND hwnd, hwndedit; + DWORD ret; + CHAR buff[10]; + LVITEMA itema; + static CHAR test[] = "test"; + static const CHAR test1[] = "test1"; + + hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + insert_item(hwnd, 0); + + /* try without edit created */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0); + expect(TRUE, ret); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "cancel edit label without edit", FALSE); + + /* cancel without data change */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected edit control to be created\n"); + ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0); + expect(TRUE, ret); + ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n"); + + /* cancel after data change */ + memset(&itema, 0, sizeof(itema)); + itema.pszText = test; + ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema); + expect(TRUE, ret); + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected edit control to be created\n"); + ret = SetWindowText(hwndedit, test1); + ok(ret != 0, "Expected edit text to change\n"); + ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0); + expect(TRUE, ret); + ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n"); + memset(&itema, 0, sizeof(itema)); + itema.pszText = buff; + itema.cchTextMax = sizeof(buff)/sizeof(CHAR); + ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema); + expect(5, ret); + ok(strcmp(buff, test1) == 0, "Expected label text not to change\n"); + + DestroyWindow(hwnd); +} + +static void test_mapidindex(void) +{ + HWND hwnd; + DWORD ret; + + /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */ + hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + insert_item(hwnd, 0); + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0); + expect(-1, ret); + DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* LVM_MAPINDEXTOID with invalid index */ + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0); + expect(-1, ret); + + insert_item(hwnd, 0); + insert_item(hwnd, 1); + + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0); + expect(-1, ret); + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0); + expect(-1, ret); + + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0); + expect(0, ret); + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0); + expect(1, ret); + /* remove 0 indexed item, id retained */ + SendMessage(hwnd, LVM_DELETEITEM, 0, 0); + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0); + expect(1, ret); + /* new id starts from previous value */ + insert_item(hwnd, 1); + ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0); + expect(2, ret); + + /* get index by id */ + ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0); + expect(-1, ret); + ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0); + expect(-1, ret); + ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0); + expect(0, ret); + ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0); + expect(1, ret); + + DestroyWindow(hwnd); +} + +static void test_getitemspacing(void) +{ + HWND hwnd; + DWORD ret; + INT cx, cy; + HIMAGELIST himl; + HBITMAP hbmp; + LVITEMA itema; + + cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON); + cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON); + + /* LVS_ICON */ + hwnd = create_listview_control(LVS_ICON); + ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0); +todo_wine { + expect(cx, LOWORD(ret)); + expect(cy, HIWORD(ret)); +} + /* now try with icons */ + himl = ImageList_Create(40, 40, 0, 4, 4); + ok(himl != NULL, "failed to create imagelist\n"); + hbmp = CreateBitmap(40, 40, 1, 1, NULL); + ok(hbmp != NULL, "failed to create bitmap\n"); + ret = ImageList_Add(himl, hbmp, 0); + expect(0, ret); + ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl); + expect(0, ret); + + itema.mask = LVIF_IMAGE; + itema.iImage = 0; + itema.iItem = 0; + itema.iSubItem = 0; + ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema); + expect(0, ret); + ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0); +todo_wine { + /* spacing + icon size returned */ + expect(cx + 40, LOWORD(ret)); + expect(cy + 40, HIWORD(ret)); +} + DestroyWindow(hwnd); + /* LVS_SMALLICON */ + hwnd = create_listview_control(LVS_SMALLICON); + ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0); +todo_wine { + expect(cx, LOWORD(ret)); + expect(cy, HIWORD(ret)); +} + DestroyWindow(hwnd); + /* LVS_REPORT */ + hwnd = create_listview_control(LVS_REPORT); + ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0); +todo_wine { + expect(cx, LOWORD(ret)); + expect(cy, HIWORD(ret)); +} + DestroyWindow(hwnd); + /* LVS_LIST */ + hwnd = create_listview_control(LVS_LIST); + ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0); +todo_wine { + expect(cx, LOWORD(ret)); + expect(cy, HIWORD(ret)); +} + DestroyWindow(hwnd); +} + +static void test_getcolumnwidth(void) +{ + HWND hwnd; + DWORD ret; + DWORD_PTR style; + LVCOLUMNA col; + LVITEMA itema; + + /* default column width */ + hwnd = create_listview_control(LVS_ICON); + ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); + expect(0, ret); + style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST); + ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); + todo_wine expect(8, ret); + style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST; + SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT); + col.mask = 0; + ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col); + expect(0, ret); + ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); + expect(10, ret); + DestroyWindow(hwnd); + + /* default column width with item added */ + hwnd = create_listview_control(LVS_LIST); + memset(&itema, 0, sizeof(itema)); + SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema); + ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); + todo_wine expect(96, ret); + DestroyWindow(hwnd); +} + +static void test_scrollnotify(void) +{ + HWND hwnd; + DWORD ret; + + hwnd = create_listview_control(LVS_REPORT); + + insert_column(hwnd, 0); + insert_column(hwnd, 1); + insert_item(hwnd, 0); + + /* make it scrollable - resize */ + ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0)); + expect(TRUE, ret); + ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0)); + expect(TRUE, ret); + + /* try with dummy call */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessage(hwnd, LVM_SCROLL, 0, 0); + expect(TRUE, ret); + ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq, + "scroll notify 1", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessage(hwnd, LVM_SCROLL, 1, 0); + expect(TRUE, ret); + ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq, + "scroll notify 2", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessage(hwnd, LVM_SCROLL, 1, 1); + expect(TRUE, ret); + ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq, + "scroll notify 3", TRUE); + + DestroyWindow(hwnd); +} + +static void test_LVS_EX_TRANSPARENTBKGND(void) +{ + HWND hwnd; + DWORD ret; + HDC hdc; + + hwnd = create_listview_control(LVS_REPORT); + + ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0)); + expect(TRUE, ret); + + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND, + LVS_EX_TRANSPARENTBKGND); + + ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0); + if (ret != CLR_NONE) + { + win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n"); + DestroyWindow(hwnd); + return; + } + + /* try to set some back color and check this style bit */ + ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0)); + expect(TRUE, ret); + ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n"); + + /* now test what this style actually does */ + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND, + LVS_EX_TRANSPARENTBKGND); + + hdc = GetWindowDC(hwndparent); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq, + "LVS_EX_TRANSPARENTBKGND parent", FALSE); + + ReleaseDC(hwndparent, hdc); + + DestroyWindow(hwnd); +} + +static void test_approximate_viewrect(void) +{ + HWND hwnd; + DWORD ret; + HIMAGELIST himl; + HBITMAP hbmp; + LVITEMA itema; + static CHAR test[] = "abracadabra, a very long item label"; + + hwnd = create_listview_control(LVS_ICON); + himl = ImageList_Create(40, 40, 0, 4, 4); + ok(himl != NULL, "failed to create imagelist\n"); + hbmp = CreateBitmap(40, 40, 1, 1, NULL); + ok(hbmp != NULL, "failed to create bitmap\n"); + ret = ImageList_Add(himl, hbmp, 0); + expect(0, ret); + ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl); + expect(0, ret); + + itema.mask = LVIF_IMAGE; + itema.iImage = 0; + itema.iItem = 0; + itema.iSubItem = 0; + ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema); + expect(0, ret); + + ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75)); + if (ret == 0) + { + /* version 4.0 */ + win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n"); + return; + } + + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100)); + ok(MAKELONG(77,827)==ret,"Incorrect Approximate rect\n"); + + ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50)); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100)); + ok(MAKELONG(102,302)==ret,"Incorrect Approximate rect\n"); + + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100)); + ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n"); + + itema.pszText = test; + ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema); + expect(TRUE, ret); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100)); + ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n"); + + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100)); + ok(MAKELONG(52,2)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100)); + ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100)); + ok(MAKELONG(102,52)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100)); + ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100)); + ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100)); + ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100)); + ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n"); + ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100)); + ok(MAKELONG(152,152)==ret,"Incorrect Approximate rect\n"); + + DestroyWindow(hwnd); +} + +static void test_finditem(void) +{ + LVFINDINFOA fi; + static char f[5]; + HWND hwnd; + DWORD r; + + hwnd = create_listview_control(LVS_REPORT); + insert_item(hwnd, 0); + + memset(&fi, 0, sizeof(fi)); + + /* full string search, inserted text was "foo" */ + strcpy(f, "foo"); + fi.flags = LVFI_STRING; + fi.psz = f; + r = SendMessage(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 = SendMessage(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; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(-1, r); + + /* try with LVFI_SUBSTRING */ + strcpy(f, "fo"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + if (r == -1) + { + win_skip("LVFI_SUBSTRING not supported\n"); + DestroyWindow(hwnd); + return; + } + expect(0, r); + strcpy(f, "f"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + strcpy(f, "o"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(-1, r); + + strcpy(f, "f"); + fi.flags = LVFI_SUBSTRING | LVFI_STRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + + DestroyWindow(hwnd); +} + +static void test_LVS_EX_HEADERINALLVIEWS(void) +{ + HWND hwnd, header; + DWORD style; + + hwnd = create_listview_control(LVS_ICON); + + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, + LVS_EX_HEADERINALLVIEWS); + + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + if (!IsWindow(header)) + { + win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n"); + DestroyWindow(hwnd); + return; + } + + /* LVS_NOCOLUMNHEADER works as before */ + style = GetWindowLongA(hwnd, GWL_STYLE); + SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER); + style = GetWindowLongA(header, GWL_STYLE); + ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n"); + style = GetWindowLongA(hwnd, GWL_STYLE); + SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER); + style = GetWindowLongA(header, GWL_STYLE); + ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n"); + + /* try to remove style */ + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header to be created\n"); + style = GetWindowLongA(header, GWL_STYLE); + ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n"); + + DestroyWindow(hwnd); + + /* check other styles */ + hwnd = create_listview_control(LVS_LIST); + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, + LVS_EX_HEADERINALLVIEWS); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header to be created\n"); + DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_SMALLICON); + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, + LVS_EX_HEADERINALLVIEWS); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header to be created\n"); + DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_REPORT); + SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, + LVS_EX_HEADERINALLVIEWS); + header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header to be created\n"); + DestroyWindow(hwnd); +} + +static void test_hover(void) +{ + HWND hwnd; + DWORD r; + + hwnd = create_listview_control(LVS_ICON); + + /* test WM_MOUSEHOVER forwarding */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE); + g_block_hover = TRUE; + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE); + g_block_hover = FALSE; + + r = SendMessage(hwnd, LVM_SETHOVERTIME, 0, 500); + expect(HOVER_DEFAULT, r); + r = SendMessage(hwnd, LVM_GETHOVERTIME, 0, 0); + expect(500, r); + + DestroyWindow(hwnd); +} + +static void test_destroynotify(void) +{ + HWND hwnd; + + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "failed to create listview window\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); + ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE); +} + +static void test_header_notification(void) +{ + HWND list, header; + HDITEMA item; + NMHEADER nmh; + LVCOLUMNA col; + LRESULT ret; + + list = create_listview_control(LVS_REPORT); + ok(list != 0, "failed to create listview window\n"); + + memset(&col, 0, sizeof(col)); + col.mask = LVCF_WIDTH; + col.cx = 100; + ret = SendMessage(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col); + ok(!ret, "expected 0, got %ld\n", ret); + + header = subclass_header(list); + + ret = SendMessage(header, HDM_GETITEMCOUNT, 0, 0); + ok(ret == 1, "expected header item count 1, got %ld\n", ret); + + memset(&item, 0, sizeof(item)); + item.mask = HDI_WIDTH; + ret = SendMessage(header, HDM_GETITEMA, 0, (LPARAM)&item); + ok(ret, "HDM_GETITEM failed\n"); + ok(item.cxy == 100, "expected 100, got %d\n", item.cxy); + + nmh.hdr.hwndFrom = header; + nmh.hdr.idFrom = GetWindowLongPtr(header, GWLP_ID); + nmh.hdr.code = HDN_ITEMCHANGEDA; + nmh.iItem = 0; + nmh.iButton = 0; + item.mask = HDI_WIDTH; + item.cxy = 50; + nmh.pitem = &item; + ret = SendMessage(list, WM_NOTIFY, 0, (LPARAM)&nmh); + ok(!ret, "WM_NOTIFY/HDN_ITEMCHANGED failed\n"); + + DestroyWindow(list); +} + +static void test_createdragimage(void) +{ + HIMAGELIST himl; + POINT pt; + HWND list; + + list = create_listview_control(LVS_ICON); + ok(list != 0, "failed to create listview window\n"); + + insert_item(list, 0); + + /* NULL point */ + himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0); + ok(himl == NULL, "got %p\n", himl); + + himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt); + ok(himl != NULL, "got %p\n", himl); + ImageList_Destroy(himl); + + DestroyWindow(list); +} + START_TEST(listview) { HMODULE hComctl32; BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + ULONG_PTR ctx_cookie; + HANDLE hCtx; + HWND hwnd; + hComctl32 = GetModuleHandleA("comctl32.dll"); pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); if (pInitCommonControlsEx) @@ -2087,11 +4538,12 @@ START_TEST(listview) init_msg_sequences(sequences, NUM_MSG_SEQUENCES); - flush_sequences(sequences, NUM_MSG_SEQUENCES); - hwndparent = create_parent_window(); - ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE); + hwndparent = create_parent_window(FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); + g_is_below_5 = is_below_comctl_5(); + + test_header_notification(); test_images(); test_checkboxes(); test_items(); @@ -2105,9 +4557,58 @@ START_TEST(listview) test_columns(); test_getorigin(); test_multiselect(); + test_getitemrect(); test_subitem_rect(); test_sorting(); test_ownerdata(); test_norecompute(); test_nosortheader(); + test_setredraw(); + test_hittest(); + test_getviewrect(); + test_getitemposition(); + test_columnscreation(); + test_editbox(); + test_notifyformat(); + test_indentation(); + test_getitemspacing(); + test_getcolumnwidth(); + test_approximate_viewrect(); + test_finditem(); + test_hover(); + test_destroynotify(); + test_createdragimage(); + + if (!load_v6_module(&ctx_cookie, &hCtx)) + { + DestroyWindow(hwndparent); + return; + } + + /* this is a XP SP3 failure workaround */ + hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo", + WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT, + 0, 0, 100, 100, + hwndparent, NULL, GetModuleHandleA(NULL), NULL); + if (!IsWindow(hwnd)) + { + win_skip("FIXME: failed to create ListView window.\n"); + unload_v6_module(ctx_cookie, hCtx); + DestroyWindow(hwndparent); + return; + } + else + DestroyWindow(hwnd); + + /* comctl32 version 6 tests start here */ + test_get_set_view(); + test_canceleditlabel(); + test_mapidindex(); + test_scrollnotify(); + test_LVS_EX_TRANSPARENTBKGND(); + test_LVS_EX_HEADERINALLVIEWS(); + + unload_v6_module(ctx_cookie, hCtx); + + DestroyWindow(hwndparent); } diff --git a/rostests/winetests/comctl32/misc.c b/rostests/winetests/comctl32/misc.c index e3cf04b79ab..8f83260db17 100644 --- a/rostests/winetests/comctl32/misc.c +++ b/rostests/winetests/comctl32/misc.c @@ -104,7 +104,9 @@ static void test_GetPtrAW(void) ok (count == sourcelen || broken(count == 0), /* win9x */ "Expected count to be %d, it was %d\n", sourcelen, count); - ok (!lstrcmp(dest, desttest), "Expected destination to not have changed\n"); + ok (!lstrcmp(dest, desttest) || + broken(!lstrcmp(dest, "")), /* Win7 */ + "Expected destination to not have changed\n"); count = 0; count = pStr_GetPtrA(source, NULL, destsize); diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c index 1ca1997d720..30f682ff815 100644 --- a/rostests/winetests/comctl32/monthcal.c +++ b/rostests/winetests/comctl32/monthcal.c @@ -33,18 +33,16 @@ #include "msg.h" #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got); +#define expect_hex(expected, got) ok(expected == got, "Expected %x, got %x\n", expected, got); #define NUM_MSG_SEQUENCES 2 #define PARENT_SEQ_INDEX 0 #define MONTHCAL_SEQ_INDEX 1 -struct subclass_info -{ - WNDPROC oldproc; -}; - static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; +static HWND parent_wnd; + static const struct message create_parent_window_seq[] = { { WM_GETMINMAXINFO, sent }, { WM_NCCREATE, sent }, @@ -56,7 +54,7 @@ static const struct message create_parent_window_seq[] = { { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 }, { WM_WINDOWPOSCHANGED, sent|optional }, { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|defwinproc|optional }, @@ -81,6 +79,7 @@ static const struct message create_monthcal_multi_sel_style_seq[] = { { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, { WM_QUERYUISTATE, sent|optional }, { WM_GETFONT, sent }, + { WM_PARENTNOTIFY, sent }, { 0 } }; @@ -126,7 +125,6 @@ static const struct message monthcal_color_seq[] = { static const struct message monthcal_curr_date_seq[] = { { MCM_SETCURSEL, sent|wparam, 0}, { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, - { WM_ERASEBKGND, sent|lparam|defwinproc, 0}, { MCM_SETCURSEL, sent|wparam, 0}, { MCM_SETCURSEL, sent|wparam, 0}, { MCM_GETCURSEL, sent|wparam, 0}, @@ -213,9 +211,6 @@ static const struct message monthcal_hit_test_seq[] = { { MCM_HITTEST, sent|wparam, 0}, { MCM_HITTEST, sent|wparam, 0}, { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, { 0 } }; @@ -224,7 +219,7 @@ static const struct message monthcal_todaylink_seq[] = { { MCM_SETTODAY, sent|wparam, 0}, { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, { MCM_GETTODAY, sent|wparam, 0}, - { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)}, + { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON}, { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0}, { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, { MCM_GETCURSEL, sent|wparam, 0}, @@ -289,6 +284,9 @@ static const struct message destroy_monthcal_child_msgs_seq[] = { static const struct message destroy_monthcal_multi_sel_style_seq[] = { { 0x0090, sent|optional }, /* Vista */ + { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0}, + { WM_WINDOWPOSCHANGING, sent|wparam, 0}, + { WM_WINDOWPOSCHANGED, sent|wparam, 0}, { WM_DESTROY, sent|wparam|lparam, 0, 0}, { WM_NCDESTROY, sent|wparam|lparam, 0, 0}, { 0 } @@ -299,12 +297,14 @@ static const struct message destroy_parent_seq[] = { { 0x0090, sent|optional }, /* Vista */ { WM_WINDOWPOSCHANGING, sent|wparam, 0}, { WM_WINDOWPOSCHANGED, sent|wparam, 0}, - { WM_NCACTIVATE, sent|wparam, 0}, - { WM_ACTIVATE, sent|wparam, 0}, + { WM_IME_SETCONTEXT, sent|wparam|optional, 0}, + { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0}, + { WM_NCACTIVATE, sent|wparam|optional, 0}, + { WM_ACTIVATE, sent|wparam|optional, 0}, { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0}, { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0}, - { WM_ACTIVATEAPP, sent|wparam, 0}, - { WM_KILLFOCUS, sent|wparam|lparam, 0, 0}, + { WM_ACTIVATEAPP, sent|wparam|optional, 0}, + { WM_KILLFOCUS, sent|wparam|lparam|optional, 0, 0}, { WM_IME_SETCONTEXT, sent|wparam|optional, 0}, { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0}, { WM_DESTROY, sent|wparam|lparam, 0, 0}, @@ -315,30 +315,97 @@ static const struct message destroy_parent_seq[] = { static void test_monthcal(void) { HWND hwnd; - SYSTEMTIME st[2], st1[2]; + SYSTEMTIME st[2], st1[2], today; int res, month_range; + DWORD limits; hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, 0, 300, 300, 0, 0, NULL, NULL); ok(hwnd != NULL, "Failed to create MonthCal\n"); + + /* test range just after creation */ + memset(&st, 0xcc, sizeof(st)); + limits = SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st); + ok(limits == 0 || + broken(limits == GDTR_MIN), /* comctl32 <= 4.70 */ + "No limits should be set (%d)\n", limits); + if (limits == GDTR_MIN) + { + win_skip("comctl32 <= 4.70 is broken\n"); + DestroyWindow(hwnd); + return; + } + + ok(0 == st[0].wYear || + broken(1752 == st[0].wYear), /* comctl32 <= 4.72 */ + "Expected 0, got %d\n", st[0].wYear); + ok(0 == st[0].wMonth || + broken(9 == st[0].wMonth), /* comctl32 <= 4.72 */ + "Expected 0, got %d\n", st[0].wMonth); + ok(0 == st[0].wDay || + broken(14 == st[0].wDay), /* comctl32 <= 4.72 */ + "Expected 0, got %d\n", st[0].wDay); + expect(0, st[0].wDayOfWeek); + expect(0, st[0].wHour); + expect(0, st[0].wMinute); + expect(0, st[0].wSecond); + expect(0, st[0].wMilliseconds); + + expect(0, st[1].wYear); + expect(0, st[1].wMonth); + expect(0, st[1].wDay); + expect(0, st[1].wDayOfWeek); + expect(0, st[1].wHour); + expect(0, st[1].wMinute); + expect(0, st[1].wSecond); + expect(0, st[1].wMilliseconds); + GetSystemTime(&st[0]); st[1] = st[0]; + SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&today); + /* Invalid date/time */ st[0].wYear = 2000; /* Time should not matter */ st[1].wHour = st[1].wMinute = st[1].wSecond = 70; + st[1].wMilliseconds = 1200; ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n"); + /* invalid timestamp is written back with today data and msecs untouched */ + expect(today.wHour, st[1].wHour); + expect(today.wMinute, st[1].wMinute); + expect(today.wSecond, st[1].wSecond); + expect(1200, st[1].wMilliseconds); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n"); - ok(st1[0].wYear != 2000, "Lover limit changed\n"); + ok(st1[0].wYear != 2000, "Lower limit changed\n"); + /* invalid timestamp should be replaced with today data, except msecs */ + expect(today.wHour, st1[1].wHour); + expect(today.wMinute, st1[1].wMinute); + expect(today.wSecond, st1[1].wSecond); + expect(1200, st1[1].wMilliseconds); + + /* Invalid date/time with invalid milliseconds only */ + GetSystemTime(&st[0]); + st[1] = st[0]; + /* Time should not matter */ + st[1].wMilliseconds = 1200; + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n"); + /* invalid milliseconds field doesn't lead to invalid timestamp */ + expect(st[0].wHour, st[1].wHour); + expect(st[0].wMinute, st[1].wMinute); + expect(st[0].wSecond, st[1].wSecond); + expect(1200, st[1].wMilliseconds); + + GetSystemTime(&st[0]); st[1].wMonth = 0; ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n"); ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n"); - ok(st1[0].wYear != 2000, "Lover limit changed\n"); + ok(st1[0].wYear != 2000, "Lower limit changed\n"); ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n"); ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n"); - ok(st1[0].wYear != 2000, "Lover limit changed\n"); + ok(st1[0].wYear != 2000, "Lower limit changed\n"); GetSystemTime(&st[0]); st[0].wDay = 20; @@ -373,6 +440,60 @@ static void test_monthcal(void) ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n"); ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n"); + /* set both limits, then set max < min */ + GetSystemTime(&st[0]); + st[1] = st[0]; + st[1].wYear++; + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n"); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n"); + st[1].wYear -= 2; + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set limits\n"); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Max limit expected\n"); + + expect(0, st1[0].wYear); + expect(0, st1[0].wMonth); + expect(0, st1[0].wDay); + expect(0, st1[0].wDayOfWeek); + expect(0, st1[0].wHour); + expect(0, st1[0].wMinute); + expect(0, st1[0].wSecond); + expect(0, st1[0].wMilliseconds); + + expect(st[1].wYear, st1[1].wYear); + expect(st[1].wMonth, st1[1].wMonth); + expect(st[1].wDay, st1[1].wDay); + expect(st[1].wDayOfWeek, st1[1].wDayOfWeek); + expect(st[1].wHour, st1[1].wHour); + expect(st[1].wMinute, st1[1].wMinute); + expect(st[1].wSecond, st1[1].wSecond); + expect(st[1].wMilliseconds, st1[1].wMilliseconds); + + st[1] = st[0]; + st[1].wYear++; + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n"); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n"); + st[0].wYear++; /* start == end now */ + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)st), "Failed to set limits\n"); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MIN, "Min limit expected\n"); + + expect(st[0].wYear, st1[0].wYear); + expect(st[0].wMonth, st1[0].wMonth); + expect(st[0].wDay, st1[0].wDay); + expect(st[0].wDayOfWeek, st1[0].wDayOfWeek); + expect(st[0].wHour, st1[0].wHour); + expect(st[0].wMinute, st1[0].wMinute); + expect(st[0].wSecond, st1[0].wSecond); + expect(st[0].wMilliseconds, st1[0].wMilliseconds); + + expect(0, st1[1].wYear); + expect(0, st1[1].wMonth); + expect(0, st1[1].wDay); + expect(0, st1[1].wDayOfWeek); + expect(0, st1[1].wHour); + expect(0, st1[1].wMinute); + expect(0, st1[1].wSecond); + expect(0, st1[1].wMilliseconds); + DestroyWindow(hwnd); } @@ -455,7 +576,7 @@ static HWND create_parent_window(void) static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -467,38 +588,40 @@ static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wPa msg.lParam = lParam; add_message(sequences, MONTHCAL_SEQ_INDEX, &msg); + /* some debug output for style changing */ + if ((message == WM_STYLECHANGING || + message == WM_STYLECHANGED) && lParam) + { + STYLESTRUCT *style = (STYLESTRUCT*)lParam; + trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew); + } + defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } -static HWND create_monthcal_control(DWORD style, HWND parent_window) +static HWND create_monthcal_control(DWORD style) { - struct subclass_info *info; + WNDPROC oldproc; HWND hwnd; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - hwnd = CreateWindowEx(0, MONTHCAL_CLASS, "", - style, + WS_CHILD | WS_BORDER | WS_VISIBLE | style, 0, 0, 300, 400, - parent_window, NULL, GetModuleHandleA(NULL), NULL); + parent_wnd, NULL, GetModuleHandleA(NULL), NULL); - if (!hwnd) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!hwnd) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, - (LONG_PTR)monthcal_subclass_proc); - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)monthcal_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0); return hwnd; } @@ -506,9 +629,12 @@ static HWND create_monthcal_control(DWORD style, HWND parent_window) /* Setter and Getters Tests */ -static void test_monthcal_color(HWND hwnd) +static void test_monthcal_color(void) { int res, temp; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -574,12 +700,17 @@ static void test_monthcal_color(HWND hwnd) expect(RGB(255,255,255), temp); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE); + + DestroyWindow(hwnd); } -static void test_monthcal_currDate(HWND hwnd) +static void test_monthcal_currdate(void) { SYSTEMTIME st_original, st_new, st_test; int res; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -629,28 +760,94 @@ static void test_monthcal_currDate(HWND hwnd) expect(st_original.wYear, st_new.wYear); expect(st_original.wMonth, st_new.wMonth); expect(st_original.wDay, st_new.wDay); - expect(st_original.wHour, st_new.wHour); - expect(st_original.wMinute, st_new.wMinute); - expect(st_original.wSecond, st_new.wSecond); + ok(st_original.wHour == st_new.wHour || + broken(0 == st_new.wHour), /* comctl32 <= 4.70 */ + "Expected %d, got %d\n", st_original.wHour, st_new.wHour); + ok(st_original.wMinute == st_new.wMinute || + broken(0 == st_new.wMinute), /* comctl32 <= 4.70 */ + "Expected %d, got %d\n", st_original.wMinute, st_new.wMinute); + ok(st_original.wSecond == st_new.wSecond || + broken(0 == st_new.wSecond), /* comctl32 <= 4.70 */ + "Expected %d, got %d\n", st_original.wSecond, st_new.wSecond); /* lparam cannot be NULL */ res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0); expect(0, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE); + + /* December, 31, 9999 is the maximum allowed date */ + memset(&st_new, 0, sizeof(st_new)); + st_new.wYear = 9999; + st_new.wMonth = 12; + st_new.wDay = 31; + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new); + expect(1, res); + memset(&st_test, 0, sizeof(st_test)); + res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test); + expect(1, res); + expect(st_new.wYear, st_test.wYear); + expect(st_new.wMonth, st_test.wMonth); + expect(st_new.wDay, st_test.wDay); + expect(st_new.wHour, st_test.wHour); + expect(st_new.wMinute, st_test.wMinute); + expect(st_new.wSecond, st_test.wSecond); + /* try one day later */ + st_original = st_new; + st_new.wYear = 10000; + st_new.wMonth = 1; + st_new.wDay = 1; + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new); + ok(0 == res || + broken(1 == res), /* comctl32 <= 4.72 */ + "Expected 0, got %d\n", res); + if (0 == res) + { + memset(&st_test, 0, sizeof(st_test)); + res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test); + expect(1, res); + expect(st_original.wYear, st_test.wYear); + expect(st_original.wMonth, st_test.wMonth); + expect(st_original.wDay, st_test.wDay); + expect(st_original.wHour, st_test.wHour); + expect(st_original.wMinute, st_test.wMinute); + expect(st_original.wSecond, st_test.wSecond); + } + + /* setting selection equal to current reports success even if out range */ + memset(&st_new, 0, sizeof(st_new)); + st_new.wYear = 2009; + st_new.wDay = 5; + st_new.wMonth = 10; + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new); + expect(1, res); + memset(&st_test, 0, sizeof(st_test)); + st_test.wYear = 2009; + st_test.wDay = 6; + st_test.wMonth = 10; + res = SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)&st_test); + expect(1, res); + /* set to current again */ + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new); + expect(1, res); + + DestroyWindow(hwnd); } -static void test_monthcal_firstDay(HWND hwnd) +static void test_monthcal_firstDay(void) { int res, fday, i, prev; - TCHAR b[128]; + CHAR b[128]; LCID lcid = LOCALE_USER_DEFAULT; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); /* Setter and Getters for first day of week */ /* check for locale first day */ - if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){ + if(GetLocaleInfoA(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){ fday = atoi(b); trace("fday: %d\n", fday); res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); @@ -660,7 +857,7 @@ static void test_monthcal_firstDay(HWND hwnd) /* checking for the values that actually will be stored as */ /* current first day when we set a new value */ for (i = -5; i < 12; i++){ - res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i); + res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, i); expect(prev, res); res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); prev = res; @@ -681,11 +878,15 @@ static void test_monthcal_firstDay(HWND hwnd) skip("Cannot retrieve first day of the week\n"); } + DestroyWindow(hwnd); } -static void test_monthcal_unicode(HWND hwnd) +static void test_monthcal_unicode(void) { int res, temp; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -700,11 +901,15 @@ static void test_monthcal_unicode(HWND hwnd) /* current setting is 1, so, should return 1 */ res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); - todo_wine {expect(1, res);} + ok(1 == res || + broken(0 == res), /* comctl32 <= 4.70 */ + "Expected 1, got %d\n", res); /* setting to 0, should return previous settings */ res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0); - todo_wine {expect(1, res);} + ok(1 == res || + broken(0 == res), /* comctl32 <= 4.70 */ + "Expected 1, got %d\n", res); /* current setting is 0, so, it should return 0 */ res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); @@ -715,22 +920,67 @@ static void test_monthcal_unicode(HWND hwnd) expect(0, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE); + + DestroyWindow(hwnd); } -static void test_monthcal_HitTest(HWND hwnd) +static void test_monthcal_hittest(void) { + typedef struct hittest_test + { + UINT ht; + int todo; + } hittest_test_t; + + static const hittest_test_t title_hits[] = { + /* Start is the same everywhere */ + { MCHT_TITLE, 0 }, + { MCHT_TITLEBTNPREV, 0 }, + /* The middle piece is only tested for presence of items */ + /* End is the same everywhere */ + { MCHT_TITLEBTNNEXT, 0 }, + { MCHT_TITLE, 0 }, + { MCHT_NOWHERE, 1 } + }; + MCHITTESTINFO mchit; - UINT res; + UINT res, old_res; SYSTEMTIME st; LONG x; UINT title_index; - static const UINT title_hits[] = - { MCHT_NOWHERE, MCHT_TITLEBK, MCHT_TITLEBTNPREV, MCHT_TITLEBK, - MCHT_TITLEMONTH, MCHT_TITLEBK, MCHT_TITLEYEAR, MCHT_TITLEBK, - MCHT_TITLEBTNNEXT, MCHT_TITLEBK, MCHT_NOWHERE }; + HWND hwnd; + RECT r; + char yearmonth[80], *locale_month, *locale_year; + int month_count, year_count; + BOOL in_the_middle; memset(&mchit, 0, sizeof(MCHITTESTINFO)); + hwnd = create_monthcal_control(0); + + /* test with invalid structure size */ + mchit.cbSize = MCHITTESTINFO_V1_SIZE - 1; + mchit.pt.x = 0; + mchit.pt.y = 0; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit); + expect(0, mchit.pt.x); + expect(0, mchit.pt.y); + expect(-1, res); + expect(0, mchit.uHit); + /* test with invalid pointer */ + res = SendMessage(hwnd, MCM_HITTEST, 0, 0); + expect(-1, res); + + /* resize control to display single Calendar */ + res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r); + if (res == 0) + { + win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n"); + DestroyWindow(hwnd); + return; + } + MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE); + flush_sequences(sequences, NUM_MSG_SEQUENCES); st.wYear = 2007; @@ -745,60 +995,60 @@ static void test_monthcal_HitTest(HWND hwnd) res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st); expect(1,res); - /* (0, 0) is the top left of the control and should not be active */ - mchit.cbSize = sizeof(MCHITTESTINFO); + /* (0, 0) is the top left of the control - title */ + mchit.cbSize = MCHITTESTINFO_V1_SIZE; mchit.pt.x = 0; mchit.pt.y = 0; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit); expect(0, mchit.pt.x); expect(0, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_NOWHERE, res);} + expect_hex(MCHT_TITLE, res); - /* (300, 400) is the bottom right of the control and should not be active */ - mchit.pt.x = 300; - mchit.pt.y = 400; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(300, mchit.pt.x); - expect(400, mchit.pt.y); + /* bottom right of the control and should not be active */ + mchit.pt.x = r.right; + mchit.pt.y = r.bottom; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit); + expect(r.right, mchit.pt.x); + expect(r.bottom, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_NOWHERE, res);} + todo_wine expect_hex(MCHT_NOWHERE, res); - /* (500, 500) is completely out of the control and should not be active */ - mchit.pt.x = 500; - mchit.pt.y = 500; + /* completely out of the control, should not be active */ + mchit.pt.x = 2 * r.right; + mchit.pt.y = 2 * r.bottom; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(500, mchit.pt.x); - expect(500, mchit.pt.y); + expect(2 * r.right, mchit.pt.x); + expect(2 * r.bottom, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_NOWHERE, res);} + todo_wine expect_hex(MCHT_NOWHERE, res); - /* (120, 180) is in active area - calendar background */ - mchit.pt.x = 120; - mchit.pt.y = 180; + /* in active area - day of the week */ + mchit.pt.x = r.right / 2; + mchit.pt.y = r.bottom / 2; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(120, mchit.pt.x); - expect(180, mchit.pt.y); + expect(r.right / 2, mchit.pt.x); + expect(r.bottom / 2, mchit.pt.y); expect(mchit.uHit, res); - expect(MCHT_CALENDARBK, res); + expect_hex(MCHT_CALENDARDATE, res); - /* (70, 70) is in active area - day of the week */ - mchit.pt.x = 70; - mchit.pt.y = 70; + /* in active area - day of the week #2 */ + mchit.pt.x = r.right / 14; /* half of first day rect */ + mchit.pt.y = r.bottom / 2; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(70, mchit.pt.x); - expect(70, mchit.pt.y); + expect(r.right / 14, mchit.pt.x); + expect(r.bottom / 2, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_CALENDARDAY, res);} + expect_hex(MCHT_CALENDARDATE, res); - /* (70, 90) is in active area - date from prev month */ - mchit.pt.x = 70; - mchit.pt.y = 90; + /* in active area - date from prev month */ + mchit.pt.x = r.right / 14; /* half of first day rect */ + mchit.pt.y = 6 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(70, mchit.pt.x); - expect(90, mchit.pt.y); + expect(r.right / 14, mchit.pt.x); + expect(6 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_CALENDARDATEPREV, res);} + expect_hex(MCHT_CALENDARDATEPREV, res); #if 0 /* (125, 115) is in active area - date from this month */ @@ -811,142 +1061,164 @@ static void test_monthcal_HitTest(HWND hwnd) expect(MCHT_CALENDARDATE, res); #endif - /* (80, 220) is in active area - background section of the title */ - mchit.pt.x = 80; - mchit.pt.y = 220; + /* in active area - date from next month */ + mchit.pt.x = 11 * r.right / 14; + mchit.pt.y = 16 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(80, mchit.pt.x); - expect(220, mchit.pt.y); + expect(11 * r.right / 14, mchit.pt.x); + expect(16 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEBK, res);} + expect_hex(MCHT_CALENDARDATENEXT, res); - /* (140, 215) is in active area - month section of the title */ - mchit.pt.x = 140; - mchit.pt.y = 215; + /* in active area - today link */ + mchit.pt.x = r.right / 14; + mchit.pt.y = 18 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(140, mchit.pt.x); - expect(215, mchit.pt.y); + expect(r.right / 14, mchit.pt.x); + expect(18 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEMONTH, res);} + expect_hex(MCHT_TODAYLINK, res); - /* (170, 215) is in active area - year section of the title */ - mchit.pt.x = 170; - mchit.pt.y = 215; + /* in active area - today link */ + mchit.pt.x = r.right / 2; + mchit.pt.y = 18 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(170, mchit.pt.x); - expect(215, mchit.pt.y); + expect(r.right / 2, mchit.pt.x); + expect(18 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEYEAR, res);} + expect_hex(MCHT_TODAYLINK, res); - /* (150, 260) is in active area - date from this month */ - mchit.pt.x = 150; - mchit.pt.y = 260; + /* in active area - today link */ + mchit.pt.x = r.right / 10; + mchit.pt.y = 18 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(150, mchit.pt.x); - expect(260, mchit.pt.y); + expect(r.right / 10, mchit.pt.x); + expect(18 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_CALENDARDATE, res);} - - /* (150, 350) is in active area - date from next month */ - mchit.pt.x = 150; - mchit.pt.y = 350; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(150, mchit.pt.x); - expect(350, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_CALENDARDATENEXT, res);} - - /* (150, 370) is in active area - today link */ - mchit.pt.x = 150; - mchit.pt.y = 370; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(150, mchit.pt.x); - expect(370, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TODAYLINK, res);} - - /* (70, 370) is in active area - today link */ - mchit.pt.x = 70; - mchit.pt.y = 370; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(70, mchit.pt.x); - expect(370, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TODAYLINK, res);} + expect_hex(MCHT_TODAYLINK, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE); /* The horizontal position of title bar elements depends on locale (y pos is constant), so we sample across a horizontal line and make sure we find all elements. */ - mchit.pt.y = 40; + + /* Get the format of the title */ + GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, yearmonth, 80); + /* Find out if we have a month and/or year */ + locale_year = strstr(yearmonth, "y"); + locale_month = strstr(yearmonth, "M"); + + mchit.pt.x = 0; + mchit.pt.y = (5/2) * r.bottom / 19; title_index = 0; - for (x = 0; x < 300; x++){ + old_res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect_hex(title_hits[title_index].ht, old_res); + + in_the_middle = FALSE; + month_count = year_count = 0; + for (x = 0; x < r.right; x++){ mchit.pt.x = x; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); expect(x, mchit.pt.x); - expect(40, mchit.pt.y); + expect((5/2) * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - if (res != title_hits[title_index]){ - title_index++; - if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index) - break; - todo_wine {expect(title_hits[title_index], res);} + if (res != old_res) { + + if (old_res == MCHT_TITLEBTNPREV) + in_the_middle = TRUE; + + if (res == MCHT_TITLEBTNNEXT) + in_the_middle = FALSE; + + if (in_the_middle) { + if (res == MCHT_TITLEMONTH) + month_count++; + else if (res == MCHT_TITLEYEAR) + year_count++; + } else { + title_index++; + + if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index) + break; + + if (title_hits[title_index].todo) { + todo_wine + ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n", + title_hits[title_index].ht, res, x); + } else { + ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n", + title_hits[title_index].ht, res, x); + } + } + old_res = res; } } - todo_wine {ok(300 <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]), - "Wrong title layout\n");} + + /* There are some limits, even if LOCALE_SYEARMONTH contains rubbish + * or no month/year indicators at all */ + if (locale_month) + todo_wine ok(month_count == 1, "Expected 1 month item, got %d\n", month_count); + else + ok(month_count <= 1, "Too many month items: %d\n", month_count); + + if (locale_year) + todo_wine ok(year_count == 1, "Expected 1 year item, got %d\n", year_count); + else + ok(year_count <= 1, "Too many year items: %d\n", year_count); + + todo_wine ok(month_count + year_count >= 1, "Not enough month and year items\n"); + + ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]), + "Wrong title layout\n"); + + DestroyWindow(hwnd); } -static void test_monthcal_todaylink(HWND hwnd) +static void test_monthcal_todaylink(void) { MCHITTESTINFO mchit; SYSTEMTIME st_test, st_new; - BOOL error = FALSE; UINT res; + HWND hwnd; + RECT r; memset(&mchit, 0, sizeof(MCHITTESTINFO)); + hwnd = create_monthcal_control(0); + + res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r); + MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE); + flush_sequences(sequences, NUM_MSG_SEQUENCES); - /* (70, 370) is in active area - today link */ - mchit.cbSize = sizeof(MCHITTESTINFO); - mchit.pt.x = 70; - mchit.pt.y = 370; + /* hit active area - today link */ + mchit.cbSize = MCHITTESTINFO_V1_SIZE; + mchit.pt.x = r.right / 14; + mchit.pt.y = 18 * r.bottom / 19; res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(70, mchit.pt.x); - expect(370, mchit.pt.y); + expect(r.right / 14, mchit.pt.x); + expect(18 * r.bottom / 19, mchit.pt.y); expect(mchit.uHit, res); - todo_wine {expect(MCHT_TODAYLINK, res);} - if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res - || MCHT_TODAYLINK != res) - error = TRUE; + expect(MCHT_TODAYLINK, res); st_test.wDay = 1; st_test.wMonth = 1; st_test.wYear = 2005; - memset(&st_new, 0, sizeof(SYSTEMTIME)); SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test); + memset(&st_new, 0, sizeof(st_new)); res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new); expect(1, res); expect(1, st_new.wDay); expect(1, st_new.wMonth); expect(2005, st_new.wYear); - if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth - || 2005 != st_new.wYear) - error = TRUE; - if (error) { - skip("cannot perform today link test\n"); - return; - } - - res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370)); + res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(mchit.pt.x, mchit.pt.y)); expect(0, res); - memset(&st_new, 0, sizeof(SYSTEMTIME)); + memset(&st_new, 0, sizeof(st_new)); res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new); expect(1, res); expect(1, st_new.wDay); @@ -954,18 +1226,24 @@ static void test_monthcal_todaylink(HWND hwnd) expect(2005, st_new.wYear); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE); + + DestroyWindow(hwnd); } -static void test_monthcal_today(HWND hwnd) +static void test_monthcal_today(void) { SYSTEMTIME st_test, st_new; int res; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); /* Setter and Getters for "today" information */ /* check for overflow, should be ok */ + memset(&st_test, 0, sizeof(st_test)); st_test.wDay = 38; st_test.wMonth = 38; @@ -1003,11 +1281,16 @@ static void test_monthcal_today(HWND hwnd) expect(0, st_new.wMonth); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE); + + DestroyWindow(hwnd); } -static void test_monthcal_scroll(HWND hwnd) +static void test_monthcal_scroll(void) { int res; + HWND hwnd; + + hwnd = create_monthcal_control(0); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -1036,46 +1319,138 @@ static void test_monthcal_scroll(HWND hwnd) expect(-5, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE); + + DestroyWindow(hwnd); } -static void test_monthcal_monthrange(HWND hwnd) +static void test_monthcal_monthrange(void) { int res; - SYSTEMTIME st_visible[2], st_daystate[2]; + SYSTEMTIME st_visible[2], st_daystate[2], st; + HWND hwnd; + RECT r; + + hwnd = create_monthcal_control(0); - flush_sequences(sequences, NUM_MSG_SEQUENCES); st_visible[0].wYear = 0; st_visible[0].wMonth = 0; st_visible[0].wDay = 0; st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0]; + st.wYear = 2000; + st.wMonth = 11; + st.wDay = 28; + st.wHour = 11; + st.wMinute = 59; + st.wSecond = 30; + st.wMilliseconds = 0; + st.wDayOfWeek = 0; + + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st); + expect(1,res); + + /* to be locale independent */ + SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6); + + res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r); + expect(TRUE, res); + /* resize control to display two Calendars */ + MoveWindow(hwnd, 0, 0, r.right, (5/2)*r.bottom, FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible); todo_wine { expect(2, res); - expect(2000, st_visible[0].wYear); - expect(11, st_visible[0].wMonth); - expect(1, st_visible[0].wDay); - expect(2000, st_visible[1].wYear); + } + expect(2000, st_visible[0].wYear); + expect(11, st_visible[0].wMonth); + expect(1, st_visible[0].wDay); + expect(2000, st_visible[1].wYear); + + todo_wine { expect(12, st_visible[1].wMonth); expect(31, st_visible[1].wDay); } res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate); todo_wine { expect(4, res); - expect(2000, st_daystate[0].wYear); - expect(10, st_daystate[0].wMonth); - expect(29, st_daystate[0].wDay); + } + expect(2000, st_daystate[0].wYear); + expect(10, st_daystate[0].wMonth); + expect(29, st_daystate[0].wDay); + + todo_wine { expect(2001, st_daystate[1].wYear); expect(1, st_daystate[1].wMonth); expect(6, st_daystate[1].wDay); } ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE); + + /* resize control to display single Calendar */ + MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE); + + memset(&st, 0, sizeof(st)); + st.wMonth = 9; + st.wYear = 1752; + st.wDay = 14; + + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st); + expect(1, res); + + /* September 1752 has 19 days */ + res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible); + expect(1, res); + + expect(1752, st_visible[0].wYear); + expect(9, st_visible[0].wMonth); + ok(14 == st_visible[0].wDay || + broken(1 == st_visible[0].wDay), /* comctl32 <= 4.72 */ + "Expected 14, got %d\n", st_visible[0].wDay); + + expect(1752, st_visible[1].wYear); + expect(9, st_visible[1].wMonth); + expect(19, st_visible[1].wDay); + + DestroyWindow(hwnd); } -static void test_monthcal_MaxSelDay(HWND hwnd) +static void test_monthcal_maxselday(void) { int res; + HWND hwnd; + DWORD style; + + hwnd = create_monthcal_control(0); + /* if no style specified default to 1 */ + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(1, res); + res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0); + expect(0, res); + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(1, res); + + /* try to set style */ + style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style | MCS_MULTISELECT); + style = GetWindowLong(hwnd, GWL_STYLE); + ok(!(style & MCS_MULTISELECT), "Expected MCS_MULTISELECT not to be set\n"); + DestroyWindow(hwnd); + + hwnd = create_monthcal_control(MCS_MULTISELECT); + /* try to remove style */ + style = GetWindowLong(hwnd, GWL_STYLE); + SetWindowLong(hwnd, GWL_STYLE, style & ~MCS_MULTISELECT); + style = GetWindowLong(hwnd, GWL_STYLE); + ok(style & MCS_MULTISELECT, "Expected MCS_MULTISELECT to be set\n"); + DestroyWindow(hwnd); + + hwnd = create_monthcal_control(MCS_MULTISELECT); + + /* default width is a week */ + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(7, res); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -1090,20 +1465,32 @@ static void test_monthcal_MaxSelDay(HWND hwnd) res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); expect(15, res); + /* test invalid value */ res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0); - todo_wine {expect(0, res);} + expect(0, res); res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); - todo_wine {expect(15, res);} + expect(15, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE); + + /* zero value is invalid too */ + res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 0, 0); + expect(0, res); + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(15, res); + + DestroyWindow(hwnd); } -static void test_monthcal_size(HWND hwnd) +static void test_monthcal_size(void) { int res; RECT r1, r2; HFONT hFont1, hFont2; LOGFONTA logfont; + HWND hwnd; + + hwnd = create_monthcal_control(0); lstrcpyA(logfont.lfFaceName, "Arial"); memset(&logfont, 0, sizeof(logfont)); @@ -1116,15 +1503,181 @@ static void test_monthcal_size(HWND hwnd) /* initialize to a font we can compare against */ SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0); res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1); + ok(res, "SendMessage(MCM_GETMINREQRECT) failed\n"); /* check that setting a larger font results in an larger rect */ SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0); res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2); + ok(res, "SendMessage(MCM_GETMINREQRECT) failed\n"); OffsetRect(&r1, -r1.left, -r1.top); OffsetRect(&r2, -r2.left, -r2.top); ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n"); + + DestroyWindow(hwnd); +} + +static void test_monthcal_create(void) +{ + HWND hwnd; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + hwnd = create_monthcal_control(0); + ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE); + + DestroyWindow(hwnd); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hwnd = create_monthcal_control(MCS_MULTISELECT); + ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE); + DestroyWindow(hwnd); +} + +static void test_monthcal_destroy(void) +{ + HWND hwnd; + + hwnd = create_monthcal_control(0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); + ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE); + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE); + + /* MCS_MULTISELECT */ + hwnd = create_monthcal_control(MCS_MULTISELECT); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE); +} + +static void test_monthcal_selrange(void) +{ + HWND hwnd; + SYSTEMTIME st, range[2], range2[2]; + BOOL ret, old_comctl32 = FALSE; + + hwnd = create_monthcal_control(MCS_MULTISELECT); + + /* just after creation selection should start and end today */ + ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st); + expect(TRUE, ret); + + memset(range, 0xcc, sizeof(range)); + ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range); + expect(TRUE, ret); + expect(st.wYear, range[0].wYear); + expect(st.wMonth, range[0].wMonth); + expect(st.wDay, range[0].wDay); + if (range[0].wDayOfWeek != st.wDayOfWeek) + { + win_skip("comctl32 <= 4.70 doesn't set some values\n"); + old_comctl32 = TRUE; + } + else + { + expect(st.wDayOfWeek, range[0].wDayOfWeek); + expect(st.wHour, range[0].wHour); + expect(st.wMinute, range[0].wMinute); + expect(st.wSecond, range[0].wSecond); + expect(st.wMilliseconds, range[0].wMilliseconds); + } + + expect(st.wYear, range[1].wYear); + expect(st.wMonth, range[1].wMonth); + expect(st.wDay, range[1].wDay); + if (!old_comctl32) + { + expect(st.wDayOfWeek, range[1].wDayOfWeek); + expect(st.wHour, range[1].wHour); + expect(st.wMinute, range[1].wMinute); + expect(st.wSecond, range[1].wSecond); + expect(st.wMilliseconds, range[1].wMilliseconds); + } + + /* bounds are swapped if min > max */ + memset(&range[0], 0, sizeof(range[0])); + range[0].wYear = 2009; + range[0].wMonth = 10; + range[0].wDay = 5; + range[1] = range[0]; + range[1].wDay = 3; + + ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range); + expect(TRUE, ret); + + ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2); + expect(TRUE, ret); + + expect(range[1].wYear, range2[0].wYear); + expect(range[1].wMonth, range2[0].wMonth); + expect(range[1].wDay, range2[0].wDay); + expect(6, range2[0].wDayOfWeek); + expect(range[1].wHour, range2[0].wHour); + expect(range[1].wMinute, range2[0].wMinute); + expect(range[1].wSecond, range2[0].wSecond); + expect(range[1].wMilliseconds, range2[0].wMilliseconds); + + expect(range[0].wYear, range2[1].wYear); + expect(range[0].wMonth, range2[1].wMonth); + expect(range[0].wDay, range2[1].wDay); + expect(1, range2[1].wDayOfWeek); + expect(range[0].wHour, range2[1].wHour); + expect(range[0].wMinute, range2[1].wMinute); + expect(range[0].wSecond, range2[1].wSecond); + expect(range[0].wMilliseconds, range2[1].wMilliseconds); + + /* try with range larger than maximum configured */ + memset(&range[0], 0, sizeof(range[0])); + range[0].wYear = 2009; + range[0].wMonth = 10; + range[0].wDay = 1; + range[1] = range[0]; + + ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range); + expect(TRUE, ret); + + range[1] = range[0]; + /* default max. range is 7 days */ + range[1].wDay = 8; + + ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range); + expect(FALSE, ret); + + ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2); + expect(TRUE, ret); + + expect(range[0].wYear, range2[0].wYear); + expect(range[0].wMonth, range2[0].wMonth); + expect(range[0].wDay, range2[0].wDay); + expect(range[0].wYear, range2[1].wYear); + expect(range[0].wMonth, range2[1].wMonth); + expect(range[0].wDay, range2[1].wDay); + + DestroyWindow(hwnd); +} + +static void test_killfocus(void) +{ + HWND hwnd; + DWORD style; + + hwnd = create_monthcal_control(0); + + /* make parent invisible */ + style = GetWindowLong(parent_wnd, GWL_STYLE); + SetWindowLong(parent_wnd, GWL_STYLE, style &~ WS_VISIBLE); + + SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)GetDesktopWindow(), 0); + + style = GetWindowLong(hwnd, GWL_STYLE); + ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n"); + + style = GetWindowLong(parent_wnd, GWL_STYLE); + SetWindowLong(parent_wnd, GWL_STYLE, style | WS_VISIBLE); + + DestroyWindow(hwnd); } START_TEST(monthcal) @@ -1132,7 +1685,6 @@ START_TEST(monthcal) HMODULE hComctl32; BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); INITCOMMONCONTROLSEX iccex; - HWND hwnd, parent_wnd; hComctl32 = GetModuleHandleA("comctl32.dll"); pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); @@ -1151,39 +1703,21 @@ START_TEST(monthcal) parent_wnd = create_parent_window(); - flush_sequences(sequences, NUM_MSG_SEQUENCES); - hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd); - assert(hwnd); - ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE); - - SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0); - - test_monthcal_color(hwnd); - test_monthcal_currDate(hwnd); - test_monthcal_firstDay(hwnd); - test_monthcal_unicode(hwnd); - test_monthcal_today(hwnd); - test_monthcal_scroll(hwnd); - test_monthcal_monthrange(hwnd); - test_monthcal_HitTest(hwnd); - test_monthcal_todaylink(hwnd); - test_monthcal_size(hwnd); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - DestroyWindow(hwnd); - ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE); - ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd); - assert(hwnd); - ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE); - - test_monthcal_MaxSelDay(hwnd); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - DestroyWindow(hwnd); - ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE); + test_monthcal_create(); + test_monthcal_destroy(); + test_monthcal_color(); + test_monthcal_currdate(); + test_monthcal_firstDay(); + test_monthcal_unicode(); + test_monthcal_today(); + test_monthcal_scroll(); + test_monthcal_monthrange(); + test_monthcal_hittest(); + test_monthcal_todaylink(); + test_monthcal_size(); + test_monthcal_maxselday(); + test_monthcal_selrange(); + test_killfocus(); flush_sequences(sequences, NUM_MSG_SEQUENCES); DestroyWindow(parent_wnd); diff --git a/rostests/winetests/comctl32/mru.c b/rostests/winetests/comctl32/mru.c index 8ebec86f148..24fcff56d68 100644 --- a/rostests/winetests/comctl32/mru.c +++ b/rostests/winetests/comctl32/mru.c @@ -69,11 +69,27 @@ static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA); static void (WINAPI *pFreeMRUList)(HANDLE); static INT (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR); static INT (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD); +static INT (WINAPI *pEnumMRUListW)(HANDLE,INT,LPVOID,DWORD); +static HANDLE (WINAPI *pCreateMRUListLazyA)(LPCREATEMRULISTA, DWORD, DWORD, DWORD); +static INT (WINAPI *pFindMRUData)(HANDLE, LPCVOID, DWORD, LPINT); +static INT (WINAPI *pAddMRUData)(HANDLE, LPCVOID, DWORD); /* static INT (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT); */ +static void InitPointers(void) +{ + pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151); + pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152); + pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153); + pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154); + pCreateMRUListLazyA = (void*)GetProcAddress(hComctl32,(LPCSTR)157); + pAddMRUData = (void*)GetProcAddress(hComctl32,(LPCSTR)167); + pFindMRUData = (void*)GetProcAddress(hComctl32,(LPCSTR)169); + pEnumMRUListW = (void*)GetProcAddress(hComctl32,(LPCSTR)403); +} + /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */ static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) { @@ -227,11 +243,6 @@ static void test_MRUListA(void) HKEY hKey; INT iRet; - pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151); - pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152); - pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153); - pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154); - if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList) { skip("MRU entry points not found\n"); @@ -374,7 +385,7 @@ static void test_MRUListA(void) /* check entry 0 */ buffer[0] = 0; iRet = pEnumMRUList(hMRU, 0, buffer, 255); - todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet); + ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet); ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer); /* check entry 0 with a too small buffer */ @@ -383,21 +394,21 @@ static void test_MRUListA(void) buffer[2] = 'A'; /* unchanged */ buffer[3] = 0; /* unchanged */ iRet = pEnumMRUList(hMRU, 0, buffer, 2); - todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet); - todo_wine ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer); + ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet); + ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer); /* make sure space after buffer has old values */ ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]); /* check entry 1 */ buffer[0] = 0; iRet = pEnumMRUList(hMRU, 1, buffer, 255); - todo_wine ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet); + ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet); ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer); /* check entry 2 */ buffer[0] = 0; iRet = pEnumMRUList(hMRU, 2, buffer, 255); - todo_wine ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet); + ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet); ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer); /* check out of bounds entry 3 */ @@ -413,6 +424,89 @@ static void test_MRUListA(void) /* FreeMRUList(NULL) crashes on Win98 OSR0 */ } +static void test_CreateMRUListLazyA(void) +{ + HANDLE hMRU; + HKEY hKey; + CREATEMRULISTA listA = { 0 }; + + if (!pCreateMRUListLazyA || !pFreeMRUList) + { + win_skip("CreateMRUListLazyA or FreeMRUList entry points not found\n"); + return; + } + + /* wrong size */ + listA.cbSize = sizeof(listA) + 1; + hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0); + ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU); + listA.cbSize = 4; + hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0); + ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU); + /* NULL hKey */ + listA.cbSize = sizeof(listA); + listA.hKey = NULL; + hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0); + ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU); + /* NULL subkey */ + ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey), + "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); + listA.cbSize = sizeof(listA); + listA.hKey = hKey; + listA.lpszSubKey = NULL; + hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0); + ok(hMRU == NULL || broken(hMRU != NULL), /* Win9x */ + "Expected NULL handle, got %p\n", hMRU); + if (hMRU) pFreeMRUList(hMRU); +} + +static void test_EnumMRUList(void) +{ + if (!pEnumMRUList || !pEnumMRUListW) + { + win_skip("EnumMRUListA/EnumMRUListW entry point not found\n"); + return; + } + + /* NULL handle */ + if (0) + { + /* crashes on NT4, passed on Win2k, XP, 2k3, Vista, 2k8 */ + pEnumMRUList(NULL, 0, NULL, 0); + pEnumMRUListW(NULL, 0, NULL, 0); + } +} + +static void test_FindMRUData(void) +{ + INT iRet; + + if (!pFindMRUData) + { + win_skip("FindMRUData entry point not found\n"); + return; + } + + /* NULL handle */ + iRet = pFindMRUData(NULL, NULL, 0, NULL); + ok(iRet == -1, "FindMRUData expected -1, got %d\n", iRet); +} + +static void test_AddMRUData(void) +{ + INT iRet; + + if (!pAddMRUData) + { + win_skip("AddMRUData entry point not found\n"); + return; + } + + /* NULL handle */ + iRet = pFindMRUData(NULL, NULL, 0, NULL); + ok(iRet == -1, "AddMRUData expected -1, got %d\n", iRet); +} + START_TEST(mru) { hComctl32 = GetModuleHandleA("comctl32.dll"); @@ -421,7 +515,13 @@ START_TEST(mru) if (!create_reg_entries()) return; + InitPointers(); + test_MRUListA(); + test_CreateMRUListLazyA(); + test_EnumMRUList(); + test_FindMRUData(); + test_AddMRUData(); delete_reg_entries(); } diff --git a/rostests/winetests/comctl32/msg.c b/rostests/winetests/comctl32/msg.c deleted file mode 100644 index 2129f222e01..00000000000 --- a/rostests/winetests/comctl32/msg.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Message Sequence Testing Code - * - * Copyright (C) 2007 James Hawkins - * Copyright (C) 2007 Lei Zhang - * - * 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 "msg.h" - -void add_message(struct msg_sequence **seq, int sequence_index, - const struct message *msg) -{ - struct msg_sequence *msg_seq = seq[sequence_index]; - - if (!msg_seq->sequence) - { - msg_seq->size = 10; - msg_seq->sequence = HeapAlloc(GetProcessHeap(), 0, - msg_seq->size * sizeof (struct message)); - } - - if (msg_seq->count == msg_seq->size) - { - msg_seq->size *= 2; - msg_seq->sequence = HeapReAlloc(GetProcessHeap(), 0, - msg_seq->sequence, - msg_seq->size * sizeof (struct message)); - } - - assert(msg_seq->sequence); - - msg_seq->sequence[msg_seq->count].message = msg->message; - msg_seq->sequence[msg_seq->count].flags = msg->flags; - msg_seq->sequence[msg_seq->count].wParam = msg->wParam; - msg_seq->sequence[msg_seq->count].lParam = msg->lParam; - msg_seq->sequence[msg_seq->count].id = msg->id; - - msg_seq->count++; -} - -void flush_sequence(struct msg_sequence **seg, int sequence_index) -{ - struct msg_sequence *msg_seq = seg[sequence_index]; - HeapFree(GetProcessHeap(), 0, msg_seq->sequence); - msg_seq->sequence = NULL; - msg_seq->count = msg_seq->size = 0; -} - -void flush_sequences(struct msg_sequence **seq, int n) -{ - int i; - - for (i = 0; i < n; i++) - flush_sequence(seq, i); -} - -void ok_sequence_(struct msg_sequence **seq, int sequence_index, - const struct message *expected, const char *context, int todo, - const char *file, int line) -{ - struct msg_sequence *msg_seq = seq[sequence_index]; - static const struct message end_of_sequence = {0, 0, 0, 0}; - const struct message *actual, *sequence; - int failcount = 0; - - add_message(seq, sequence_index, &end_of_sequence); - - sequence = msg_seq->sequence; - actual = sequence; - - while (expected->message && actual->message) - { - trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message); - - if (expected->message == actual->message) - { - if (expected->flags & wparam) - { - if (expected->wParam != actual->wParam && todo) - { - todo_wine - { - failcount++; - ok_(file, line) (FALSE, - "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, expected->message, expected->wParam, actual->wParam); - } - } - else - { - ok_(file, line) (expected->wParam == actual->wParam, - "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, expected->message, expected->wParam, actual->wParam); - } - } - - if (expected->flags & lparam) - { - if (expected->lParam != actual->lParam && todo) - { - todo_wine - { - failcount++; - ok_(file, line) (FALSE, - "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, expected->message, expected->lParam, actual->lParam); - } - } - else - { - ok_(file, line) (expected->lParam == actual->lParam, - "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, expected->message, expected->lParam, actual->lParam); - } - } - - if (expected->flags & id) - { - if (expected->id != actual->id && todo) - { - todo_wine - { - failcount++; - ok_(file, line) (FALSE, - "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", - context, expected->message, expected->id, actual->id); - } - } - else - { - ok_(file, line) (expected->id == actual->id, - "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", - context, expected->message, expected->id, actual->id); - } - } - - if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) - { - todo_wine - { - failcount++; - ok_(file, line) (FALSE, - "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); - } - } - else - { - ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), - "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); - } - - ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), - "%s: the msg 0x%04x should %shave been sent by BeginPaint\n", - context, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); - ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), - "%s: the msg 0x%04x should have been %s\n", - context, expected->message, (expected->flags & posted) ? "posted" : "sent"); - ok_(file, line) ((expected->flags & parent) == (actual->flags & parent), - "%s: the msg 0x%04x was expected in %s\n", - context, expected->message, (expected->flags & parent) ? "parent" : "child"); - ok_(file, line) ((expected->flags & hook) == (actual->flags & hook), - "%s: the msg 0x%04x should have been sent by a hook\n", - context, expected->message); - ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), - "%s: the msg 0x%04x should have been sent by a winevent hook\n", - context, expected->message); - expected++; - actual++; - } - else if (expected->flags & optional) - expected++; - else if (todo) - { - failcount++; - todo_wine - { - ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, expected->message, actual->message); - } - - flush_sequence(seq, sequence_index); - return; - } - else - { - ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, expected->message, actual->message); - expected++; - actual++; - } - } - - /* skip all optional trailing messages */ - while (expected->message && ((expected->flags & optional))) - expected++; - - if (todo) - { - todo_wine - { - if (expected->message || actual->message) - { - failcount++; - ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", - context, expected->message, actual->message); - } - } - } - else if (expected->message || actual->message) - { - ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", - context, expected->message, actual->message); - } - - if(todo && !failcount) /* succeeded yet marked todo */ - { - todo_wine - { - ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); - } - } - - flush_sequence(seq, sequence_index); -} - -void init_msg_sequences(struct msg_sequence **seq, int n) -{ - int i; - - for (i = 0; i < n; i++) - seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct msg_sequence)); -} - -START_TEST(msg) -{ -} diff --git a/rostests/winetests/comctl32/msg.h b/rostests/winetests/comctl32/msg.h index 2ec3ea17a85..361ccdbf598 100644 --- a/rostests/winetests/comctl32/msg.h +++ b/rostests/winetests/comctl32/msg.h @@ -47,7 +47,8 @@ struct message msg_flags_t flags; /* message props */ WPARAM wParam; /* expected value of wParam */ LPARAM lParam; /* expected value of lParam */ - UINT id; /* id of the window */ + UINT id; /* extra message data: id of the window, + notify code etc. */ }; struct msg_sequence @@ -57,17 +58,237 @@ struct msg_sequence struct message *sequence; }; -void add_message(struct msg_sequence **seq, int sequence_index, - const struct message *msg); -void flush_sequence(struct msg_sequence **seg, int sequence_index); -void flush_sequences(struct msg_sequence **seq, int n); +static void add_message(struct msg_sequence **seq, int sequence_index, + const struct message *msg) +{ + struct msg_sequence *msg_seq = seq[sequence_index]; + + if (!msg_seq->sequence) + { + msg_seq->size = 10; + msg_seq->sequence = HeapAlloc(GetProcessHeap(), 0, + msg_seq->size * sizeof (struct message)); + } + + if (msg_seq->count == msg_seq->size) + { + msg_seq->size *= 2; + msg_seq->sequence = HeapReAlloc(GetProcessHeap(), 0, + msg_seq->sequence, + msg_seq->size * sizeof (struct message)); + } + + assert(msg_seq->sequence); + + msg_seq->sequence[msg_seq->count].message = msg->message; + msg_seq->sequence[msg_seq->count].flags = msg->flags; + msg_seq->sequence[msg_seq->count].wParam = msg->wParam; + msg_seq->sequence[msg_seq->count].lParam = msg->lParam; + msg_seq->sequence[msg_seq->count].id = msg->id; + + msg_seq->count++; +} + +static void flush_sequence(struct msg_sequence **seg, int sequence_index) +{ + struct msg_sequence *msg_seq = seg[sequence_index]; + HeapFree(GetProcessHeap(), 0, msg_seq->sequence); + msg_seq->sequence = NULL; + msg_seq->count = msg_seq->size = 0; +} + +static void flush_sequences(struct msg_sequence **seq, int n) +{ + int i; + + for (i = 0; i < n; i++) + flush_sequence(seq, i); +} + +static void ok_sequence_(struct msg_sequence **seq, int sequence_index, + const struct message *expected, const char *context, int todo, + const char *file, int line) +{ + struct msg_sequence *msg_seq = seq[sequence_index]; + static const struct message end_of_sequence = {0, 0, 0, 0}; + const struct message *actual, *sequence; + int failcount = 0; + + add_message(seq, sequence_index, &end_of_sequence); + + sequence = msg_seq->sequence; + actual = sequence; + + while (expected->message && actual->message) + { + trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message); + + if (expected->message == actual->message) + { + if (expected->flags & wparam) + { + if (expected->wParam != actual->wParam && todo) + { + todo_wine + { + failcount++; + ok_(file, line) (FALSE, + "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + context, expected->message, expected->wParam, actual->wParam); + } + } + else + { + ok_(file, line) (expected->wParam == actual->wParam, + "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + context, expected->message, expected->wParam, actual->wParam); + } + } + + if (expected->flags & lparam) + { + if (expected->lParam != actual->lParam && todo) + { + todo_wine + { + failcount++; + ok_(file, line) (FALSE, + "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + context, expected->message, expected->lParam, actual->lParam); + } + } + else + { + ok_(file, line) (expected->lParam == actual->lParam, + "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + context, expected->message, expected->lParam, actual->lParam); + } + } + + if (expected->flags & id) + { + if (expected->id != actual->id && expected->flags & optional) + { + expected++; + continue; + } + if (expected->id != actual->id && todo) + { + todo_wine + { + failcount++; + ok_(file, line) (FALSE, + "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", + context, expected->message, expected->id, actual->id); + } + } + else + { + ok_(file, line) (expected->id == actual->id, + "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", + context, expected->message, expected->id, actual->id); + } + } + + if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) + { + todo_wine + { + failcount++; + ok_(file, line) (FALSE, + "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", + context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + } + } + else + { + ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), + "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", + context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + } + + ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), + "%s: the msg 0x%04x should %shave been sent by BeginPaint\n", + context, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); + ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), + "%s: the msg 0x%04x should have been %s\n", + context, expected->message, (expected->flags & posted) ? "posted" : "sent"); + ok_(file, line) ((expected->flags & parent) == (actual->flags & parent), + "%s: the msg 0x%04x was expected in %s\n", + context, expected->message, (expected->flags & parent) ? "parent" : "child"); + ok_(file, line) ((expected->flags & hook) == (actual->flags & hook), + "%s: the msg 0x%04x should have been sent by a hook\n", + context, expected->message); + ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), + "%s: the msg 0x%04x should have been sent by a winevent hook\n", + context, expected->message); + expected++; + actual++; + } + else if (expected->flags & optional) + expected++; + else if (todo) + { + failcount++; + todo_wine + { + ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + context, expected->message, actual->message); + } + + flush_sequence(seq, sequence_index); + return; + } + else + { + ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + context, expected->message, actual->message); + expected++; + actual++; + } + } + + /* skip all optional trailing messages */ + while (expected->message && ((expected->flags & optional))) + expected++; + + if (todo) + { + todo_wine + { + if (expected->message || actual->message) + { + failcount++; + ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", + context, expected->message, actual->message); + } + } + } + else if (expected->message || actual->message) + { + ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", + context, expected->message, actual->message); + } + + if(todo && !failcount) /* succeeded yet marked todo */ + { + todo_wine + { + ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); + } + } + + flush_sequence(seq, sequence_index); +} #define ok_sequence(seq, index, exp, contx, todo) \ ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__) -void ok_sequence_(struct msg_sequence **seq, int sequence_index, - const struct message *expected, const char *context, int todo, - const char *file, int line); +static void init_msg_sequences(struct msg_sequence **seq, int n) +{ + int i; -void init_msg_sequences(struct msg_sequence **seq, int n); + for (i = 0; i < n; i++) + seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct msg_sequence)); +} diff --git a/rostests/winetests/comctl32/progress.c b/rostests/winetests/comctl32/progress.c index 10bbbef8a28..3083e8ba2e5 100644 --- a/rostests/winetests/comctl32/progress.c +++ b/rostests/winetests/comctl32/progress.c @@ -163,6 +163,7 @@ static void cleanup(void) static void test_redraw(void) { RECT client_rect; + LRESULT ret; SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0); @@ -184,7 +185,11 @@ static void test_redraw(void) /* PBM_STEPIT */ ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n"); ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n"); - ok((UINT)SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0) == 100, "PBM_GETPOS returned a wrong position\n"); + ret = SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0); + if (ret == 0) + win_skip("PBM_GETPOS needs comctl32 > 4.70\n"); + else + ok(ret == 100, "PBM_GETPOS returned a wrong position : %d\n", (UINT)ret); /* PBM_SETRANGE and PBM_SETRANGE32: Usually the progress bar doesn't repaint itself immediately. If the diff --git a/rostests/winetests/comctl32/propsheet.c b/rostests/winetests/comctl32/propsheet.c index 4164f68c60e..bf40db4f6ec 100644 --- a/rostests/winetests/comctl32/propsheet.c +++ b/rostests/winetests/comctl32/propsheet.c @@ -1,6 +1,7 @@ /* Unit test suite for property sheet control. * * Copyright 2006 Huw Davies + * Copyright 2009 Jan de Mooij * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +21,16 @@ #include #include +#include "resources.h" + #include "wine/test.h" static HWND parent; +static HWND sheethwnd; + +static LONG active_page = -1; + +#define IDC_APPLY_BUTTON 12321 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) { @@ -33,12 +41,13 @@ static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) char caption[256]; GetWindowTextA(hwnd, caption, sizeof(caption)); ok(!strcmp(caption,"test caption"), "caption: %s\n", caption); + sheethwnd = hwnd; return 0; } } return 0; } - + static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -64,6 +73,10 @@ static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, return FALSE; } } + case WM_NCDESTROY: + ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n"); + return TRUE; + default: return FALSE; } @@ -79,7 +92,7 @@ static void test_title(void) memset(&psp, 0, sizeof(psp)); psp.dwSize = sizeof(psp); psp.dwFlags = 0; - psp.hInstance = GetModuleHandleW(NULL); + psp.hInstance = GetModuleHandleA(NULL); U(psp).pszTemplate = "prop_page1"; U2(psp).pszIcon = NULL; psp.pfnDlgProc = page_dlg_proc; @@ -97,6 +110,12 @@ static void test_title(void) psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } DestroyWindow(hdlg); } @@ -110,7 +129,7 @@ static void test_nopage(void) memset(&psp, 0, sizeof(psp)); psp.dwSize = sizeof(psp); psp.dwFlags = 0; - psp.hInstance = GetModuleHandleW(NULL); + psp.hInstance = GetModuleHandleA(NULL); U(psp).pszTemplate = "prop_page1"; U2(psp).pszIcon = NULL; psp.pfnDlgProc = page_dlg_proc; @@ -128,6 +147,12 @@ static void test_nopage(void) psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } ShowWindow(hdlg,SW_NORMAL); SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0); RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); @@ -170,6 +195,7 @@ static void test_disableowner(void) HPROPSHEETPAGE hpsp[1]; PROPSHEETPAGEA psp; PROPSHEETHEADERA psh; + INT_PTR p; register_parent_wnd_class(); parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0); @@ -177,7 +203,7 @@ static void test_disableowner(void) memset(&psp, 0, sizeof(psp)); psp.dwSize = sizeof(psp); psp.dwFlags = 0; - psp.hInstance = GetModuleHandleW(NULL); + psp.hInstance = GetModuleHandleA(NULL); U(psp).pszTemplate = "prop_page1"; U2(psp).pszIcon = NULL; psp.pfnDlgProc = NULL; @@ -194,14 +220,227 @@ static void test_disableowner(void) U3(psh).phpage = hpsp; psh.pfnCallback = disableowner_callback; - PropertySheetA(&psh); + p = PropertySheetA(&psh); + todo_wine + ok(p == 0, "Expected 0, got %ld\n", p); ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n"); DestroyWindow(parent); } +static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg){ + case WM_NOTIFY: + { + LPNMHDR hdr = (LPNMHDR)lparam; + switch(hdr->code){ + case PSN_SETACTIVE: + active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); + return TRUE; + case PSN_KILLACTIVE: + /* prevent navigation away from the fourth page */ + if(active_page == 3){ + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + } + } + return FALSE; +} + +static void test_wiznavigation(void) +{ + HPROPSHEETPAGE hpsp[4]; + PROPSHEETPAGEA psp[4]; + PROPSHEETHEADERA psh; + HWND hdlg, control; + LONG_PTR controlID; + LRESULT defidres; + BOOL hwndtoindex_supported = TRUE; + const INT nextID = 12324; + const INT backID = 12323; + + /* create the property sheet pages */ + memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4); + + psp[0].dwSize = sizeof(PROPSHEETPAGEA); + psp[0].hInstance = GetModuleHandleA(NULL); + U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO); + psp[0].pfnDlgProc = nav_page_proc; + hpsp[0] = CreatePropertySheetPageA(&psp[0]); + + psp[1].dwSize = sizeof(PROPSHEETPAGEA); + psp[1].hInstance = GetModuleHandleA(NULL); + U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT); + psp[1].pfnDlgProc = nav_page_proc; + hpsp[1] = CreatePropertySheetPageA(&psp[1]); + + psp[2].dwSize = sizeof(PROPSHEETPAGEA); + psp[2].hInstance = GetModuleHandleA(NULL); + U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO); + psp[2].pfnDlgProc = nav_page_proc; + hpsp[2] = CreatePropertySheetPageA(&psp[2]); + + psp[3].dwSize = sizeof(PROPSHEETPAGEA); + psp[3].hInstance = GetModuleHandleA(NULL); + U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT); + psp[3].pfnDlgProc = nav_page_proc; + hpsp[3] = CreatePropertySheetPageA(&psp[3]); + + /* set up the property sheet dialog */ + memset(&psh, 0, sizeof(psh)); + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_MODELESS | PSH_WIZARD; + psh.pszCaption = "A Wizard"; + psh.nPages = 4; + psh.hwndParent = GetDesktopWindow(); + U3(psh).phpage = hpsp; + hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } + + ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page); + + control = GetFocus(); + controlID = GetWindowLongPtr(control, GWLP_ID); + ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); + + /* simulate pressing the Next button */ + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); + if (!active_page) hwndtoindex_supported = FALSE; + if (hwndtoindex_supported) + ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page); + + control = GetFocus(); + controlID = GetWindowLongPtr(control, GWLP_ID); + ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID); + + defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); + ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); + + /* set the focus to the second edit box on this page */ + SetFocus(GetNextDlgTabItem(hdlg, control, FALSE)); + + /* press next again */ + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); + if (hwndtoindex_supported) + ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); + + control = GetFocus(); + controlID = GetWindowLongPtr(control, GWLP_ID); + ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID); + + /* back button */ + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); + if (hwndtoindex_supported) + ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page); + + control = GetFocus(); + controlID = GetWindowLongPtr(control, GWLP_ID); + ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID); + + defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); + ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres)); + + /* press next twice */ + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); + if (hwndtoindex_supported) + ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); + if (hwndtoindex_supported) + ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page); + else + active_page = 3; + + control = GetFocus(); + controlID = GetWindowLongPtr(control, GWLP_ID); + ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); + + /* try to navigate away, but shouldn't be able to */ + SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); + ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page); + + defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); + ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); + + DestroyWindow(hdlg); +} +static void test_buttons(void) +{ + HPROPSHEETPAGE hpsp[1]; + PROPSHEETPAGEA psp; + PROPSHEETHEADERA psh; + HWND hdlg; + HWND button; + RECT rc; + int prevRight, top; + + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.dwFlags = 0; + psp.hInstance = GetModuleHandleA(NULL); + U(psp).pszTemplate = "prop_page1"; + U2(psp).pszIcon = NULL; + psp.pfnDlgProc = page_dlg_proc; + psp.lParam = 0; + + hpsp[0] = CreatePropertySheetPageA(&psp); + + memset(&psh, 0, sizeof(psh)); + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; + psh.pszCaption = "test caption"; + psh.nPages = 1; + psh.hwndParent = GetDesktopWindow(); + U3(psh).phpage = hpsp; + psh.pfnCallback = sheet_callback; + + hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } + + /* OK button */ + button = GetDlgItem(hdlg, IDOK); + GetWindowRect(button, &rc); + prevRight = rc.right; + top = rc.top; + + /* Cancel button */ + button = GetDlgItem(hdlg, IDCANCEL); + GetWindowRect(button, &rc); + ok(rc.top == top, "Cancel button should have same top as OK button\n"); + ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n"); + prevRight = rc.right; + + button = GetDlgItem(hdlg, IDC_APPLY_BUTTON); + GetWindowRect(button, &rc); + ok(rc.top == top, "Apply button should have same top as OK button\n"); + ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n"); + prevRight = rc.right; + + button = GetDlgItem(hdlg, IDHELP); + GetWindowRect(button, &rc); + ok(rc.top == top, "Help button should have same top as OK button\n"); + ok(rc.left > prevRight, "Help button should be to the right of Apply button\n"); + + DestroyWindow(hdlg); +} + START_TEST(propsheet) { test_title(); test_nopage(); test_disableowner(); + test_wiznavigation(); + test_buttons(); } diff --git a/rostests/winetests/comctl32/rebar.c b/rostests/winetests/comctl32/rebar.c index d055d8aec8f..a75a0647f95 100644 --- a/rostests/winetests/comctl32/rebar.c +++ b/rostests/winetests/comctl32/rebar.c @@ -32,7 +32,6 @@ RECT height_change_notify_rect; static HWND hMainWnd; -static HWND hRebar; #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \ @@ -66,14 +65,17 @@ static BOOL is_font_installed(const char *name) return ret; } -static void rebuild_rebar(HWND *hRebar) +static HWND create_rebar_control(void) { - if (*hRebar) - DestroyWindow(*hRebar); + HWND hwnd; - *hRebar = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, + hwnd = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)17, GetModuleHandle(NULL), NULL); - SendMessageA(*hRebar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0); + ok(hwnd != NULL, "Failed to create Rebar\n"); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0); + + return hwnd; } static HWND build_toolbar(int nr, HWND hParent) @@ -85,7 +87,7 @@ static HWND build_toolbar(int nr, HWND hParent) int i; ok(hToolbar != NULL, "Toolbar creation problem\n"); - ok(SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n"); + ok(SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n"); ok(SendMessage(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); ok(SendMessage(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n"); @@ -104,7 +106,7 @@ static HWND build_toolbar(int nr, HWND hParent) case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break; case 2: iBitmapId = IDB_STD_SMALL_COLOR; break; } - ok(SendMessage(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGE failed\n"); + ok(SendMessage(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGES failed\n"); ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n"); return hToolbar; } @@ -117,7 +119,7 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa { NMHDR *lpnm = (NMHDR *)lParam; if (lpnm->code == RBN_HEIGHTCHANGE) - GetClientRect(hRebar, &height_change_notify_rect); + GetClientRect(lpnm->hwndFrom, &height_change_notify_rect); } break; } @@ -150,7 +152,7 @@ static void dump_sizes(HWND hRebar) for (i=0; inBands, "%d"); \ for (i=0; inBands); i++) { \ - ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_ITEMRECT\n"); \ + ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_GETRECT\n"); \ if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \ check_rect("band", rc, res->bands[i].rc); \ - rbi.cbSize = sizeof(REBARBANDINFO); \ + rbi.cbSize = REBARBANDINFOA_V6_SIZE; \ rbi.fMask = RBBIM_STYLE | RBBIM_SIZE; \ ok(SendMessageA(hRebar, RB_GETBANDINFO, i, (LPARAM)&rbi) == 1, "RB_GETBANDINFO\n"); \ compare(rbi.fStyle, res->bands[i].fStyle, "%x"); \ @@ -329,11 +331,11 @@ static int rbsize_numtests = 0; static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal) { CHAR buffer[MAX_PATH]; - REBARBANDINFO rbi; + REBARBANDINFOA rbi; if (lpszText != NULL) strcpy(buffer, lpszText); - rbi.cbSize = sizeof(rbi); + rbi.cbSize = REBARBANDINFOA_V6_SIZE; rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT; rbi.cx = cx; rbi.cxMinChild = cxMinChild; @@ -344,16 +346,16 @@ static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); } -static void layout_test(void) +static void test_layout(void) { - HWND hRebar = NULL; + HWND hRebar; REBARBANDINFO rbi; HIMAGELIST himl; REBARINFO ri; - rebuild_rebar(&hRebar); + hRebar = create_rebar_control(); check_sizes(); - rbi.cbSize = sizeof(rbi); + rbi.cbSize = REBARBANDINFOA_V6_SIZE; rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD; rbi.cx = 200; rbi.cxMinChild = 100; @@ -409,7 +411,9 @@ static void layout_test(void) SendMessageA(hRebar, RB_DELETEBAND, 1, 0); check_sizes(); - rebuild_rebar(&hRebar); + DestroyWindow(hRebar); + + hRebar = create_rebar_control(); add_band_w(hRebar, "ABC", 70, 40, 100); add_band_w(hRebar, NULL, 40, 70, 100); add_band_w(hRebar, NULL, 170, 240, 100); @@ -448,8 +452,10 @@ static void layout_test(void) SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi); check_sizes(); + DestroyWindow(hRebar); + /* VARHEIGHT resizing test on a horizontal rebar */ - rebuild_rebar(&hRebar); + hRebar = create_rebar_control(); SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE); check_sizes(); rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE; @@ -474,8 +480,10 @@ static void layout_test(void) SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); check_sizes(); + DestroyWindow(hRebar); + /* VARHEIGHT resizing on a vertical rebar */ - rebuild_rebar(&hRebar); + hRebar = create_rebar_control(); SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE); check_sizes(); rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE; @@ -503,6 +511,7 @@ static void layout_test(void) check_sizes(); DestroyWindow(hRebar); + ImageList_Destroy(himl); } #if 0 /* use this to generate more tests */ @@ -684,7 +693,7 @@ static int resize_numtests = 0; #endif -static void resize_test(void) +static void test_resize(void) { DWORD dwStyles[] = {CCS_TOP, CCS_TOP | CCS_NODIVIDER, CCS_BOTTOM, CCS_BOTTOM | CCS_NODIVIDER, CCS_VERT, CCS_RIGHT, CCS_NOPARENTALIGN, CCS_NOPARENTALIGN | CCS_NODIVIDER, CCS_NORESIZE, CCS_NOMOVEY, CCS_NOMOVEY | CCS_VERT, @@ -696,6 +705,8 @@ static void resize_test(void) for (i = 0; i < styles_count; i++) { + HWND hRebar; + comment("style %08x", dwStyles[i]); SetRect(&height_change_notify_rect, -1, -1, -1, -1); hRebar = CreateWindow(REBARCLASSNAME, "A", dwStyles[i] | WS_CHILD | WS_VISIBLE, 10, 5, 500, 15, hMainWnd, NULL, GetModuleHandle(NULL), 0); @@ -735,17 +746,17 @@ static void resize_test(void) } } -static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore, +static void expect_band_content(HWND hRebar, UINT uBand, INT fStyle, COLORREF clrFore, COLORREF clrBack, LPCSTR lpText, int iImage, HWND hwndChild, INT cxMinChild, INT cyMinChild, INT cx, HBITMAP hbmBack, INT wID, INT cyChild, INT cyMaxChild, INT cyIntegral, INT cxIdeal, LPARAM lParam, - INT cxHeader) + INT cxHeader, INT cxHeader_broken) { CHAR buf[MAX_PATH] = "abc"; - REBARBANDINFO rb; + REBARBANDINFOA rb; memset(&rb, 0xdd, sizeof(rb)); - rb.cbSize = sizeof(rb); + rb.cbSize = REBARBANDINFOA_V6_SIZE; rb.fMask = RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_COLORS | RBBIM_HEADERSIZE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_IMAGE | RBBIM_LPARAM | RBBIM_SIZE | RBBIM_STYLE | RBBIM_TEXT; @@ -753,8 +764,8 @@ static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore, rb.cch = MAX_PATH; ok(SendMessageA(hRebar, RB_GETBANDINFOA, uBand, (LPARAM)&rb), "RB_GETBANDINFO failed\n"); expect_eq(rb.fStyle, fStyle, int, "%x"); - todo_wine expect_eq(rb.clrFore, clrFore, COLORREF, "%x"); - todo_wine expect_eq(rb.clrBack, clrBack, unsigned, "%x"); + expect_eq(rb.clrFore, clrFore, COLORREF, "%x"); + expect_eq(rb.clrBack, clrBack, COLORREF, "%x"); expect_eq(strcmp(rb.lpText, lpText), 0, int, "%d"); expect_eq(rb.iImage, iImage, int, "%x"); expect_eq(rb.hwndChild, hwndChild, HWND, "%p"); @@ -769,20 +780,27 @@ static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore, expect_eq(rb.cyIntegral, cyIntegral, int, "%x"); expect_eq(rb.cxIdeal, cxIdeal, int, "%d"); expect_eq(rb.lParam, lParam, LPARAM, "%ld"); - expect_eq(rb.cxHeader, cxHeader, int, "%d"); + ok( rb.cxHeader == cxHeader || broken(rb.cxHeader == cxHeader_broken), + "expected %d for %d\n", cxHeader, rb.cxHeader ); } -static void bandinfo_test(void) +static void test_bandinfo(void) { REBARBANDINFOA rb; CHAR szABC[] = "ABC"; CHAR szABCD[] = "ABCD"; + HWND hRebar; - rebuild_rebar(&hRebar); - rb.cbSize = sizeof(REBARBANDINFO); + hRebar = create_rebar_control(); + rb.cbSize = REBARBANDINFOA_V6_SIZE; rb.fMask = 0; - ok(SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0); + if (!SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb)) + { + win_skip( "V6 info not supported\n" ); + DestroyWindow(hRebar); + return; + } + expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1); rb.fMask = RBBIM_CHILDSIZE; rb.cxMinChild = 15; @@ -790,62 +808,93 @@ static void bandinfo_test(void) rb.cyChild = 30; rb.cyMaxChild = 20; rb.cyIntegral = 10; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1); rb.fMask = RBBIM_TEXT; rb.lpText = szABC; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35, -1); - rb.cbSize = sizeof(REBARBANDINFO); + rb.cbSize = REBARBANDINFOA_V6_SIZE; rb.fMask = 0; ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9); - expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40); + expect_band_content(hRebar, 1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9, -1); + expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40, -1); rb.fMask = RBBIM_HEADERSIZE; rb.cxHeader = 50; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50, -1); rb.cxHeader = 5; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1); rb.fMask = RBBIM_TEXT; rb.lpText = szABCD; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1); rb.fMask = RBBIM_STYLE | RBBIM_TEXT; rb.fStyle = RBBS_VARIABLEHEIGHT; rb.lpText = szABC; - ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n"); - expect_band_content(0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40); + ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n"); + expect_band_content(hRebar, 0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40, 5); DestroyWindow(hRebar); } -START_TEST(rebar) +static void test_colors(void) { - HMODULE hComctl32; - BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); - INITCOMMONCONTROLSEX iccex; - WNDCLASSA wc; - MSG msg; - RECT rc; + COLORSCHEME scheme; + COLORREF clr; + BOOL ret; + HWND hRebar; + REBARBANDINFOA bi; - /* LoadLibrary is needed. This file has no references to functions in comctl32 */ - hComctl32 = LoadLibraryA("comctl32.dll"); - pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); - if (!pInitCommonControlsEx) + hRebar = create_rebar_control(); + + /* test default colors */ + clr = SendMessage(hRebar, RB_GETTEXTCOLOR, 0, 0); + compare(clr, CLR_NONE, "%x"); + clr = SendMessage(hRebar, RB_GETBKCOLOR, 0, 0); + compare(clr, CLR_NONE, "%x"); + + scheme.dwSize = sizeof(scheme); + scheme.clrBtnHighlight = 0; + scheme.clrBtnShadow = 0; + ret = SendMessage(hRebar, RB_GETCOLORSCHEME, 0, (LPARAM)&scheme); + if (ret) { - skip("InitCommonControlsEx() is missing. Skipping the tests\n"); - return; + compare(scheme.clrBtnHighlight, CLR_DEFAULT, "%x"); + compare(scheme.clrBtnShadow, CLR_DEFAULT, "%x"); } - iccex.dwSize = sizeof(iccex); - iccex.dwICC = ICC_COOL_CLASSES; - pInitCommonControlsEx(&iccex); + else + skip("RB_GETCOLORSCHEME not supported\n"); + + /* check default band colors */ + add_band_w(hRebar, "", 0, 10, 10); + bi.cbSize = REBARBANDINFOA_V6_SIZE; + bi.fMask = RBBIM_COLORS; + bi.clrFore = bi.clrBack = 0xc0ffe; + ret = SendMessage(hRebar, RB_GETBANDINFO, 0, (LPARAM)&bi); + ok(ret, "RB_GETBANDINFO failed\n"); + compare(bi.clrFore, RGB(0, 0, 0), "%x"); + compare(bi.clrBack, GetSysColor(COLOR_3DFACE), "%x"); + + SendMessage(hRebar, RB_SETTEXTCOLOR, 0, RGB(255, 0, 0)); + bi.clrFore = bi.clrBack = 0xc0ffe; + ret = SendMessage(hRebar, RB_GETBANDINFO, 0, (LPARAM)&bi); + ok(ret, "RB_GETBANDINFO failed\n"); + compare(bi.clrFore, RGB(0, 0, 0), "%x"); + + DestroyWindow(hRebar); +} + + +static BOOL register_parent_wnd_class(void) +{ + WNDCLASSA wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; @@ -857,23 +906,59 @@ START_TEST(rebar) wc.lpszMenuName = NULL; wc.lpszClassName = "MyTestWnd"; wc.lpfnWndProc = MyWndProc; - RegisterClassA(&wc); - hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, + + return RegisterClassA(&wc); +} + +static HWND create_parent_window(void) +{ + HWND hwnd; + + if (!register_parent_wnd_class()) return NULL; + + hwnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME), 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), NULL, NULL, GetModuleHandleA(NULL), 0); - GetClientRect(hMainWnd, &rc); - ShowWindow(hMainWnd, SW_SHOW); - bandinfo_test(); + ShowWindow(hwnd, SW_SHOW); + return hwnd; +} - if(is_font_installed("System") && is_font_installed("Tahoma")) +START_TEST(rebar) +{ + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + INITCOMMONCONTROLSEX iccex; + MSG msg; + + /* LoadLibrary is needed. This file has no references to functions in comctl32 */ + hComctl32 = LoadLibraryA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) { - layout_test(); - resize_test(); - } else - skip("Missing System or Tahoma font\n"); + win_skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_COOL_CLASSES; + pInitCommonControlsEx(&iccex); + hMainWnd = create_parent_window(); + + test_bandinfo(); + test_colors(); + + if(!is_font_installed("System") || !is_font_installed("Tahoma")) + { + skip("Missing System or Tahoma font\n"); + goto out; + } + + test_layout(); + test_resize(); + +out: PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) { TranslateMessage(&msg); diff --git a/rostests/winetests/comctl32/resources.h b/rostests/winetests/comctl32/resources.h index c99633d342d..8459fc81c16 100644 --- a/rostests/winetests/comctl32/resources.h +++ b/rostests/winetests/comctl32/resources.h @@ -31,4 +31,14 @@ #define IDS_TBADD5 20 #define IDS_TBADD7 22 +#define IDD_PROP_PAGE_INTRO 30 +#define IDD_PROP_PAGE_EDIT 31 +#define IDD_PROP_PAGE_RADIO 32 +#define IDD_PROP_PAGE_EXIT 33 + +#define IDC_PS_EDIT1 1000 +#define IDC_PS_EDIT2 1001 +#define IDC_PS_RADIO1 1010 +#define IDC_PS_RADIO2 1011 + #endif /* __WINE_COMCTL32_TEST_RESOURCES_H */ diff --git a/rostests/winetests/comctl32/rsrc.rc b/rostests/winetests/comctl32/rsrc.rc index bf195b661d1..06e382e3c4a 100644 --- a/rostests/winetests/comctl32/rsrc.rc +++ b/rostests/winetests/comctl32/rsrc.rc @@ -30,6 +30,40 @@ FONT 8, "MS Shell Dlg" LTEXT "Test", -1, 10, 6, 100, 8 } +IDD_PROP_PAGE_INTRO DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215 +STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE +CAPTION "Edit Control Page" +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 +STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE +CAPTION "Edit Control Page" +FONT 8, "MS Shell Dlg" +{ + EDITTEXT IDC_PS_EDIT1, 5, 5, 150, 140, WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE + 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 +STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE +CAPTION "Edit Control Page" +FONT 8, "MS Shell Dlg" +{ + CONTROL "Radio1", IDC_PS_RADIO1, "Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 20, 20, 39, 10 + CONTROL "Radio2", IDC_PS_RADIO2, "Button", BS_AUTORADIOBUTTON, 20, 40, 39, 10 +} + +IDD_PROP_PAGE_EXIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215 +STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE +CAPTION "Edit Control Page" +FONT 8, "MS Shell Dlg" +{ + LTEXT "This has been a test property sheet!", -1, 10, 6, 170, 8 +} + STRINGTABLE { IDS_TBADD1 "abc" diff --git a/rostests/winetests/comctl32/status.c b/rostests/winetests/comctl32/status.c index f1cbda47f0d..839b138bb40 100644 --- a/rostests/winetests/comctl32/status.c +++ b/rostests/winetests/comctl32/status.c @@ -466,6 +466,112 @@ static void test_status_ownerdraw(void) SetWindowLongPtr( g_hMainWnd, GWLP_WNDPROC, (LONG_PTR)g_wndproc_saved ); } +static void test_gettext(void) +{ + HWND hwndStatus = CreateWindow(SUBCLASS_NAME, NULL, WS_CHILD|WS_VISIBLE, + 0, 0, 300, 20, g_hMainWnd, NULL, NULL, NULL); + char buf[5]; + int r; + + r = SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)"Text"); + expect(TRUE, r); + r = SendMessage(hwndStatus, WM_GETTEXTLENGTH, 0, 0); + expect(4, r); + /* A size of 0 returns the length of the text */ + r = SendMessage(hwndStatus, WM_GETTEXT, 0, 0); + expect(4, r); + /* A size of 1 only stores the NULL terminator */ + buf[0] = 0xa; + r = SendMessage(hwndStatus, WM_GETTEXT, 1, (LPARAM)buf); + ok( r == 0 || broken(r == 4), "Expected 0 got %d\n", r ); + if (!r) ok(!buf[0], "expected empty buffer\n"); + /* A size of 2 returns a length 1 */ + r = SendMessage(hwndStatus, WM_GETTEXT, 2, (LPARAM)buf); + ok( r == 1 || broken(r == 4), "Expected 1 got %d\n", r ); + r = SendMessage(hwndStatus, WM_GETTEXT, sizeof(buf), (LPARAM)buf); + expect(4, r); + ok(!strcmp(buf, "Text"), "expected Text, got %s\n", buf); + DestroyWindow(hwndStatus); +} + +/* Notify events to parent */ +static BOOL g_got_dblclk; +static BOOL g_got_click; +static BOOL g_got_rdblclk; +static BOOL g_got_rclick; + +/* Messages to parent */ +static BOOL g_got_contextmenu; + +static LRESULT WINAPI test_notify_parent_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_NOTIFY: + { + NMHDR *hdr = ((LPNMHDR)lParam); + switch(hdr->code) + { + case NM_DBLCLK: g_got_dblclk = TRUE; break; + case NM_CLICK: g_got_click = TRUE; break; + case NM_RDBLCLK: g_got_rdblclk = TRUE; break; + case NM_RCLICK: g_got_rclick = TRUE; break; + } + + /* Return zero to indicate default processing */ + return 0; + } + + case WM_CONTEXTMENU: g_got_contextmenu = TRUE; return 0; + + default: + return( DefWindowProcA(hwnd, msg, wParam, lParam)); + } + + return 0; +} + +/* Test that WM_NOTIFY messages from the status control works correctly */ +static void test_notify(void) +{ + HWND hwndParent; + HWND hwndStatus; + ATOM atom; + WNDCLASSA wclass = {0}; + wclass.lpszClassName = "TestNotifyParentClass"; + wclass.lpfnWndProc = test_notify_parent_proc; + atom = RegisterClassA(&wclass); + ok(atom, "RegisterClass failed\n"); + + /* create parent */ + hwndParent = CreateWindow(wclass.lpszClassName, "parent", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, 300, 20, NULL, NULL, NULL, NULL); + ok(hwndParent != NULL, "Parent creation failed!\n"); + + /* create status bar */ + hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, WS_VISIBLE | WS_CHILD, + 0, 0, 300, 20, hwndParent, NULL, NULL, NULL); + ok(hwndStatus != NULL, "Status creation failed!\n"); + + /* Send various mouse event, and check that we get them */ + g_got_dblclk = FALSE; + SendMessage(hwndStatus, WM_LBUTTONDBLCLK, 0, 0); + ok(g_got_dblclk, "WM_LBUTTONDBLCLK was not processed correctly!\n"); + g_got_rdblclk = FALSE; + SendMessage(hwndStatus, WM_RBUTTONDBLCLK, 0, 0); + ok(g_got_rdblclk, "WM_RBUTTONDBLCLK was not processed correctly!\n"); + g_got_click = FALSE; + SendMessage(hwndStatus, WM_LBUTTONUP, 0, 0); + ok(g_got_click, "WM_LBUTTONUP was not processed correctly!\n"); + + /* For R-UP, check that we also get the context menu from the default processing */ + g_got_contextmenu = FALSE; + g_got_rclick = FALSE; + SendMessage(hwndStatus, WM_RBUTTONUP, 0, 0); + ok(g_got_rclick, "WM_RBUTTONUP was not processed correctly!\n"); + ok(g_got_contextmenu, "WM_RBUTTONUP did not activate the context menu!\n"); +} + START_TEST(status) { hinst = GetModuleHandleA(NULL); @@ -483,4 +589,6 @@ START_TEST(status) test_create(); test_height(); test_status_ownerdraw(); + test_gettext(); + test_notify(); } diff --git a/rostests/winetests/comctl32/subclass.c b/rostests/winetests/comctl32/subclass.c index f4d0b727794..8511275c8f9 100644 --- a/rostests/winetests/comctl32/subclass.c +++ b/rostests/winetests/comctl32/subclass.c @@ -279,21 +279,49 @@ static BOOL RegisterWindowClasses(void) return TRUE; } -START_TEST(subclass) +static int init_function_pointers(void) { - HMODULE hdll; - - hdll = GetModuleHandleA("comctl32.dll"); - assert(hdll); + HMODULE hmod; + void *ptr; + + hmod = GetModuleHandleA("comctl32.dll"); + assert(hmod); + /* Functions have to be loaded by ordinal. Only XP and W2K3 export * them by name. */ - pSetWindowSubclass = (void*)GetProcAddress(hdll, (LPSTR)410); - pRemoveWindowSubclass = (void*)GetProcAddress(hdll, (LPSTR)412); - pDefSubclassProc = (void*)GetProcAddress(hdll, (LPSTR)413); - +#define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord))) + MAKEFUNC_ORD(SetWindowSubclass, 410); + MAKEFUNC_ORD(RemoveWindowSubclass, 412); + MAKEFUNC_ORD(DefSubclassProc, 413); +#undef MAKEFUNC_ORD + if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc) - return; + { + win_skip("SetWindowSubclass and friends are not available\n"); + return 0; + } + + /* test named exports */ + ptr = GetProcAddress(hmod, "SetWindowSubclass"); + ok(broken(ptr == 0) || ptr != 0, "expected named export for SetWindowSubclass\n"); + if(ptr) + { +#define TESTNAMED(f) \ + ptr = (void*)GetProcAddress(hmod, #f); \ + ok(ptr != 0, "expected named export for " #f "\n"); + TESTNAMED(RemoveWindowSubclass); + TESTNAMED(DefSubclassProc); + /* GetWindowSubclass exported for V6 only */ +#undef TESTNAMED + } + + return 1; +} + +START_TEST(subclass) +{ + if(!init_function_pointers()) return; if(!RegisterWindowClasses()) assert(0); diff --git a/rostests/winetests/comctl32/tab.c b/rostests/winetests/comctl32/tab.c index 3bf68945120..6774d51a1a5 100644 --- a/rostests/winetests/comctl32/tab.c +++ b/rostests/winetests/comctl32/tab.c @@ -89,13 +89,14 @@ static const struct message create_parent_wnd_seq[] = { static const struct message add_tab_to_parent[] = { { TCM_INSERTITEMA, sent }, - { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent|optional }, { WM_NOTIFYFORMAT, sent|defwinproc }, { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 }, { WM_PARENTNOTIFY, sent|defwinproc }, { TCM_INSERTITEMA, sent }, { TCM_INSERTITEMA, sent }, { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent|optional }, { 0 } }; @@ -236,12 +237,15 @@ static const struct message insert_focus_seq[] = { { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, { TCM_INSERTITEM, sent|wparam, 1 }, + { WM_NOTIFYFORMAT, sent|defwinproc|optional }, + { WM_QUERYUISTATE, sent|defwinproc|optional }, + { WM_PARENTNOTIFY, sent|defwinproc|optional }, { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, { TCM_INSERTITEM, sent|wparam, 2 }, - { WM_NOTIFYFORMAT, sent|defwinproc, }, + { WM_NOTIFYFORMAT, sent|defwinproc|optional }, { WM_QUERYUISTATE, sent|defwinproc|optional, }, - { WM_PARENTNOTIFY, sent|defwinproc, }, + { WM_PARENTNOTIFY, sent|defwinproc|optional }, { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 }, @@ -370,14 +374,9 @@ static HWND createParentWindow(void) GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); } -struct subclass_info -{ - WNDPROC oldproc; -}; - static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -402,7 +401,7 @@ static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, } defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; @@ -412,14 +411,10 @@ static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT { HWND tabHandle; TCITEM tcNewTab; - struct subclass_info *info; + WNDPROC oldproc; RECT rect; INT i; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - GetClientRect(parent_wnd, &rect); tabHandle = CreateWindow ( @@ -431,8 +426,8 @@ static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT assert(tabHandle); - info->oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess); - SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess); + SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc); tcNewTab.mask = mask; @@ -505,7 +500,7 @@ static void test_tab(INT nMinTabWidth) SIZE size; HDC hdc; HFONT hOldFont; - INT i, dpi; + INT i, dpi, exp; hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE); SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); @@ -585,8 +580,11 @@ static void test_tab(INT nMinTabWidth) SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); trace (" non fixed width, with text...\n"); - CheckSize(hwTab, max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth), -1, - "no icon, default width"); + exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth); + SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab ); + ok( rTab.right - rTab.left == exp || broken(rTab.right - rTab.left == DEFAULT_MIN_TAB_WIDTH), + "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left ); + for (i=0; i<8; i++) { INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth; @@ -610,7 +608,11 @@ static void test_tab(INT nMinTabWidth) SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); trace (" non fixed width, no text...\n"); - CheckSize(hwTab, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth, -1, "no icon, default width"); + exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth; + SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab ); + ok( rTab.right - rTab.left == exp || broken(rTab.right - rTab.left == DEFAULT_MIN_TAB_WIDTH), + "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left ); + for (i=0; i<8; i++) { INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth; @@ -636,7 +638,290 @@ static void test_tab(INT nMinTabWidth) DeleteObject(hFont); } -static void test_getters_setters(HWND parent_wnd, INT nTabs) +static void test_curfocus(HWND parent_wnd, INT nTabs) +{ + INT focusIndex; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing CurFocus with largest appropriate value */ + SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(nTabs-1, focusIndex); + + /* Testing CurFocus with negative value */ + SendMessage(hTab, TCM_SETCURFOCUS, -10, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(-1, focusIndex); + + /* Testing CurFocus with value larger than number of tabs */ + focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); + expect(-1, focusIndex); + + SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(1, focusIndex); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_cursel(HWND parent_wnd, INT nTabs) +{ + INT selectionIndex; + INT focusIndex; + TCITEM tcItem; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing CurSel with largest appropriate value */ + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0); + expect(0, selectionIndex); + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(nTabs-1, selectionIndex); + + /* Focus should switch with selection */ + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(nTabs-1, focusIndex); + + /* Testing CurSel with negative value */ + SendMessage(hTab, TCM_SETCURSEL, -10, 0); + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(-1, selectionIndex); + + /* Testing CurSel with value larger than number of tabs */ + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); + expect(-1, selectionIndex); + + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0); + expect(-1, selectionIndex); + selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(1, selectionIndex); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE); + + /* selected item should have TCIS_BUTTONPRESSED state + It doesn't depend on button state */ + memset(&tcItem, 0, sizeof(TCITEM)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem); + ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */ + "Selected item should have TCIS_BUTTONPRESSED\n"); + + DestroyWindow(hTab); +} + +static void test_extendedstyle(HWND parent_wnd, INT nTabs) +{ + DWORD prevExtendedStyle; + DWORD extendedStyle; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing Flat Separators */ + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS); + expect(extendedStyle, prevExtendedStyle); + + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + expect(TCS_EX_FLATSEPARATORS, extendedStyle); + + /* Testing Register Drop */ + prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP); + expect(extendedStyle, prevExtendedStyle); + + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + todo_wine{ + expect(TCS_EX_REGISTERDROP, extendedStyle); + } + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_unicodeformat(HWND parent_wnd, INT nTabs) +{ + INT unicodeFormat; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); + todo_wine{ + expect(0, unicodeFormat); + } + unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); + expect(1, unicodeFormat); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0); + expect(1, unicodeFormat); + unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); + expect(0, unicodeFormat); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); + expect(0, unicodeFormat); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_getset_item(HWND parent_wnd, INT nTabs) +{ + TCITEM tcItem; + DWORD ret; + char szText[32] = "New Label"; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + /* passing invalid index should result in initialization to zero + for members mentioned in mask requested */ + + /* valid range here is [0,4] */ + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_IMAGE; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + expect(0, tcItem.iImage); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_TEXT; + tcItem.pszText = szText; + szText[0] = 'a'; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + expect('a', szText[0]); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = 0; + tcItem.dwState = TCIS_BUTTONPRESSED; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = TCIS_BUTTONPRESSED; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.dwState == 0, "Expected zero dwState\n"); + + /* check with negative index to be sure */ + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + tcItem.mask = TCIF_TEXT; + tcItem.pszText = &szText[0]; + tcItem.cchTextMax = sizeof(szText); + + strcpy(szText, "New Label"); + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + expect_str("New Label", tcItem.pszText); + + ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n"); + expect_str("Tab 2", tcItem.pszText); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE); + + /* TCIS_BUTTONPRESSED doesn't depend on tab style */ + memset(&tcItem, 0, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = TCIS_BUTTONPRESSED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + if (tcItem.dwState) + { + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); + /* next highlight item, test that dwStateMask actually masks */ + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_HIGHLIGHTED; + tcItem.dwState = TCIS_HIGHLIGHTED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n"); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); + } + else win_skip( "Item state mask not supported\n" ); + + DestroyWindow(hTab); +} + +static void test_getset_tooltips(HWND parent_wnd, INT nTabs) +{ + HWND hTab, toolTip; + char toolTipText[32] = "ToolTip Text Test"; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + toolTip = create_tooltip(hTab, toolTipText); + SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0); + ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); + + SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0); + ok (NULL == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE); + + DestroyWindow(hTab); +} + +static void test_misc(HWND parent_wnd, INT nTabs) { HWND hTab; RECT rTab; @@ -694,196 +979,6 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE); - /* Testing CurFocus */ - { - INT focusIndex; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing CurFocus with largest appropriate value */ - SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(nTabs-1, focusIndex); - - /* Testing CurFocus with negative value */ - SendMessage(hTab, TCM_SETCURFOCUS, -10, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(-1, focusIndex); - - /* Testing CurFocus with value larger than number of tabs */ - focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); - todo_wine{ - expect(-1, focusIndex); - } - - SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(1, focusIndex); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE); - } - - /* Testing CurSel */ - { - INT selectionIndex; - INT focusIndex; - TCITEM tcItem; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing CurSel with largest appropriate value */ - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0); - expect(1, selectionIndex); - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - expect(nTabs-1, selectionIndex); - - /* Focus should switch with selection */ - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(nTabs-1, focusIndex); - - /* Testing CurSel with negative value */ - SendMessage(hTab, TCM_SETCURSEL, -10, 0); - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - expect(-1, selectionIndex); - - /* Testing CurSel with value larger than number of tabs */ - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); - expect(-1, selectionIndex); - - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0); - expect(-1, selectionIndex); - selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(1, selectionIndex); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE); - - /* selected item should have TCIS_BUTTONPRESSED state - It doesn't depend on button state */ - memset(&tcItem, 0, sizeof(TCITEM)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem); - ok (tcItem.dwState & TCIS_BUTTONPRESSED, "Selected item should have TCIS_BUTTONPRESSED\n"); - } - - /* Testing ExtendedStyle */ - { - DWORD prevExtendedStyle; - DWORD extendedStyle; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing Flat Separators */ - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS); - expect(extendedStyle, prevExtendedStyle); - - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - expect(TCS_EX_FLATSEPARATORS, extendedStyle); - - /* Testing Register Drop */ - prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP); - expect(extendedStyle, prevExtendedStyle); - - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - todo_wine{ - expect(TCS_EX_REGISTERDROP, extendedStyle); - } - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE); - } - - /* Testing UnicodeFormat */ - { - INT unicodeFormat; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); - todo_wine{ - expect(0, unicodeFormat); - } - unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); - expect(1, unicodeFormat); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0); - expect(1, unicodeFormat); - unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); - expect(0, unicodeFormat); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); - expect(0, unicodeFormat); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE); - } - - /* Testing GetSet Item */ - { - TCITEM tcItem; - char szText[32] = "New Label"; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - tcItem.mask = TCIF_TEXT; - tcItem.pszText = &szText[0]; - tcItem.cchTextMax = sizeof(szText); - - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - expect_str("New Label", tcItem.pszText); - - ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n"); - expect_str("Tab 2", tcItem.pszText); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE); - - /* TCIS_BUTTONPRESSED doesn't depend on tab style */ - memset(&tcItem, 0, sizeof(tcItem)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - tcItem.dwState = TCIS_BUTTONPRESSED; - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); - /* next highlight item, test that dwStateMask actually masks */ - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_HIGHLIGHTED; - tcItem.dwState = TCIS_HIGHLIGHTED; - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n"); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); - } - - /* Testing GetSet ToolTip */ - { - HWND toolTip; - char toolTipText[32] = "ToolTip Text Test"; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - toolTip = create_tooltip(hTab, toolTipText); - SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0); - ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); - - SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0); - ok (NULL == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE); - ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE); - } - DestroyWindow(hTab); } @@ -903,6 +998,7 @@ static void test_adjustrect(HWND parent_wnd) r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0); expect(-1, r); } + static void test_insert_focus(HWND parent_wnd) { HWND hTab; @@ -960,8 +1056,8 @@ static void test_insert_focus(HWND parent_wnd) r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); expect(2, r); - ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", TRUE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", FALSE); + ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE); DestroyWindow(hTab); } @@ -1010,7 +1106,7 @@ static void test_delete_focus(HWND parent_wnd) expect(-1, r); ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE); DestroyWindow(hTab); } @@ -1078,6 +1174,28 @@ static void test_removeimage(HWND parent_wnd) DestroyIcon(hicon); } +static void test_delete_selection(HWND parent_wnd) +{ + HWND hTab; + DWORD ret; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4); + ok(hTab != NULL, "Failed to create tab control\n"); + + ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0); + expect(0, ret); + ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(3, ret); + /* delete selected item - selection goes to -1 */ + ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0); + expect(TRUE, ret); + + ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(-1, ret); + + DestroyWindow(hTab); +} + START_TEST(tab) { HWND parent_wnd; @@ -1108,13 +1226,19 @@ START_TEST(tab) parent_wnd = createParentWindow(); ok(parent_wnd != NULL, "Failed to create parent window!\n"); - /* Testing getters and setters with 5 tabs */ - test_getters_setters(parent_wnd, 5); + test_curfocus(parent_wnd, 5); + test_cursel(parent_wnd, 5); + test_extendedstyle(parent_wnd, 5); + test_unicodeformat(parent_wnd, 5); + test_getset_item(parent_wnd, 5); + test_getset_tooltips(parent_wnd, 5); + test_misc(parent_wnd, 5); test_adjustrect(parent_wnd); test_insert_focus(parent_wnd); test_delete_focus(parent_wnd); + test_delete_selection(parent_wnd); test_removeimage(parent_wnd); DestroyWindow(parent_wnd); diff --git a/rostests/winetests/comctl32/testlist.c b/rostests/winetests/comctl32/testlist.c index 7e32af490c3..1789e5c4812 100644 --- a/rostests/winetests/comctl32/testlist.c +++ b/rostests/winetests/comctl32/testlist.c @@ -15,7 +15,6 @@ extern void func_listview(void); extern void func_misc(void); extern void func_monthcal(void); extern void func_mru(void); -extern void func_msg(void); extern void func_progress(void); extern void func_propsheet(void); extern void func_rebar(void); @@ -40,7 +39,6 @@ const struct test winetest_testlist[] = { "misc", func_misc }, { "monthcal", func_monthcal }, { "mru", func_mru }, - { "msg", func_msg }, { "progress", func_progress }, { "propsheet", func_propsheet }, { "rebar", func_rebar }, diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c index 19460952349..8311df575ec 100644 --- a/rostests/winetests/comctl32/toolbar.c +++ b/rostests/winetests/comctl32/toolbar.c @@ -33,12 +33,27 @@ #include "wine/test.h" +#include "msg.h" + +#define PARENT_SEQ_INDEX 0 +#define NUM_MSG_SEQUENCES 1 + +static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; + static HWND hMainWnd; static BOOL g_fBlockHotItemChange; static BOOL g_fReceivedHotItemChange; static BOOL g_fExpectedHotItemOld; static BOOL g_fExpectedHotItemNew; static DWORD g_dwExpectedDispInfoMask; +static BOOL g_ResetDispTextPtr; + +static const struct message ttgetdispinfo_parent_seq[] = { + { WM_NOTIFY, sent|id, 0, 0, TBN_GETINFOTIPA }, + /* next line is todo, currently TTN_GETDISPINFOW is raised here */ + { WM_NOTIFY, sent|id, 0, 0, TTN_GETDISPINFOA }, + { 0 } +}; #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) @@ -56,7 +71,7 @@ static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) { p->iString = nString; } -static LRESULT MyWnd_Notify(LPARAM lParam) +static LRESULT parent_wnd_notify(LPARAM lParam) { NMHDR *hdr = (NMHDR *)lParam; NMTBHOTITEM *nmhi; @@ -79,25 +94,65 @@ static LRESULT MyWnd_Notify(LPARAM lParam) ok(FALSE, "TBN_GETDISPINFOA received\n"); break; + case TBN_GETINFOTIPA: + { + NMTBGETINFOTIPA *tbgit = (NMTBGETINFOTIPA*)lParam; + + if (g_ResetDispTextPtr) + { + tbgit->pszText = NULL; + return 0; + } + break; + } case TBN_GETDISPINFOW: nmdisp = (NMTBDISPINFOA *)lParam; compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x"); - compare(nmdisp->iImage, -1, "%d"); ok(nmdisp->pszText == NULL, "pszText is not NULL\n"); break; } return 0; } -static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - switch (msg) + static LONG defwndproc_counter = 0; + struct message msg; + LRESULT ret; + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code; + + /* 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); + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + switch (message) { case WM_NOTIFY: - return MyWnd_Notify(lParam); + return parent_wnd_notify(lParam); } - return DefWindowProcA(hWnd, msg, wParam, lParam); + + defwndproc_counter++; + ret = DefWindowProcA(hWnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; } static void basic_test(void) @@ -163,7 +218,7 @@ static void basic_test(void) static void rebuild_toolbar(HWND *hToolbar) { - if (*hToolbar != NULL) + if (*hToolbar) DestroyWindow(*hToolbar); *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL); @@ -374,6 +429,8 @@ static void test_add_bitmap(void) addbmp.hInst = HINST_COMMCTRL; addbmp.nID = IDB_STD_SMALL_COLOR; rebuild_toolbar(&hToolbar); + ImageList_Destroy(himl); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); CHECK_IMAGELIST(15, 16, 16); compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x"); @@ -415,7 +472,7 @@ static void test_add_bitmap(void) ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \ } \ ok(SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \ - "Too many string in table\n"); \ + "Too many strings in table\n"); \ } static void test_add_string(void) @@ -432,10 +489,17 @@ static void test_add_string(void) HWND hToolbar = NULL; TBBUTTON button; int ret; + CHAR buf[260]; rebuild_toolbar(&hToolbar); ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1); ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret); + ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, 1), (LPARAM)buf); + if (ret == 0) + { + win_skip("TB_GETSTRING needs 5.80\n"); + return; + } CHECK_STRING_TABLE(2, ret1); ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2); ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret); @@ -734,6 +798,22 @@ static tbsize_result_t tbsize_results[] = static int tbsize_numtests = 0; +typedef struct +{ + int test_num; + int rect_index; + RECT rcButton; +} tbsize_alt_result_t; + +static tbsize_alt_result_t tbsize_alt_results[] = +{ + { 5, 2, { 0, 24, 8, 29 } }, + { 20, 1, { 100, 2, 107, 102 } }, + { 20, 2, { 107, 2, 207, 102 } } +}; + +static int tbsize_alt_numtests = 0; + #define check_sizes_todo(todomask) { \ RECT rc; \ int buttonCount, i, mask=(todomask); \ @@ -745,7 +825,11 @@ static int tbsize_numtests = 0; compare(buttonCount, res->nButtons, "%d"); \ for (i=0; inButtons); i++) { \ ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \ - if (!(mask&1)) { \ + if (broken(tbsize_alt_numtests < sizeof(tbsize_alt_results)/sizeof(tbsize_alt_results[0]) && \ + memcmp(&rc, &tbsize_alt_results[tbsize_alt_numtests].rcButton, sizeof(RECT)) == 0)) { \ + win_skip("Alternate rect found\n"); \ + tbsize_alt_numtests++; \ + } else if (!(mask&1)) { \ check_rect("button", rc, res->rcButtons[i]); \ } else {\ todo_wine { check_rect("button", rc, res->rcButtons[i]); } \ @@ -954,6 +1038,7 @@ static void test_sizes(void) rebuild_toolbar(&hToolbar); ImageList_Destroy(himl); + ImageList_Destroy(himl2); SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n"); @@ -995,10 +1080,17 @@ static void test_sizes(void) tbinfo.cx = 672; tbinfo.cbSize = sizeof(TBBUTTONINFO); tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX; - ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); - ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); - SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); - check_sizes(); + if (SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo)) + { + ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes(); + } + else /* TBIF_BYINDEX probably not supported, confirm that this was the reason for the failure */ + { + tbinfo.dwMask = TBIF_SIZE; + ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 33, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); + } DestroyWindow(hToolbar); } @@ -1049,21 +1141,24 @@ static void restore_recalc_state(HWND hToolbar) static void test_recalc(void) { - HWND hToolbar; + HWND hToolbar = NULL; TBBUTTONINFO bi; CHAR test[] = "Test"; const int EX_STYLES_COUNT = 5; int i; + BOOL recalc; /* Like TB_ADDBUTTONS tested in test_sized, inserting a button without text * results in a relayout, while adding one with text forces a recalc */ prepare_recalc_test(&hToolbar); SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[0]); - ok(!did_recalc(hToolbar), "Unexpected recalc - adding button without text\n"); + recalc = did_recalc(hToolbar); + ok(!recalc, "Unexpected recalc - adding button without text\n"); prepare_recalc_test(&hToolbar); SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[3]); - ok(did_recalc(hToolbar), "Expected a recalc - adding button with text\n"); + recalc = did_recalc(hToolbar); + ok(recalc, "Expected a recalc - adding button with text\n"); /* TB_SETBUTTONINFO, even when adding a text, results only in a relayout */ prepare_recalc_test(&hToolbar); @@ -1071,7 +1166,8 @@ static void test_recalc(void) bi.dwMask = TBIF_TEXT; bi.pszText = test; SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&bi); - ok(!did_recalc(hToolbar), "Unexpected recalc - setting a button text\n"); + recalc = did_recalc(hToolbar); + ok(!recalc, "Unexpected recalc - setting a button text\n"); /* most extended styled doesn't force a recalc (testing all the bits gives * the same results, but prints some ERRs while testing) */ @@ -1082,22 +1178,31 @@ static void test_recalc(void) prepare_recalc_test(&hToolbar); expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0)); SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, (1 << i)); - ok(!did_recalc(hToolbar), "Unexpected recalc - setting bit %d\n", i); + recalc = did_recalc(hToolbar); + ok(!recalc, "Unexpected recalc - setting bit %d\n", i); SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0); - ok(!did_recalc(hToolbar), "Unexpected recalc - clearing bit %d\n", i); + recalc = did_recalc(hToolbar); + ok(!recalc, "Unexpected recalc - clearing bit %d\n", i); expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0)); } /* TBSTYLE_EX_MIXEDBUTTONS does a recalc on change */ prepare_recalc_test(&hToolbar); SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS); - ok(did_recalc(hToolbar), "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n"); - restore_recalc_state(hToolbar); - SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS); - ok(!did_recalc(hToolbar), "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n"); - restore_recalc_state(hToolbar); - SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0); - ok(did_recalc(hToolbar), "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n"); + recalc = did_recalc(hToolbar); + if (recalc) + { + ok(recalc, "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n"); + restore_recalc_state(hToolbar); + SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS); + recalc = did_recalc(hToolbar); + ok(!recalc, "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n"); + restore_recalc_state(hToolbar); + SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0); + recalc = did_recalc(hToolbar); + ok(recalc, "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n"); + } + else win_skip( "No recalc on TBSTYLE_EX_MIXEDBUTTONS\n" ); /* undocumented exstyle 0x2 seems to changes the top margin, what * interferes with these tests */ @@ -1117,8 +1222,8 @@ static void test_getbuttoninfo(void) int ret; tbi.cbSize = i; - tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; - ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi); + tbi.dwMask = TBIF_COMMAND; + ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 1, (LPARAM)&tbi); if (i == sizeof(TBBUTTONINFO)) { compare(ret, 0, "%d"); } else { @@ -1189,7 +1294,7 @@ static void test_dispinfo(void) rebuild_toolbar(&hToolbar); SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL); SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp); - g_dwExpectedDispInfoMask = 1; + g_dwExpectedDispInfoMask = TBNF_IMAGE; /* Some TBN_GETDISPINFO tests will be done in MyWnd_Notify function. * We will receive TBN_GETDISPINFOW even if the control is ANSI */ compare((BOOL)SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0, "%d"); @@ -1281,6 +1386,12 @@ static void test_getstring(void) ok(hToolbar != NULL, "Toolbar creation problem\n"); r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0); + if (r == 0) + { + win_skip("TB_GETSTRING and TB_GETSTRINGW need 5.80\n"); + DestroyWindow(hToolbar); + return; + } expect(-1, r); r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0); expect(-1, r); @@ -1300,12 +1411,46 @@ static void test_getstring(void) DestroyWindow(hToolbar); } +static void test_tooltip(void) +{ + HWND hToolbar = NULL; + const TBBUTTON buttons_disp[] = { + {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1}, + {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1}, + }; + NMTTDISPINFOW nmtti; + + rebuild_toolbar(&hToolbar); + + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp); + + /* W used to get through toolbar code that assumes tooltip is always Unicode */ + memset(&nmtti, 0, sizeof(nmtti)); + nmtti.hdr.code = TTN_GETDISPINFOW; + nmtti.hdr.idFrom = 20; + + SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti); + ok_sequence(sequences, PARENT_SEQ_INDEX, ttgetdispinfo_parent_seq, + "dispinfo from tooltip", TRUE); + + g_ResetDispTextPtr = TRUE; + SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti); + g_ResetDispTextPtr = FALSE; + + DestroyWindow(hToolbar); +} + START_TEST(toolbar) { WNDCLASSA wc; MSG msg; RECT rc; - + + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + InitCommonControls(); wc.style = CS_HREDRAW | CS_VREDRAW; @@ -1316,11 +1461,11 @@ START_TEST(toolbar) wc.hCursor = LoadCursorA(NULL, IDC_IBEAM); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; - wc.lpszClassName = "MyTestWnd"; - wc.lpfnWndProc = MyWndProc; + wc.lpszClassName = "Toolbar test parent"; + wc.lpfnWndProc = parent_wnd_proc; RegisterClassA(&wc); - hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, + hMainWnd = CreateWindowExA(0, "Toolbar test parent", "Blah", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); GetClientRect(hMainWnd, &rc); ShowWindow(hMainWnd, SW_SHOW); @@ -1336,6 +1481,7 @@ START_TEST(toolbar) test_dispinfo(); test_setrows(); test_getstring(); + test_tooltip(); PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) { diff --git a/rostests/winetests/comctl32/tooltips.c b/rostests/winetests/comctl32/tooltips.c index 2b4f43ffd1b..8ca3f7bb903 100644 --- a/rostests/winetests/comctl32/tooltips.c +++ b/rostests/winetests/comctl32/tooltips.c @@ -23,6 +23,8 @@ #include "wine/test.h" +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) + static void test_create_tooltip(void) { HWND parent, hwnd; @@ -42,7 +44,8 @@ static void test_create_tooltip(void) trace("style = %08x\n", style); exp_style = 0x7fffffff | WS_POPUP; exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME); - ok(style == exp_style,"wrong style %08x/%08x\n", style, exp_style); + ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */ + "wrong style %08x/%08x\n", style, exp_style); DestroyWindow(hwnd); @@ -142,7 +145,6 @@ static void test_customdraw(void) { /* Invalid notification responses */ {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT}, {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT}, - {CDRF_NOTIFYSUBITEMDRAW, TEST_CDDS_PREPAINT}, {CDRF_NEWFONT, TEST_CDDS_PREPAINT} }; @@ -168,6 +170,7 @@ static void test_customdraw(void) { iterationNumber++) { HWND parent, hwndTip; + RECT rect; TOOLINFO toolInfo = { 0 }; /* Create a main window */ @@ -201,7 +204,7 @@ static void test_customdraw(void) { SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); /* Create a tool */ - toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.cbSize = TTTOOLINFO_V1_SIZE; toolInfo.hwnd = parent; toolInfo.hinst = GetModuleHandleA(NULL); toolInfo.uFlags = TTF_SUBCLASS; @@ -216,13 +219,18 @@ static void test_customdraw(void) { SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0)); /* Put cursor inside window, tooltip will appear immediately */ - SetCursorPos(100, 100); + GetWindowRect( parent, &rect ); + SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 ); flush_events(200); - /* Check CustomDraw results */ - ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls, - "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages, - expectedResults[iterationNumber].ExpectedCalls); + if (CD_Stages) + { + /* Check CustomDraw results */ + ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls || + broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */ + "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages, + expectedResults[iterationNumber].ExpectedCalls); + } /* Clean up */ DestroyWindow(hwndTip); @@ -232,14 +240,63 @@ static void test_customdraw(void) { } +static const CHAR testcallbackA[] = "callback"; + +static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_NOTIFY && lParam) + { + NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam; + + if (ttnmdi->hdr.code == TTN_GETDISPINFOA) + lstrcpy(ttnmdi->lpszText, testcallbackA); + } + + return DefWindowProcA(hwnd, message, wParam, lParam); +} + +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 = "Tooltips test parent class"; + return RegisterClassA(&cls); +} + +static HWND create_parent_window(void) +{ + if (!register_parent_wnd_class()) + return NULL; + + return CreateWindowEx(0, "Tooltips test parent class", + "Tooltips test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); +} + static void test_gettext(void) { - HWND hwnd; + HWND hwnd, notify; TTTOOLINFOA toolinfoA; TTTOOLINFOW toolinfoW; LRESULT r; - char bufA[10] = ""; + CHAR bufA[10] = ""; WCHAR bufW[10] = { 0 }; + static const CHAR testtipA[] = "testtip"; + + notify = create_parent_window(); + ok(notify != NULL, "Expected notification window to be created\n"); /* For bug 14790 - lpszText is NULL */ hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, @@ -247,6 +304,8 @@ static void test_gettext(void) NULL, NULL, NULL, 0); assert(hwnd); + /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */ + /* otherwise it crashes on the NULL lpszText */ toolinfoA.cbSize = sizeof(TTTOOLINFOA); toolinfoA.hwnd = NULL; toolinfoA.hinst = GetModuleHandleA(NULL); @@ -256,7 +315,6 @@ static void test_gettext(void) toolinfoA.lParam = 0xdeadbeef; GetClientRect(hwnd, &toolinfoA.rect); r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); - ok(r, "Adding the tool to the tooltip failed\n"); if (r) { toolinfoA.hwnd = NULL; @@ -265,8 +323,65 @@ static void test_gettext(void) SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n"); } + else + { + win_skip( "Old comctl32, not testing NULL text\n" ); + DestroyWindow( hwnd ); + return; + } + + /* add another tool with text */ + toolinfoA.cbSize = sizeof(TTTOOLINFOA); + toolinfoA.hwnd = NULL; + toolinfoA.hinst = GetModuleHandleA(NULL); + toolinfoA.uFlags = 0; + toolinfoA.uId = 0x1235ABCD; + strcpy(bufA, testtipA); + toolinfoA.lpszText = bufA; + toolinfoA.lParam = 0xdeadbeef; + GetClientRect(hwnd, &toolinfoA.rect); + r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); + ok(r, "Adding the tool to the tooltip failed\n"); + if (r) + { + DWORD length; + + length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); + ok(length == 0, "Expected 0, got %d\n", length); + + toolinfoA.hwnd = NULL; + toolinfoA.uId = 0x1235ABCD; + toolinfoA.lpszText = bufA; + SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); + ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n"); + + length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); + ok(length == 0, "Expected 0, got %d\n", length); + } + + /* add another with callback text */ + toolinfoA.cbSize = sizeof(TTTOOLINFOA); + toolinfoA.hwnd = notify; + toolinfoA.hinst = GetModuleHandleA(NULL); + toolinfoA.uFlags = 0; + toolinfoA.uId = 0x1236ABCD; + toolinfoA.lpszText = LPSTR_TEXTCALLBACKA; + toolinfoA.lParam = 0xdeadbeef; + GetClientRect(hwnd, &toolinfoA.rect); + r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); + ok(r, "Adding the tool to the tooltip failed\n"); + if (r) + { + toolinfoA.hwnd = notify; + toolinfoA.uId = 0x1236ABCD; + toolinfoA.lpszText = bufA; + SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); + ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0, + "lpszText should be an (%s) string\n", testcallbackA); + } DestroyWindow(hwnd); + DestroyWindow(notify); SetLastError(0xdeadbeef); hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, @@ -303,6 +418,208 @@ static void test_gettext(void) DestroyWindow(hwnd); } +static void test_ttm_gettoolinfo(void) +{ + TTTOOLINFOA ti; + TTTOOLINFOW tiW; + HWND hwnd; + DWORD r; + + hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, + 10, 10, 300, 100, + NULL, NULL, NULL, 0); + + ti.cbSize = TTTOOLINFOA_V2_SIZE; + ti.hwnd = NULL; + ti.hinst = GetModuleHandleA(NULL); + ti.uFlags = 0; + ti.uId = 0x1234ABCD; + ti.lpszText = NULL; + ti.lParam = 0xdeadbeef; + GetClientRect(hwnd, &ti.rect); + r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); + ok(r, "Adding the tool to the tooltip failed\n"); + + ti.cbSize = TTTOOLINFOA_V2_SIZE; + ti.lParam = 0xaaaaaaaa; + r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti); + ok(r, "Getting tooltip info failed\n"); + ok(0xdeadbeef == ti.lParam || + broken(0xdeadbeef != ti.lParam), /* comctl32 < 5.81 */ + "Expected 0xdeadbeef, got %lx\n", ti.lParam); + + tiW.cbSize = TTTOOLINFOW_V2_SIZE; + tiW.hwnd = NULL; + tiW.uId = 0x1234ABCD; + tiW.lParam = 0xaaaaaaaa; + r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW); + ok(r, "Getting tooltip info failed\n"); + ok(0xdeadbeef == tiW.lParam || + broken(0xdeadbeef != tiW.lParam), /* comctl32 < 5.81 */ + "Expected 0xdeadbeef, got %lx\n", tiW.lParam); + + ti.cbSize = TTTOOLINFOA_V2_SIZE; + ti.uId = 0x1234ABCD; + ti.lParam = 0xaaaaaaaa; + SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti); + + ti.cbSize = TTTOOLINFOA_V2_SIZE; + ti.lParam = 0xdeadbeef; + r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti); + ok(r, "Getting tooltip info failed\n"); + ok(0xaaaaaaaa == ti.lParam || + broken(0xaaaaaaaa != ti.lParam), /* comctl32 < 5.81 */ + "Expected 0xaaaaaaaa, got %lx\n", ti.lParam); + + DestroyWindow(hwnd); + + /* 1. test size parameter validation rules (ansi messages) */ + hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, + 10, 10, 300, 100, + NULL, NULL, NULL, 0); + + ti.cbSize = TTTOOLINFOA_V1_SIZE - 1; + ti.hwnd = NULL; + ti.hinst = GetModuleHandleA(NULL); + ti.uFlags = 0; + ti.uId = 0x1234ABCD; + ti.lpszText = NULL; + ti.lParam = 0xdeadbeef; + GetClientRect(hwnd, &ti.rect); + r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + ti.cbSize = TTTOOLINFOA_V1_SIZE - 1; + ti.hwnd = NULL; + ti.uId = 0x1234ABCD; + SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + ti.cbSize = TTTOOLINFOA_V2_SIZE - 1; + ti.hwnd = NULL; + ti.hinst = GetModuleHandleA(NULL); + ti.uFlags = 0; + ti.uId = 0x1234ABCD; + ti.lpszText = NULL; + ti.lParam = 0xdeadbeef; + GetClientRect(hwnd, &ti.rect); + r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + ti.cbSize = TTTOOLINFOA_V2_SIZE - 1; + ti.hwnd = NULL; + ti.uId = 0x1234ABCD; + SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + ti.cbSize = TTTOOLINFOA_V2_SIZE + 1; + ti.hwnd = NULL; + ti.hinst = GetModuleHandleA(NULL); + ti.uFlags = 0; + ti.uId = 0x1234ABCD; + ti.lpszText = NULL; + ti.lParam = 0xdeadbeef; + GetClientRect(hwnd, &ti.rect); + r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + ti.cbSize = TTTOOLINFOA_V2_SIZE + 1; + ti.hwnd = NULL; + ti.uId = 0x1234ABCD; + SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); + r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + DestroyWindow(hwnd); + + /* 2. test size parameter validation rules (w-messages) */ + 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; + } + + tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1; + tiW.hwnd = NULL; + tiW.hinst = GetModuleHandleA(NULL); + tiW.uFlags = 0; + tiW.uId = 0x1234ABCD; + tiW.lpszText = NULL; + tiW.lParam = 0xdeadbeef; + GetClientRect(hwnd, &tiW.rect); + r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1; + tiW.hwnd = NULL; + tiW.uId = 0x1234ABCD; + SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1; + tiW.hwnd = NULL; + tiW.hinst = GetModuleHandleA(NULL); + tiW.uFlags = 0; + tiW.uId = 0x1234ABCD; + tiW.lpszText = NULL; + tiW.lParam = 0xdeadbeef; + GetClientRect(hwnd, &tiW.rect); + r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1; + tiW.hwnd = NULL; + tiW.uId = 0x1234ABCD; + SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1; + tiW.hwnd = NULL; + tiW.hinst = GetModuleHandleA(NULL); + tiW.uFlags = 0; + tiW.uId = 0x1234ABCD; + tiW.lpszText = NULL; + tiW.lParam = 0xdeadbeef; + GetClientRect(hwnd, &tiW.rect); + r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW); + ok(r, "Adding the tool to the tooltip failed\n"); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + /* looks like TTM_DELTOOLW doesn't work with invalid size */ + tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1; + tiW.hwnd = NULL; + tiW.uId = 0x1234ABCD; + SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(1, r); + + tiW.cbSize = TTTOOLINFOW_V2_SIZE; + tiW.hwnd = NULL; + tiW.uId = 0x1234ABCD; + SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); + r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); + expect(0, r); + + DestroyWindow(hwnd); +} + START_TEST(tooltips) { InitCommonControls(); @@ -310,4 +627,5 @@ START_TEST(tooltips) test_create_tooltip(); test_customdraw(); test_gettext(); + test_ttm_gettoolinfo(); } diff --git a/rostests/winetests/comctl32/trackbar.c b/rostests/winetests/comctl32/trackbar.c index d94ffe9a28c..68261d833fb 100644 --- a/rostests/winetests/comctl32/trackbar.c +++ b/rostests/winetests/comctl32/trackbar.c @@ -30,32 +30,10 @@ #define PARENT_SEQ_INDEX 0 #define TRACKBAR_SEQ_INDEX 1 +HWND hWndParent; static struct msg_sequence *sequences[NUM_MSG_SEQUENCE]; -static const struct message create_parent_wnd_seq[] = { - { WM_GETMINMAXINFO, sent }, - { WM_NCCREATE, sent }, - { WM_NCCALCSIZE, sent|wparam, 0 }, - { WM_CREATE, sent }, - { WM_SHOWWINDOW, sent|wparam, 1 }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_QUERYNEWPALETTE, sent|optional }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, - { WM_ACTIVATE, sent|wparam, 1 }, - { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, - { WM_IME_NOTIFY, sent|defwinproc|optional }, - { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, - /* Win9x adds SWP_NOZORDER below */ - { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, - { WM_NCCALCSIZE, sent|wparam|optional, 1 }, - { WM_SIZE, sent }, - { WM_MOVE, sent }, - { 0 } -}; - static const struct message create_trackbar_wnd_seq[] = { {0} }; @@ -81,12 +59,12 @@ static const struct message parent_create_trackbar_wnd_seq[] = { static const struct message parent_new_window_test_seq[] = { { WM_QUERYNEWPALETTE, sent|optional }, - { WM_WINDOWPOSCHANGING, sent}, - { WM_NCACTIVATE, sent}, - { PBT_APMRESUMECRITICAL, sent}, + { WM_WINDOWPOSCHANGING, sent|optional}, + { WM_NCACTIVATE, sent|optional}, + { PBT_APMRESUMECRITICAL, sent|optional}, { WM_IME_SETCONTEXT, sent|defwinproc|optional}, { WM_IME_NOTIFY, sent|defwinproc|optional}, - { WM_SETFOCUS, sent|defwinproc}, + { WM_SETFOCUS, sent|defwinproc|optional}, { WM_NOTIFYFORMAT, sent}, { WM_QUERYUISTATE, sent|optional}, {0} @@ -386,11 +364,6 @@ static const struct message ignore_selection_test_seq[] = { {0} }; -struct subclass_info -{ - WNDPROC oldproc; -}; - static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ static LONG defwndproc_counter = 0; LRESULT ret; @@ -452,7 +425,7 @@ static HWND create_parent_window(void){ } static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ - struct subclass_info *info = (struct subclass_info *) GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -467,36 +440,27 @@ static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wPa add_message(sequences, TRACKBAR_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } static HWND create_trackbar(DWORD style, HWND parent){ - struct subclass_info *info; HWND hWndTrack; + WNDPROC oldproc; RECT rect; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - GetClientRect(parent, &rect); hWndTrack = CreateWindowEx( 0, TRACKBAR_CLASS,"Trackbar Control", style, rect.right,rect.bottom, 100, 50, parent, NULL,GetModuleHandleA(NULL) ,NULL); - if (!hWndTrack) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!hWndTrack) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndTrack, GWLP_WNDPROC, (LONG_PTR)trackbar_subclass_proc); - - SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hWndTrack, GWLP_WNDPROC, (LONG_PTR)trackbar_subclass_proc); + SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)oldproc); return hWndTrack; } @@ -785,40 +749,63 @@ static void test_thumb_length(HWND hWndTrackbar){ static void test_tic_settings(HWND hWndTrackbar){ int r; - flush_sequences(sequences, NUM_MSG_SEQUENCE); /* testing TBM_SETTIC */ /* Set tics at 5 and 10 */ /* 0 and 20 are out of range and should not be set */ + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0, 0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0, 0); + expect(5, r); + + flush_sequences(sequences, NUM_MSG_SEQUENCE); r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 0); ok(r == FALSE, "Expected FALSE, got %d\n", r); r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 5); - todo_wine{ - ok(r == TRUE, "Expected TRUE, got %d\n", r); - r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 10); - ok(r == TRUE, "Expected TRUE, got %d\n", r); - } + ok(r == TRUE, "Expected TRUE, got %d\n", r); + r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 10); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 20); ok(r == FALSE, "Expected False, got %d\n", r); /* test TBM_SETTICFREQ */ SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(0, 10)); SendMessage(hWndTrackbar, TBM_SETTICFREQ, 2, 0); - r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); expect(6, r); SendMessage(hWndTrackbar, TBM_SETTICFREQ, 5, 0); - r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); expect(3, r); SendMessage(hWndTrackbar, TBM_SETTICFREQ, 15, 0); - r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); expect(2, r); /* test TBM_GETNUMTICS */ /* since TIC FREQ is 15, there should be only 2 tics now */ - r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); expect(2, r); ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_settings_test_seq, "tic settings test sequence", TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_tic_settings_test_seq, "parent tic settings test sequence", TRUE); + + /* range [0,0], freq = 1 */ + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 0); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); + expect(2, r); + /* range [0,1], freq = 1 */ + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 1); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); + expect(2, r); + /* range [0,2], freq = 1 */ + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 2); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); + expect(3, r); } static void test_tic_placement(HWND hWndTrackbar){ @@ -846,9 +833,7 @@ static void test_tic_placement(HWND hWndTrackbar){ r = SendMessage(hWndTrackbar, TBM_GETTIC, 2,0); expect(4, r); r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0); - todo_wine{ - expect(-1, r); - } + expect(-1, r); /* test TBM_GETTICPIC */ r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0); @@ -869,15 +854,13 @@ static void test_tool_tips(HWND hWndTrackbar){ flush_sequences(sequences, NUM_MSG_SEQUENCE); /* testing TBM_SETTIPSIDE */ r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_TOP, 0); - todo_wine{ - expect(0, r); - } + expect(TBTS_TOP, r); r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_LEFT, 0); - expect(0, r); + expect(TBTS_TOP, r); r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_BOTTOM, 0); - expect(1, r); + expect(TBTS_LEFT, r); r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_RIGHT, 0); - expect(2, r); + expect(TBTS_BOTTOM, r); /* testing TBM_SETTOOLTIPS */ hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0, @@ -967,17 +950,31 @@ static void test_ignore_selection(HWND hWndTrackbar){ ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE); } +static void test_initial_state(void) +{ + HWND hWnd; + DWORD ret; + + hWnd = create_trackbar(0, 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); + + DestroyWindow(hWnd); +} + START_TEST(trackbar) { DWORD style = WS_VISIBLE | TBS_TOOLTIPS | TBS_ENABLESELRANGE | TBS_FIXEDLENGTH | TBS_AUTOTICKS; HWND hWndTrackbar; - HWND hWndParent; init_msg_sequences(sequences, NUM_MSG_SEQUENCE); InitCommonControls(); - flush_sequences(sequences, NUM_MSG_SEQUENCE); - /* create parent window */ hWndParent = create_parent_window(); ok(hWndParent != NULL, "Failed to create parent Window!\n"); @@ -987,7 +984,6 @@ START_TEST(trackbar) return; } - ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create Parent Window", TRUE); flush_sequences(sequences, NUM_MSG_SEQUENCE); /* create trackbar with set styles */ @@ -1036,5 +1032,7 @@ START_TEST(trackbar) DestroyWindow(hWndTrackbar); + test_initial_state(); + DestroyWindow(hWndParent); } diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c index 05a52373ac3..848d4ca1d8e 100644 --- a/rostests/winetests/comctl32/treeview.c +++ b/rostests/winetests/comctl32/treeview.c @@ -35,110 +35,103 @@ const char *TEST_CALLBACK_TEXT = "callback_text"; #define NUM_MSG_SEQUENCES 1 -#define LISTVIEW_SEQ_INDEX 0 +#define TREEVIEW_SEQ_INDEX 0 + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES]; static const struct message FillRootSeq[] = { { TVM_INSERTITEM, sent }, - { TVM_GETITEM, sent }, { TVM_INSERTITEM, sent }, { 0 } }; -static const struct message DoTest1Seq[] = { - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, +static const struct message rootnone_select_seq[] = { + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, { 0 } }; -static const struct message DoTest2Seq[] = { - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, +static const struct message rootchild_select_seq[] = { + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, + { TVM_SELECTITEM, sent|wparam, 9 }, { 0 } }; -static const struct message DoTest3Seq[] = { +static const struct message getitemtext_seq[] = { { TVM_INSERTITEM, sent }, { TVM_GETITEM, sent }, { TVM_DELETEITEM, sent }, { 0 } }; -static const struct message DoFocusTestSeq[] = { +static const struct message focus_seq[] = { { TVM_INSERTITEM, sent }, { TVM_INSERTITEM, sent }, + { TVM_SELECTITEM, sent|wparam, 9 }, + /* The following end up out of order in wine */ { WM_WINDOWPOSCHANGING, sent|defwinproc }, - { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, + { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE }, { WM_WINDOWPOSCHANGED, sent|defwinproc }, { WM_SIZE, sent|defwinproc }, - { WM_WINDOWPOSCHANGING, sent }, - { WM_NCCALCSIZE, sent|wparam, 0x00000001 }, - { WM_WINDOWPOSCHANGED, sent }, - { WM_SIZE, sent|defwinproc }, - { WM_WINDOWPOSCHANGING, sent|defwinproc|optional }, - { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 0x00000001 }, - { WM_WINDOWPOSCHANGED, sent|defwinproc|optional }, - { WM_SIZE, sent|defwinproc|optional }, - { TVM_SELECTITEM, sent|wparam, 0x00000009 }, - /* The following end up out of order in wine */ { WM_PAINT, sent|defwinproc }, - { WM_NCPAINT, sent|wparam|defwinproc, 0x00000001 }, + { WM_NCPAINT, sent|wparam|defwinproc, 1 }, { WM_ERASEBKGND, sent|defwinproc }, { TVM_EDITLABEL, sent }, - { WM_COMMAND, sent|wparam|defwinproc, 0x04000000 }, - { WM_COMMAND, sent|wparam|defwinproc, 0x03000000 }, - { WM_PARENTNOTIFY, sent|wparam|defwinproc, 0x00000001 }, + { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) }, + { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) }, + { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) }, { WM_KILLFOCUS, sent|defwinproc }, { WM_PAINT, sent|defwinproc }, { WM_IME_SETCONTEXT, sent|defwinproc|optional }, - { WM_COMMAND, sent|wparam|defwinproc, 0x01000000}, - { WM_ERASEBKGND, sent|defwinproc }, + { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) }, + { WM_ERASEBKGND, sent|defwinproc|optional }, { WM_CTLCOLOREDIT, sent|defwinproc|optional }, { WM_CTLCOLOREDIT, sent|defwinproc|optional }, { 0 } }; -static const struct message TestGetSetBkColorSeq[] = { - { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff }, - { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, -1 }, +static const struct message test_get_set_bkcolor_seq[] = { + { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff }, + { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 }, { 0 } }; -static const struct message TestGetSetImageListSeq[] = { - { TVM_SETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_imagelist_seq[] = { + { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 }, + { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetIndentSeq[] = { - { TVM_SETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_indent_seq[] = { + { TVM_SETINDENT, sent|wparam|lparam, 0, 0 }, + { TVM_GETINDENT, sent|wparam|lparam, 0, 0 }, /* The actual amount to indent is dependent on the system for this message */ { TVM_SETINDENT, sent }, - { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_GETINDENT, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetInsertMarkColorSeq[] = { - { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_insertmarkcolor_seq[] = { + { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetItemSeq[] = { +static const struct message test_get_set_item_seq[] = { { TVM_GETITEM, sent }, { TVM_SETITEM, sent }, { TVM_GETITEM, sent }, @@ -146,57 +139,53 @@ static const struct message TestGetSetItemSeq[] = { { 0 } }; -static const struct message TestGetSetItemHeightSeq[] = { - { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0x00000000 }, - { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0x00000000 }, - { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0x00000000, 0x00000000 }, - { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 0x00000009, 0x00000000 }, - { WM_WINDOWPOSCHANGING, sent|defwinproc }, - { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, - { WM_WINDOWPOSCHANGED, sent|defwinproc }, - { WM_SIZE, sent|defwinproc }, - { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_itemheight_seq[] = { + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, + { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetScrollTimeSeq[] = { - { TVM_SETSCROLLTIME, sent|wparam|lparam, 0x00000014, 0x00000000 }, - { TVM_GETSCROLLTIME, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_scrolltime_seq[] = { + { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 }, + { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetTextColorSeq[] = { - { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff }, - { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, -1 }, +static const struct message test_get_set_textcolor_seq[] = { + { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) }, + { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 }, + { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE }, { 0 } }; -static const struct message TestGetSetToolTipsSeq[] = { - { WM_COMMAND, sent|wparam, 0x02000000 }, - { WM_PARENTNOTIFY, sent|wparam|defwinproc, 0x00020002 }, - { TVM_SETTOOLTIPS, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETTOOLTIPS, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_tooltips_seq[] = { + { WM_KILLFOCUS, sent }, + { WM_IME_SETCONTEXT, sent|optional }, + { WM_IME_NOTIFY, sent|optional }, + { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 }, + { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, { 0 } }; -static const struct message TestGetSetUnicodeFormatSeq[] = { - { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000001, 0x00000000 }, - { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 }, +static const struct message test_get_set_unicodeformat_seq[] = { + { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 }, + { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, + { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, + { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, + { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, { 0 } }; static HWND hMainWnd; -static HWND hTree, hEdit; static HTREEITEM hRoot, hChild; static int pos = 0; @@ -231,21 +220,84 @@ static void IdentifyItem(HTREEITEM hItem) AddItem('?'); } -static void FillRoot(void) +/* This function hooks in and records all messages to the treeview control */ +static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static LONG defwndproc_counter = 0; + LRESULT ret; + struct message msg; + WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(MsgSequences, TREEVIEW_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND create_treeview_control(void) +{ + WNDPROC pOldWndProc; + HWND hTree; + + hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE| + TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS, + 0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0); + + SetFocus(hTree); + + /* Record the old WNDPROC so we can call it after recording the messages */ + pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc); + SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc); + + return hTree; +} + +static void fill_tree(HWND hTree) { TVINSERTSTRUCTA ins; - TVITEM tvi; static CHAR root[] = "Root", child[] = "Child"; - Clear(); - AddItem('A'); ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; U(ins).item.pszText = root; hRoot = TreeView_InsertItem(hTree, &ins); + + ins.hParent = hRoot; + ins.hInsertAfter = TVI_FIRST; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = child; + hChild = TreeView_InsertItem(hTree, &ins); +} + +static void test_fillroot(void) +{ + TVITEM tvi; + HWND hTree; + + hTree = create_treeview_control(); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); + + fill_tree(hTree); + + Clear(); + AddItem('A'); assert(hRoot); + AddItem('B'); + assert(hChild); + AddItem('.'); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE); + ok(!strcmp(sequence, "AB."), "Item creation\n"); /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */ tvi.hItem = hRoot; @@ -254,19 +306,10 @@ static void FillRoot(void) ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage); ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage); - AddItem('B'); - ins.hParent = hRoot; - ins.hInsertAfter = TVI_FIRST; - U(ins).item.mask = TVIF_TEXT; - U(ins).item.pszText = child; - hChild = TreeView_InsertItem(hTree, &ins); - assert(hChild); - AddItem('.'); - - ok(!strcmp(sequence, "AB."), "Item creation\n"); + DestroyWindow(hTree); } -static void TestCallback(void) +static void test_callback(void) { HTREEITEM hRoot; HTREEITEM hItem1, hItem2; @@ -275,8 +318,13 @@ static void TestCallback(void) CHAR test_string[] = "Test_string"; CHAR buf[128]; LRESULT ret; + HWND hTree; - TreeView_DeleteAllItems(hTree); + hTree = create_treeview_control(); + fill_tree(hTree); + + ret = TreeView_DeleteAllItems(hTree); + ok(ret == TRUE, "ret\n"); ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; @@ -301,7 +349,8 @@ static void TestCallback(void) assert(hItem1); tvi.hItem = hItem1; - TreeView_GetItem(hTree, &tvi); + ret = TreeView_GetItem(hTree, &tvi); + ok(ret == TRUE, "ret\n"); ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n", tvi.pszText, test_string); @@ -310,7 +359,8 @@ static void TestCallback(void) ret = TreeView_SetItem(hTree, &tvi); ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret); tvi.pszText = buf; - TreeView_GetItem(hTree, &tvi); + ret = TreeView_GetItem(hTree, &tvi); + ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret); ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", tvi.pszText, TEST_CALLBACK_TEXT); @@ -319,57 +369,90 @@ static void TestCallback(void) assert(hItem2); tvi.hItem = hItem2; memset(buf, 0, sizeof(buf)); - TreeView_GetItem(hTree, &tvi); + ret = TreeView_GetItem(hTree, &tvi); + ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret); ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", tvi.pszText, TEST_CALLBACK_TEXT); + + DestroyWindow(hTree); } -static void DoTest1(void) +static void test_select(void) { BOOL r; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + /* root-none select tests */ + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); r = TreeView_SelectItem(hTree, NULL); + expect(TRUE, r); Clear(); AddItem('1'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('2'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('3'); r = TreeView_SelectItem(hTree, NULL); + expect(TRUE, r); AddItem('4'); r = TreeView_SelectItem(hTree, NULL); + expect(TRUE, r); AddItem('5'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('.'); ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n"); -} + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq, + "root-none select seq", FALSE); -static void DoTest2(void) -{ - BOOL r; + /* root-child select tests */ + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); r = TreeView_SelectItem(hTree, NULL); + expect(TRUE, r); + Clear(); AddItem('1'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('2'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('3'); r = TreeView_SelectItem(hTree, hChild); + expect(TRUE, r); AddItem('4'); r = TreeView_SelectItem(hTree, hChild); + expect(TRUE, r); AddItem('5'); r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); AddItem('.'); ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n"); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq, + "root-child select seq", FALSE); + + DestroyWindow(hTree); } -static void DoTest3(void) +static void test_getitemtext(void) { TVINSERTSTRUCTA ins; HTREEITEM hChild; TVITEM tvi; + HWND hTree; - int nBufferSize = 80; CHAR szBuffer[80] = "Blah"; + int nBufferSize = sizeof(szBuffer)/sizeof(CHAR); + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* add an item without TVIF_TEXT mask and pszText == NULL */ ins.hParent = hRoot; @@ -389,14 +472,24 @@ static void DoTest3(void) SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi ); ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer); ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n"); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE); + + DestroyWindow(hTree); } -static void DoFocusTest(void) +static void test_focus(void) { TVINSERTSTRUCTA ins; static CHAR child1[] = "Edit", child2[] = "A really long string"; HTREEITEM hChild1, hChild2; + HWND hTree; + HWND hEdit; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* This test verifies that when a label is being edited, scrolling * the treeview does not cause the label to lose focus. To test @@ -416,38 +509,57 @@ static void DoFocusTest(void) assert(hChild2); ShowWindow(hMainWnd,SW_SHOW); - /* Using SendMessageA since Win98 doesn't have default unicode support */ SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild); hEdit = TreeView_EditLabel(hTree, hChild); ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN); ok(GetFocus() == hEdit, "Edit control should have focus\n"); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE); + + DestroyWindow(hTree); } -static void TestGetSetBkColor(void) +static void test_get_set_bkcolor(void) { COLORREF crColor = RGB(0,0,0); + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* If the value is -1, the control is using the system color for the background color. */ crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 ); ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor); /* Test for black background */ - SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(0,0,0) ); + SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0) ); crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 ); ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor); /* Test for white background */ - SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(255,255,255) ); + SendMessage( hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255) ); crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 ); ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor); /* Reset the default background */ SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 ); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq, + "test get set bkcolor", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetImageList(void) +static void test_get_set_imagelist(void) { HIMAGELIST hImageList = NULL; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* Test a NULL HIMAGELIST */ SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList ); @@ -455,13 +567,24 @@ static void TestGetSetImageList(void) ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList); /* TODO: Test an actual image list */ + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq, + "test get imagelist", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetIndent(void) +static void test_get_set_indent(void) { int ulIndent = -1; int ulMinIndent = -1; int ulMoreThanTwiceMin = -1; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* Finding the minimum indent */ SendMessage( hTree, TVM_SETINDENT, 0, 0 ); @@ -472,21 +595,44 @@ static void TestGetSetIndent(void) SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 ); ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 ); ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq, + "test get set indent", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetInsertMarkColor(void) +static void test_get_set_insertmark(void) { COLORREF crColor = RGB(0,0,0); + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); + SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor ); crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 ); ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq, + "test get set insertmark color", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetItem(void) +static void test_get_set_item(void) { TVITEM tviRoot = {0}; int nBufferSize = 80; char szBuffer[80] = {0}; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* Test the root item */ tviRoot.hItem = hRoot; @@ -507,12 +653,23 @@ static void TestGetSetItem(void) memset(szBuffer, 0, nBufferSize); strncpy(szBuffer, "Root", nBufferSize); SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot ); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq, + "test get set item", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetItemHeight(void) +static void test_get_set_itemheight(void) { int ulOldHeight = 0; int ulNewHeight = 0; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* Assuming default height to begin with */ ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 ); @@ -531,42 +688,77 @@ static void TestGetSetItemHeight(void) SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 ); ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 ); ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq, + "test get set item height", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetScrollTime(void) +static void test_get_set_scrolltime(void) { int ulExpectedTime = 20; int ulTime = 0; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); + SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 ); ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 ); ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq, + "test get set scroll time", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetTextColor(void) +static void test_get_set_textcolor(void) { /* If the value is -1, the control is using the system color for the text color. */ COLORREF crColor = RGB(0,0,0); + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); + crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 ); ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor); /* Test for black text */ - SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(0,0,0) ); + SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0) ); crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 ); ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor); /* Test for white text */ - SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(255,255,255) ); + SendMessage( hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255) ); crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 ); ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor); /* Reset the default text color */ - SendMessage( hTree, TVM_SETTEXTCOLOR, 0, -1 ); + SendMessage( hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE ); + + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq, + "test get set text color", FALSE); + + DestroyWindow(hTree); } -static void TestGetSetToolTips(void) +static void test_get_set_tooltips(void) { HWND hwndLastToolTip = NULL; HWND hPopupTreeView; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */ hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL); @@ -577,13 +769,23 @@ static void TestGetSetToolTips(void) hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 ); ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq, + "test get set tooltips", TRUE); + /* TODO: Add a test of an actual tooltip */ + DestroyWindow(hTree); } -static void TestGetSetUnicodeFormat(void) +static void test_get_set_unicodeformat(void) { BOOL bPreviousSetting = 0; BOOL bNewSetting = 0; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); /* Set to Unicode */ bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 ); @@ -596,114 +798,17 @@ static void TestGetSetUnicodeFormat(void) ok(bNewSetting == 0, "ANSI setting did not work.\n"); /* Revert to original setting */ - SendMessage( hTree, TVM_SETUNICODEFORMAT, (LPARAM)bPreviousSetting, 0 ); -} + SendMessage( hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0 ); -static void TestGetSet(void) -{ - /* TVM_GETBKCOLOR and TVM_SETBKCOLOR */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetBkColor(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetBkColorSeq, - "TestGetSetBkColor", FALSE); + ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq, + "test get set unicode format", FALSE); - /* TVM_GETIMAGELIST and TVM_SETIMAGELIST */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetImageList(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetImageListSeq, - "TestGetImageList", FALSE); - - /* TVM_SETINDENT and TVM_GETINDENT */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetIndent(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetIndentSeq, - "TestGetSetIndent", FALSE); - - /* TVM_GETINSERTMARKCOLOR and TVM_GETINSERTMARKCOLOR */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetInsertMarkColor(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetInsertMarkColorSeq, - "TestGetSetInsertMarkColor", FALSE); - - /* TVM_GETITEM and TVM_SETITEM */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetItem(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetItemSeq, - "TestGetSetItem", FALSE); - - /* TVM_GETITEMHEIGHT and TVM_SETITEMHEIGHT */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetItemHeight(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetItemHeightSeq, - "TestGetSetItemHeight", FALSE); - - /* TVM_GETSCROLLTIME and TVM_SETSCROLLTIME */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetScrollTime(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetScrollTimeSeq, - "TestGetSetScrollTime", FALSE); - - /* TVM_GETTEXTCOLOR and TVM_SETTEXTCOLOR */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetTextColor(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetTextColorSeq, - "TestGetSetTextColor", FALSE); - - /* TVM_GETTOOLTIPS and TVM_SETTOOLTIPS */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetToolTips(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetToolTipsSeq, - "TestGetSetToolTips", TRUE); - - /* TVM_GETUNICODEFORMAT and TVM_SETUNICODEFORMAT */ - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - TestGetSetUnicodeFormat(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetUnicodeFormatSeq, - "TestGetSetUnicodeFormat", FALSE); -} - -/* This function hooks in and records all messages to the treeview control */ -static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - static LONG defwndproc_counter = 0; - LRESULT ret; - struct message msg; - WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - - msg.message = message; - msg.flags = sent|wparam|lparam; - if (defwndproc_counter) msg.flags |= defwinproc; - msg.wParam = wParam; - msg.lParam = lParam; - add_message(MsgSequences, LISTVIEW_SEQ_INDEX, &msg); - - defwndproc_counter++; - ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam); - defwndproc_counter--; - - return ret; + DestroyWindow(hTree); } static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - WNDPROC pOldWndProc; - switch(msg) { - - case WM_CREATE: - { - hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE| - TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS, - 0, 0, 120, 100, hWnd, (HMENU)100, GetModuleHandleA(0), 0); - - SetFocus(hTree); - - /* Record the old WNDPROC so we can call it after recording the messages */ - pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc); - SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc); - - return 0; - } case WM_NOTIFY: { NMHDR *pHdr = (NMHDR *)lParam; @@ -729,15 +834,12 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa } return 0; } + case TVN_ENDLABELEDIT: return TRUE; } } return 0; } - case WM_SIZE: - MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); - break; - case WM_DESTROY: PostQuitMessage(0); break; @@ -748,13 +850,17 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa return 0L; } -static void TestExpandInvisible(void) +static void test_expandinvisible(void) { static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"}; TVINSERTSTRUCTA ins; HTREEITEM node[5]; RECT dummyRect; BOOL nodeVisible; + LRESULT ret; + HWND hTree; + + hTree = create_treeview_control(); /* The test builds the following tree and expands then node 1, while node 0 is collapsed. * @@ -766,8 +872,8 @@ static void TestExpandInvisible(void) * */ - TreeView_DeleteAllItems(hTree); - + ret = TreeView_DeleteAllItems(hTree); + ok(ret == TRUE, "ret\n"); ins.hParent = TVI_ROOT; ins.hInsertAfter = TVI_ROOT; U(ins).item.mask = TVIF_TEXT; @@ -815,8 +921,121 @@ static void TestExpandInvisible(void) ok(!nodeVisible, "Node 3 should not be visible.\n"); nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE); ok(!nodeVisible, "Node 4 should not be visible.\n"); + + DestroyWindow(hTree); } +static void test_itemedit(void) +{ + DWORD r; + HWND edit; + TVITEMA item; + CHAR buff[2]; + HWND hTree; + + hTree = create_treeview_control(); + fill_tree(hTree); + + /* try with null item */ + edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, 0); + ok(!IsWindow(edit), "Expected valid handle\n"); + + /* trigger edit */ + edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot); + ok(IsWindow(edit), "Expected valid handle\n"); + /* item shouldn't be selected automatically after TVM_EDITLABEL */ + r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED); + expect(0, r); + /* try to cancel with wrong edit handle */ + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); + expect(0, r); + ok(IsWindow(edit), "Expected edit control to be valid\n"); + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); + expect(0, r); + ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); + /* try to cancel without creating edit */ + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0); + expect(0, r); + + /* try to cancel with wrong (not null) handle */ + edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot); + ok(IsWindow(edit), "Expected valid handle\n"); + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree); + expect(0, r); + ok(IsWindow(edit), "Expected edit control to be valid\n"); + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); + expect(0, r); + + /* remove selection after starting edit */ + r = TreeView_SelectItem(hTree, hRoot); + expect(TRUE, r); + edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot); + ok(IsWindow(edit), "Expected valid handle\n"); + r = TreeView_SelectItem(hTree, NULL); + expect(TRUE, r); + /* alter text */ + strncpy(buff, "x", sizeof(buff)/sizeof(CHAR)); + r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff); + expect(TRUE, r); + r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit); + expect(0, r); + ok(!IsWindow(edit), "Expected edit control to be destroyed\n"); + /* check that text is saved */ + item.mask = TVIF_TEXT; + item.hItem = hRoot; + item.pszText = buff; + item.cchTextMax = sizeof(buff)/sizeof(CHAR); + r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item); + expect(TRUE, r); + ok(!strcmp("x", buff), "Expected item text to change\n"); + + DestroyWindow(hTree); +} + +static void test_treeview_classinfo(void) +{ + WNDCLASSA cls; + + memset(&cls, 0, sizeof(cls)); + GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls); + ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground); + ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style); + expect(0, cls.cbClsExtra); +} + +static void test_get_linecolor(void) +{ + COLORREF clr; + HWND hTree; + + hTree = create_treeview_control(); + + /* newly created control has default color */ + clr = (COLORREF)SendMessage(hTree, TVM_GETLINECOLOR, 0, 0); + if (clr == 0) + win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n"); + else + expect(CLR_DEFAULT, clr); + + DestroyWindow(hTree); +} + +static void test_get_insertmarkcolor(void) +{ + COLORREF clr; + HWND hTree; + + hTree = create_treeview_control(); + + /* newly created control has default color */ + clr = (COLORREF)SendMessage(hTree, TVM_GETINSERTMARKCOLOR, 0, 0); + if (clr == 0) + win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n"); + else + expect(CLR_DEFAULT, clr); + + DestroyWindow(hTree); +} START_TEST(treeview) { @@ -851,41 +1070,32 @@ START_TEST(treeview) wc.lpfnWndProc = MyWndProc; RegisterClassA(&wc); - hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0); - if ( !ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n") ) - return; + ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n"); + if (!hMainWnd) return; - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - FillRoot(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE); - - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - DoTest1(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest1Seq, "DoTest1", FALSE); - - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - DoTest2(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest2Seq, "DoTest2", FALSE); - - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - DoTest3(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest3Seq, "DoTest3", FALSE); - - flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); - DoFocusTest(); - ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoFocusTestSeq, "DoFocusTest", TRUE); - - /* Sequences tested inside due to number */ - TestGetSet(); - - /* Clears all the previous items */ - TestCallback(); - - /* Clears all the previous items */ - TestExpandInvisible(); + test_fillroot(); + test_select(); + test_getitemtext(); + test_focus(); + test_get_set_bkcolor(); + test_get_set_imagelist(); + test_get_set_indent(); + test_get_set_insertmark(); + test_get_set_item(); + test_get_set_itemheight(); + test_get_set_scrolltime(); + test_get_set_textcolor(); + test_get_linecolor(); + test_get_insertmarkcolor(); + test_get_set_tooltips(); + test_get_set_unicodeformat(); + test_callback(); + test_expandinvisible(); + test_itemedit(); + test_treeview_classinfo(); PostMessageA(hMainWnd, WM_CLOSE, 0, 0); while(GetMessageA(&msg,0,0,0)) { diff --git a/rostests/winetests/comctl32/updown.c b/rostests/winetests/comctl32/updown.c index 433c190ae97..859b3a0a988 100644 --- a/rostests/winetests/comctl32/updown.c +++ b/rostests/winetests/comctl32/updown.c @@ -59,38 +59,15 @@ #define EDIT_SEQ_INDEX 1 #define UPDOWN_SEQ_INDEX 2 -static HWND parent_wnd, edit, updown; +#define UPDOWN_ID 0 +#define BUDDY_ID 1 + +static HWND parent_wnd, g_edit; + +static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; -static const struct message create_parent_wnd_seq[] = { - { WM_GETMINMAXINFO, sent }, - { WM_NCCREATE, sent }, - { WM_NCCALCSIZE, sent|wparam, 0 }, - { WM_CREATE, sent }, - { WM_SHOWWINDOW, sent|wparam, 1 }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_QUERYNEWPALETTE, sent|optional }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, - { WM_ACTIVATE, sent|wparam, 1 }, - { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, - { WM_IME_NOTIFY, sent|defwinproc|optional }, - { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, - /* Win9x adds SWP_NOZORDER below */ - { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, - { WM_NCCALCSIZE, sent|wparam|optional, 1 }, - { WM_SIZE, sent }, - { WM_MOVE, sent }, - { 0 } -}; - -static const struct message add_edit_to_parent_seq[] = { - { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, - { 0 } -}; - static const struct message add_updown_with_edit_seq[] = { { WM_WINDOWPOSCHANGING, sent }, { WM_NCCALCSIZE, sent|wparam, TRUE }, @@ -182,12 +159,8 @@ static const struct message test_updown_unicode_seq[] = { { 0 } }; -static const struct message test_updown_destroy_seq[] = { - { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent}, - { WM_WINDOWPOSCHANGED, sent}, - { WM_DESTROY, sent}, - { WM_NCDESTROY, sent}, +static const struct message test_updown_pos_nochange_seq[] = { + { WM_GETTEXT, sent|id, 0, 0, BUDDY_ID }, { 0 } }; @@ -254,14 +227,9 @@ static HWND create_parent_window(void) GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); } -struct subclass_info -{ - WNDPROC oldproc; -}; - static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -273,43 +241,37 @@ static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.id = BUDDY_ID; add_message(sequences, EDIT_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } static HWND create_edit_control(void) { - struct subclass_info *info; + WNDPROC oldproc; + HWND hwnd; RECT rect; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - GetClientRect(parent_wnd, &rect); - edit = CreateWindowExA(0, "EDIT", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, + hwnd = CreateWindowExA(0, WC_EDITA, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, rect.right, rect.bottom, parent_wnd, NULL, GetModuleHandleA(NULL), NULL); - if (!edit) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!hwnd) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, - (LONG_PTR)edit_subclass_proc); - SetWindowLongPtrA(edit, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)edit_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); - return edit; + return hwnd; } static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -321,46 +283,42 @@ static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wPara if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.id = UPDOWN_ID; add_message(sequences, UPDOWN_SEQ_INDEX, &msg); defwndproc_counter++; - ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); defwndproc_counter--; return ret; } -static HWND create_updown_control(void) +static HWND create_updown_control(DWORD style, HWND buddy) { - struct subclass_info *info; + WNDPROC oldproc; HWND updown; RECT rect; - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); - if (!info) - return NULL; - GetClientRect(parent_wnd, &rect); - updown = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_ALIGNRIGHT, - 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), edit, + updown = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | style, + 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), buddy, 100, 0, 50); - if (!updown) - { - HeapFree(GetProcessHeap(), 0, info); - return NULL; - } + if (!updown) return NULL; - info->oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC, - (LONG_PTR)updown_subclass_proc); - SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)info); + oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC, + (LONG_PTR)updown_subclass_proc); + SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)oldproc); return updown; } static void test_updown_pos(void) { + HWND updown; int r; + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); + flush_sequences(sequences, NUM_MSG_SEQUENCES); /* Set Range from 0 to 100 */ @@ -410,24 +368,63 @@ static void test_updown_pos(void) expect(1,HIWORD(r)); ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE); + + DestroyWindow(updown); + + /* there's no attempt to update buddy Edit if text didn't change */ + SetWindowTextA(g_edit, "50"); + updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit); + + /* test sequence only on 5.8x versions */ + r = SendMessage(updown, UDM_GETPOS32, 0, 0); + if (r) + { + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + r = SendMessage(updown, UDM_SETPOS, 0, 50); + expect(50,r); + + ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, + "test updown pos, no change", FALSE); + } + + DestroyWindow(updown); } static void test_updown_pos32(void) { + HWND updown; int r; int low, high; + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); + flush_sequences(sequences, NUM_MSG_SEQUENCES); /* Set the position to 0 to 1000 */ SendMessage(updown, UDM_SETRANGE32, 0 , 1000 ); + low = high = -1; r = SendMessage(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high ); + if (low == -1) + { + win_skip("UDM_SETRANGE32/UDM_GETRANGE32 not available\n"); + DestroyWindow(updown); + return; + } + expect(0,low); expect(1000,high); - /* Set position to 500, don't check return since it is unset*/ - SendMessage(updown, UDM_SETPOS32, 0 , 500 ); + /* Set position to 500 */ + r = SendMessage(updown, UDM_SETPOS32, 0 , 500 ); + if (!r) + { + win_skip("UDM_SETPOS32 and UDM_GETPOS32 need 5.80\n"); + DestroyWindow(updown); + return; + } + expect(50,r); /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */ @@ -464,30 +461,83 @@ static void test_updown_pos32(void) expect(1,high); ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE); + + DestroyWindow(updown); + + /* there's no attempt to update buddy Edit if text didn't change */ + SetWindowTextA(g_edit, "50"); + updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + r = SendMessage(updown, UDM_SETPOS32, 0, 50); + expect(50,r); + ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, + "test updown pos, no change", FALSE); + + DestroyWindow(updown); } static void test_updown_buddy(void) { - HWND buddyReturn; + HWND updown, buddyReturn, buddy; + WNDPROC proc; + DWORD style; + + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); flush_sequences(sequences, NUM_MSG_SEQUENCES); buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 ); - ok(buddyReturn == edit, "Expected edit handle\n"); + ok(buddyReturn == g_edit, "Expected edit handle\n"); - buddyReturn = (HWND)SendMessage(updown, UDM_SETBUDDY, (WPARAM) edit, 0); - ok(buddyReturn == edit, "Expected edit handle\n"); + buddyReturn = (HWND)SendMessage(updown, UDM_SETBUDDY, (WPARAM) g_edit, 0); + ok(buddyReturn == g_edit, "Expected edit handle\n"); buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 ); - ok(buddyReturn == edit, "Expected edit handle\n"); + ok(buddyReturn == g_edit, "Expected edit handle\n"); ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_buddy_seq, "test updown buddy", TRUE); ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "test updown buddy_edit", FALSE); + + DestroyWindow(updown); + + buddy = create_edit_control(); + proc = (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC); + + updown= create_updown_control(UDS_ALIGNRIGHT, buddy); + ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); + + style = GetWindowLongA(updown, GWL_STYLE); + SetWindowLongA(updown, GWL_STYLE, style | UDS_ARROWKEYS); + style = GetWindowLongA(updown, GWL_STYLE); + ok(style & UDS_ARROWKEYS, "Expected UDS_ARROWKEYS\n"); + /* no subclass if UDS_ARROWKEYS set after creation */ + ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); + + DestroyWindow(updown); + + updown= create_updown_control(UDS_ALIGNRIGHT | UDS_ARROWKEYS, buddy); + ok(proc != (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "Subclassing expected\n"); + + if (pSetWindowSubclass) + { + /* updown uses subclass helpers for buddy on >5.8x systems */ + ok(GetPropA(buddy, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); + } + + DestroyWindow(updown); + + DestroyWindow(buddy); } static void test_updown_base(void) { + HWND updown; int r; + CHAR text[10]; + + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -520,12 +570,36 @@ static void test_updown_base(void) expect(10,r); ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE); + + DestroyWindow(updown); + + /* switch base with buddy attached */ + updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); + + r = SendMessage(updown, UDM_SETPOS, 0, 10); + expect(50, r); + + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + ok(lstrcmpA(text, "10") == 0, "Expected '10', got '%s'\n", text); + + r = SendMessage(updown, UDM_SETBASE, 16, 0); + expect(10, r); + + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + /* FIXME: currently hex output isn't properly formatted, but for this + test only change from initial text matters */ + ok(lstrcmpA(text, "10") != 0, "Expected '0x000A', got '%s'\n", text); + + DestroyWindow(updown); } static void test_updown_unicode(void) { + HWND updown; int r; + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); + flush_sequences(sequences, NUM_MSG_SEQUENCES); /* Set it to ANSI, don't check return as we don't know previous state */ @@ -537,6 +611,12 @@ static void test_updown_unicode(void) r = SendMessage(updown, UDM_SETUNICODEFORMAT, 1 , 0); expect(0,r); r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0); + if (!r) + { + win_skip("UDM_SETUNICODEFORMAT not available\n"); + DestroyWindow(updown); + return; + } expect(1,r); /* And now set it back to ANSI */ @@ -546,49 +626,161 @@ static void test_updown_unicode(void) expect(0,r); ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE); + + DestroyWindow(updown); } - -static void test_create_updown_control(void) +static void test_updown_create(void) { CHAR text[MAX_PATH]; - - parent_wnd = create_parent_window(); - ok(parent_wnd != NULL, "Failed to create parent window!\n"); - ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE); + HWND updown; + RECT r; flush_sequences(sequences, NUM_MSG_SEQUENCES); - edit = create_edit_control(); - ok(edit != NULL, "Failed to create edit control\n"); - ok_sequence(sequences, PARENT_SEQ_INDEX, add_edit_to_parent_seq, "add edit control to parent", FALSE); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - updown = create_updown_control(); + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); ok(updown != NULL, "Failed to create updown control\n"); ok_sequence(sequences, PARENT_SEQ_INDEX, add_updown_to_parent_seq, "add updown control to parent", TRUE); ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "add updown control with edit", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); - GetWindowTextA(edit, text, MAX_PATH); + GetWindowTextA(g_edit, text, MAX_PATH); ok(lstrlenA(text) == 0, "Expected empty string\n"); ok_sequence(sequences, EDIT_SEQ_INDEX, get_edit_text_seq, "get edit text", FALSE); - flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(updown); + /* create with zero width */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.right = 0; + GetClientRect(updown, &r); + ok(r.right > 0, "Expected default width, got %d\n", r.right); + DestroyWindow(updown); + /* create with really small width */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 2, 0, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.right = 0; + GetClientRect(updown, &r); + ok(r.right != 2 && r.right > 0, "Expected default width, got %d\n", r.right); + DestroyWindow(updown); + /* create with width greater than default */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 100, 0, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.right = 0; + GetClientRect(updown, &r); + ok(r.right < 100 && r.right > 0, "Expected default width, got %d\n", r.right); + DestroyWindow(updown); + /* create with zero height, UDS_HORZ */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.bottom = 0; + GetClientRect(updown, &r); + ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); + DestroyWindow(updown); + /* create with really small height, UDS_HORZ */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 2, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.bottom = 0; + GetClientRect(updown, &r); + ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); + DestroyWindow(updown); + /* create with height greater than default, UDS_HORZ */ + updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 100, + parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); + ok(updown != NULL, "Failed to create updown control\n"); + r.bottom = 0; + GetClientRect(updown, &r); + ok(r.bottom < 100 && r.bottom > 0, "Expected default height, got %d\n", r.bottom); + DestroyWindow(updown); +} + +static void test_UDS_SETBUDDYINT(void) +{ + HWND updown; + DWORD style, ret; + CHAR text[10]; + + /* cleanup buddy */ + text[0] = '\0'; + SetWindowTextA(g_edit, text); + + /* creating without UDS_SETBUDDYINT */ + updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); + /* try to set UDS_SETBUDDYINT after creation */ + style = GetWindowLongA(updown, GWL_STYLE); + SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); + style = GetWindowLongA(updown, GWL_STYLE); + ok(style & UDS_SETBUDDYINT, "Expected UDS_SETBUDDY to be set\n"); + SendMessage(updown, UDM_SETPOS, 0, 20); + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + ok(lstrlenA(text) == 0, "Expected empty string\n"); + DestroyWindow(updown); + + /* creating with UDS_SETBUDDYINT */ + updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + /* 50 is initial value here */ + ok(lstrcmpA(text, "50") == 0, "Expected '50', got '%s'\n", text); + /* now remove style flag */ + style = GetWindowLongA(updown, GWL_STYLE); + SetWindowLongA(updown, GWL_STYLE, style & ~UDS_SETBUDDYINT); + SendMessage(updown, UDM_SETPOS, 0, 20); + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + ok(lstrcmpA(text, "20") == 0, "Expected '20', got '%s'\n", text); + /* set edit text directly, check position */ + strcpy(text, "10"); + SetWindowTextA(g_edit, text); + ret = SendMessageA(updown, UDM_GETPOS, 0, 0); + expect(10, ret); + strcpy(text, "11"); + SetWindowTextA(g_edit, text); + ret = SendMessageA(updown, UDM_GETPOS, 0, 0); + expect(11, LOWORD(ret)); + expect(0, HIWORD(ret)); + /* set to invalid value */ + strcpy(text, "21st"); + SetWindowTextA(g_edit, text); + ret = SendMessageA(updown, UDM_GETPOS, 0, 0); + expect(11, LOWORD(ret)); + expect(TRUE, HIWORD(ret)); + /* set style back */ + style = GetWindowLongA(updown, GWL_STYLE); + SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); + SendMessage(updown, UDM_SETPOS, 0, 30); + GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); + ok(lstrcmpA(text, "30") == 0, "Expected '30', got '%s'\n", text); + DestroyWindow(updown); +} + +START_TEST(updown) +{ + 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"); + g_edit = create_edit_control(); + ok(g_edit != NULL, "Failed to create edit control\n"); + + test_updown_create(); test_updown_pos(); test_updown_pos32(); test_updown_buddy(); test_updown_base(); test_updown_unicode(); -} + test_UDS_SETBUDDYINT(); -START_TEST(updown) -{ - InitCommonControls(); - init_msg_sequences(sequences, NUM_MSG_SEQUENCES); - - test_create_updown_control(); + DestroyWindow(g_edit); + DestroyWindow(parent_wnd); } diff --git a/rostests/winetests/comctl32/v6util.h b/rostests/winetests/comctl32/v6util.h new file mode 100644 index 00000000000..848e95b9225 --- /dev/null +++ b/rostests/winetests/comctl32/v6util.h @@ -0,0 +1,142 @@ +/* + * Utility routines for comctl32 v6 tests + * + * Copyright 2006 Mike McCormack for CodeWeavers + * Copyright 2007 George Gov + * Copyright 2009 Owen Rudge 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 + */ + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) + +#ifdef __i386__ +#define ARCH "x86" +#elif defined __x86_64__ +#define ARCH "amd64" +#else +#define ARCH "none" +#endif + +static const CHAR manifest_name[] = "cc6.manifest"; + +static const CHAR manifest[] = + "\n" + "\n" + " \n" + "Wine comctl32 test suite\n" + "\n" + " \n" + " \n" + "\n" + "\n" + "\n"; + +static void unload_v6_module(ULONG_PTR cookie, HANDLE hCtx) +{ + HANDLE hKernel32; + BOOL (WINAPI *pDeactivateActCtx)(DWORD, ULONG_PTR); + VOID (WINAPI *pReleaseActCtx)(HANDLE); + + hKernel32 = GetModuleHandleA("kernel32.dll"); + pDeactivateActCtx = (void*)GetProcAddress(hKernel32, "DeactivateActCtx"); + pReleaseActCtx = (void*)GetProcAddress(hKernel32, "ReleaseActCtx"); + if (!pDeactivateActCtx || !pReleaseActCtx) + { + win_skip("Activation contexts unsupported\n"); + return; + } + + pDeactivateActCtx(0, cookie); + pReleaseActCtx(hCtx); + + DeleteFileA(manifest_name); +} + +static BOOL load_v6_module(ULONG_PTR *pcookie, HANDLE *hCtx) +{ + HANDLE hKernel32; + HANDLE (WINAPI *pCreateActCtxA)(ACTCTXA*); + BOOL (WINAPI *pActivateActCtx)(HANDLE, ULONG_PTR*); + + ACTCTXA ctx; + BOOL ret; + HANDLE file; + DWORD written; + + hKernel32 = GetModuleHandleA("kernel32.dll"); + pCreateActCtxA = (void*)GetProcAddress(hKernel32, "CreateActCtxA"); + pActivateActCtx = (void*)GetProcAddress(hKernel32, "ActivateActCtx"); + if (!(pCreateActCtxA && pActivateActCtx)) + { + win_skip("Activation contexts unsupported. No version 6 tests possible.\n"); + return FALSE; + } + + /* create manifest */ + file = CreateFileA( manifest_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); + if (file != INVALID_HANDLE_VALUE) + { + ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) && + written == sizeof(manifest)-1); + CloseHandle( file ); + if (!ret) + { + DeleteFileA( manifest_name ); + skip("Failed to fill manifest file. Skipping comctl32 V6 tests.\n"); + return FALSE; + } + else + trace("created %s\n", manifest_name); + } + else + { + skip("Failed to create manifest file. Skipping comctl32 V6 tests.\n"); + return FALSE; + } + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.lpSource = manifest_name; + + *hCtx = pCreateActCtxA(&ctx); + ok(*hCtx != 0, "Expected context handle\n"); + + ret = pActivateActCtx(*hCtx, pcookie); + expect(TRUE, ret); + + if (!ret) + { + win_skip("A problem during context activation occurred.\n"); + DeleteFileA(manifest_name); + } + + return ret; +} + +#undef expect +#undef ARCH