From: The Wine Synchronizer Date: Sat, 1 Dec 2007 18:29:29 +0000 (+0000) Subject: Autosyncing with Wine HEAD X-Git-Tag: backups/curicon_rewrite@32816~697 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=58ffb98f70e3e678f9c344656c696691699f2a1a Autosyncing with Wine HEAD svn path=/trunk/; revision=30937 --- diff --git a/rostests/winetests/comctl32/bmp128x15.bmp b/rostests/winetests/comctl32/bmp128x15.bmp new file mode 100644 index 00000000000..85061b45f38 Binary files /dev/null and b/rostests/winetests/comctl32/bmp128x15.bmp differ diff --git a/rostests/winetests/comctl32/bmp80x15.bmp b/rostests/winetests/comctl32/bmp80x15.bmp new file mode 100644 index 00000000000..c524d71b9a6 Binary files /dev/null and b/rostests/winetests/comctl32/bmp80x15.bmp differ diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c index 3743c07a1e8..8f436ca6cad 100644 --- a/rostests/winetests/comctl32/comboex.c +++ b/rostests/winetests/comctl32/comboex.c @@ -82,108 +82,108 @@ static void test_comboboxex(void) { out_of_range_item[] = {'O','u','t',' ','o','f',' ','R','a','n','g','e',' ','I','t','e','m',0}; /* Allocate space for result */ - textBuffer = malloc(MAX_CHARS); + textBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_CHARS); /* Basic comboboxex test */ myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); /* Add items onto the end of the combobox */ res = addItem(myHwnd, -1, first_item); - ok(res == 0, "Adding simple item failed (%ld)\n", res); + ok(res == 0, "Adding simple item failed (%d)\n", res); res = addItem(myHwnd, -1, second_item); - ok(res == 1, "Adding simple item failed (%ld)\n", res); + ok(res == 1, "Adding simple item failed (%d)\n", res); res = addItem(myHwnd, 2, third_item); - ok(res == 2, "Adding simple item failed (%ld)\n", res); + ok(res == 2, "Adding simple item failed (%d)\n", res); res = addItem(myHwnd, 1, middle_item); - ok(res == 1, "Inserting simple item failed (%ld)\n", res); + ok(res == 1, "Inserting simple item failed (%d)\n", res); /* Add an item completely out of range */ res = addItem(myHwnd, 99, out_of_range_item); - ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res); + ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res); res = addItem(myHwnd, 5, out_of_range_item); - ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res); + ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res); /* Removed: Causes traps on Windows XP res = addItem(myHwnd, -2, "Out Of Range Item"); ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res); */ - /* Get an item completely out of range */ - res = getItem(myHwnd, 99, &cbexItem); - ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText); - res = getItem(myHwnd, 4, &cbexItem); - ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText); - res = getItem(myHwnd, -2, &cbexItem); - ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText); - - /* Get an item in range */ - res = getItem(myHwnd, 0, &cbexItem); - ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res); + /* Get an item completely out of range */ + res = getItem(myHwnd, 99, &cbexItem); + ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); + res = getItem(myHwnd, 4, &cbexItem); + ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); + res = getItem(myHwnd, -2, &cbexItem); + ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); + + /* Get an item in range */ + res = getItem(myHwnd, 0, &cbexItem); + ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); - res = getItem(myHwnd, 1, &cbexItem); - ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res); + res = getItem(myHwnd, 1, &cbexItem); + ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); - res = getItem(myHwnd, 2, &cbexItem); - ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res); + res = getItem(myHwnd, 2, &cbexItem); + ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); - res = getItem(myHwnd, 3, &cbexItem); - ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res); + res = getItem(myHwnd, 3, &cbexItem); + ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); - /* Set an item completely out of range */ - res = setItem(myHwnd, 99, replacement_item); - ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res); - res = setItem(myHwnd, 4, replacement_item); - ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res); - res = setItem(myHwnd, -2, replacement_item); - ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res); + /* Set an item completely out of range */ + res = setItem(myHwnd, 99, replacement_item); + ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); + res = setItem(myHwnd, 4, replacement_item); + ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); + res = setItem(myHwnd, -2, replacement_item); + ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); - /* Set an item in range */ + /* Set an item in range */ res = setItem(myHwnd, 0, replacement_item); - ok(res != 0, "Setting first item failed (%ld)\n", res); + ok(res != 0, "Setting first item failed (%d)\n", res); res = setItem(myHwnd, 3, replacement_item); - ok(res != 0, "Setting last item failed (%ld)\n", res); + ok(res != 0, "Setting last item failed (%d)\n", res); /* Remove items completely out of range (4 items in control at this point) */ res = delItem(myHwnd, -1); - ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res); + ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); res = delItem(myHwnd, 4); - ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res); + ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); /* Remove items in range (4 items in control at this point) */ res = delItem(myHwnd, 3); - ok(res == 3, "Deleting using out of range index failed (%ld)\n", res); + ok(res == 3, "Deleting using out of range index failed (%d)\n", res); res = delItem(myHwnd, 0); - ok(res == 2, "Deleting using out of range index failed (%ld)\n", res); + ok(res == 2, "Deleting using out of range index failed (%d)\n", res); res = delItem(myHwnd, 0); - ok(res == 1, "Deleting using out of range index failed (%ld)\n", res); + ok(res == 1, "Deleting using out of range index failed (%d)\n", res); res = delItem(myHwnd, 0); - ok(res == 0, "Deleting using out of range index failed (%ld)\n", res); + ok(res == 0, "Deleting using out of range index failed (%d)\n", res); /* Remove from an empty box */ res = delItem(myHwnd, 0); - ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res); + ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); /* Cleanup */ - free(textBuffer); + HeapFree(GetProcessHeap(), 0, textBuffer); } -LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); break; - + default: return DefWindowProcA(hWnd, msg, wParam, lParam); } - + return 0L; } @@ -200,14 +200,14 @@ static void init(void) { wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW)); + wc.hCursor = LoadCursorA(NULL, IDC_ARROW); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = ComboExTestClass; wc.lpfnWndProc = ComboExTestWndProc; RegisterClassA(&wc); - hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW, + hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); assert(hComboExParentWnd != NULL); @@ -218,13 +218,13 @@ static void init(void) { static void cleanup(void) { MSG msg; - + PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0); while (GetMessageA(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessageA(&msg); } - + UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); } diff --git a/rostests/winetests/comctl32/comctl32.rbuild b/rostests/winetests/comctl32/comctl32.rbuild index 407eac31b69..07d9b34ca81 100644 --- a/rostests/winetests/comctl32/comctl32.rbuild +++ b/rostests/winetests/comctl32/comctl32.rbuild @@ -1,29 +1,39 @@ - - . - - shlwapi - ole32 - comctl32 - ntdll - gdi32 - user32 - kernel32 - advapi32 - comboex.c - dpa.c - header.c - imagelist.c - listview.c - monthcal.c - mru.c - progress.c - propsheet.c - subclass.c - tab.c - testlist.c - toolbar.c - tooltips.c - treeview.c - updown.c - propsheet.rc + + + + . + 0x600 + 0x600 + wine + comctl32 + ole32 + shlwapi + user32 + gdi32 + advapi32 + kernel32 + ntdll + comboex.c + datetime.c + dpa.c + header.c + imagelist.c + listview.c + misc.c + monthcal.c + mru.c + msg.c + progress.c + propsheet.c + rebar.c + status.c + subclass.c + tab.c + toolbar.c + tooltips.c + trackbar.c + treeview.c + updown.c + rsrc.rc + testlist.c diff --git a/rostests/winetests/comctl32/comctl32_ros.diff b/rostests/winetests/comctl32/comctl32_ros.diff new file mode 100644 index 00000000000..4dfe3b1e8b4 --- /dev/null +++ b/rostests/winetests/comctl32/comctl32_ros.diff @@ -0,0 +1,24 @@ +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" diff --git a/rostests/winetests/comctl32/datetime.c b/rostests/winetests/comctl32/datetime.c new file mode 100644 index 00000000000..1a8afd1e14f --- /dev/null +++ b/rostests/winetests/comctl32/datetime.c @@ -0,0 +1,571 @@ +/* Unit test suite for datetime control. +* +* Copyright 2007 Kanit Therdsteerasukdi +* +* 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 +#include + +#include "wine/test.h" +#include "msg.h" + +#define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT)) + +#define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT)) + +#define NUM_MSG_SEQUENCES 1 +#define DATETIME_SEQ_INDEX 0 + +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 }, + { 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 }, + { 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 }, + { 0 } +}; + +static const struct message test_dtm_get_monthcal_seq[] = { + { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { 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 }, + { 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 }, + { 0 } +}; + +static const struct message test_dtm_set_and_get_system_time_seq[] = { + { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 }, + { 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 }, + { 0 } +}; + +static const struct message destroy_window_seq[] = { + { 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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("datetime: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, DATETIME_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND create_datetime_control(DWORD style, DWORD exstyle) +{ + struct subclass_info *info; + HWND hWndDateTime = NULL; + + info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); + if (!info) + return NULL; + + hWndDateTime = CreateWindowEx(0, + DATETIMEPICK_CLASS, + NULL, + style, + 0,50,300,120, + NULL, + NULL, + NULL, + NULL); + + if (!hWndDateTime) { + HeapFree(GetProcessHeap(), 0, info); + return NULL; + } + + info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC, + (LONG_PTR)datetime_subclass_proc); + SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)info); + + return hWndDateTime; +} + +static void test_dtm_set_format(HWND hWndDateTime) +{ + LRESULT r; + + r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, (LPARAM)NULL); + expect(1, r); + + r = SendMessage(hWndDateTime, 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); + flush_sequences(sequences, NUM_MSG_SEQUENCES); +} + +static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name) +{ + LRESULT r; + COLORREF theColor, prevColor; + + theColor=RGB(0,0,0); + r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); + ok(r != -1, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %ld\n", mccolor_name, r); + prevColor=theColor; + theColor=RGB(255,255,255); + r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); + ok(r==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %ld\n", mccolor_name, r); + prevColor=theColor; + theColor=RGB(100,180,220); + r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); + ok(r==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %ld\n", mccolor_name, r); + r = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0); + ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r); +} + +static void test_dtm_set_and_get_mccolor(HWND hWndDateTime) +{ + 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"); + + 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); +} + +static void test_dtm_set_and_get_mcfont(HWND hWndDateTime) +{ + HFONT hFontOrig, hFontNew; + + hFontOrig = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE); + hFontNew = (HFONT)SendMessage(hWndDateTime, 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); +} + +static void test_dtm_get_monthcal(HWND hWndDateTime) +{ + LRESULT r; + + todo_wine { + r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0); + ok(r == (LPARAM)NULL, "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); +} + +static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds) +{ + st->wYear = year; + st->wMonth = month; + st->wDayOfWeek = dayofweek; + st->wDay = day; + st->wHour = hour; + st->wMinute = minute; + st->wSecond = second; + st->wMilliseconds = milliseconds; +} + +static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2) +{ + return (st1->wYear == st2->wYear) + && (st1->wMonth == st2->wMonth) + && (st1->wDayOfWeek == st2->wDayOfWeek) + && (st1->wDay == st2->wDay); +} + +static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2) +{ + return (st1->wHour == st2->wHour) + && (st1->wMinute == st2->wMinute) + && (st1->wSecond == st2->wSecond) + && (st1->wMilliseconds == st2->wMilliseconds); +} + +static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2) +{ + if(!compare_systime_date(st1, st2)) + return 0; + + return compare_systime_time(st1, st2); +} + +#define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n") +#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) +{ + LRESULT r; + SYSTEMTIME st[2]; + SYSTEMTIME getSt[2]; + + /* initialize st[0] to lowest possible value */ + fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); + /* intialize 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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); + expect_unsuccess(0, r); + + /* set st[0] to all invalid numbers */ + fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000); + /* 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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); + expect_unsuccess(0, r); + r = SendMessage(hWndDateTime, 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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]); + + /* initialize st[0] to lowest possible value */ + fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); + /* 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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]); + + /* set st[0] to value higher than minimum */ + fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); + /* 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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); +} + +/* when maxmax, min and max values should be swapped by DTM_SETRANGE + automatically */ + r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); + expect(1, r); + r = SendMessage(hWndDateTime, 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]); + } + + fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); + + r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); + expect(1, r); + r = SendMessage(hWndDateTime, 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]); + } + + /* set st[0] to value higher than minimum */ + fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); + /* 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); + 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); + 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]); + } + + /* set st[0] to value higher than st[1] */ + fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999); + fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465); + + /* 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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]); + + /* initialize st[0] to lowest possible value */ + fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); + /* 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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); +} + +static void test_dtm_set_and_get_system_time(HWND hWndDateTime) +{ + LRESULT r; + SYSTEMTIME st; + SYSTEMTIME getSt; + HWND hWndDateTime_test_gdt_none; + + hWndDateTime_test_gdt_none = create_datetime_control(0, 0); + + ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none); + if(hWndDateTime_test_gdt_none) { + r = SendMessage(hWndDateTime_test_gdt_none, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); + expect(0, r); + } + else { + skip("hWndDateTime_test_gdt_none is NULL\n"); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + return; + } + + DestroyWindow(hWndDateTime_test_gdt_none); + + r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); + expect(1, r); + r = SendMessage(hWndDateTime, 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); + 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); + 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); + expect(1, r); + r = SendMessage(hWndDateTime, 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); + 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); +} + +static void test_datetime_control(void) +{ + HWND hWndDateTime; + + hWndDateTime = create_datetime_control(DTS_SHOWNONE, 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"); + } + + DestroyWindow(hWndDateTime); + ok_sequence(sequences, DATETIME_SEQ_INDEX, destroy_window_seq, "test_dtm_set_and_get_system_time", TRUE); +} + +START_TEST(datetime) +{ + INITCOMMONCONTROLSEX icex; + + icex.dwSize = sizeof(icex); + icex.dwICC = ICC_DATE_CLASSES; + InitCommonControlsEx(&icex); + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + + test_datetime_control(); +} diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c index 4aa7b88f1a2..f1ca8f23e25 100644 --- a/rostests/winetests/comctl32/dpa.c +++ b/rostests/winetests/comctl32/dpa.c @@ -23,7 +23,10 @@ #include -#include "windows.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" #include "commctrl.h" #include "objidl.h" @@ -49,7 +52,7 @@ static PVOID (WINAPI *pDPA_DeleteAllPtrs)(const HDPA); static PVOID (WINAPI *pDPA_DeletePtr)(const HDPA,INT); static BOOL (WINAPI *pDPA_Destroy)(const HDPA); static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); -static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); +static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); static INT (WINAPI *pDPA_GetPtr)(const HDPA,INT); static INT (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID); static BOOL (WINAPI *pDPA_Grow)(HDPA,INT); @@ -63,7 +66,7 @@ static BOOL (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM); #define COMCTL32_GET_PROC(func, ord) \ ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \ - : (trace( #func " not exported\n"), 0)) + : (trace( #func " not exported\n"), 0)) static BOOL InitFunctionPtrs(HMODULE hcomctl32) { @@ -112,7 +115,7 @@ static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) { ok(lp == 0xdeadbeef, "lp=%ld\n", lp); return p1; -} +} static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) { @@ -123,7 +126,7 @@ static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM l static INT nEnum; static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp) -{ +{ INT i; i = pDPA_GetPtrIndex(lp, pItem); @@ -136,12 +139,12 @@ static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp) static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) { HRESULT hRes; - + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL); - ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + ok(hRes == S_OK, "hRes=0x%x\n", hRes); hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL); - ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + ok(hRes == S_OK, "hRes=0x%x\n", hRes); return S_OK; } @@ -149,14 +152,14 @@ static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) { HRESULT hRes; INT iOldPos; - + iOldPos = pInfo->iPos; ok(lp == 0xdeadbeef, "lp=%ld\n", lp); hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL); - ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + ok(hRes == S_OK, "hRes=0x%x\n", 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%lx\n", hRes); + ok(hRes == S_OK, "hRes=0x%x\n", hRes); return S_OK; } @@ -171,23 +174,23 @@ static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut) if(!ulItem) break; dwOut = dwOut << 4 | (ulItem & 0xf); } - + *pdwOut = dwOut; if(dwOut != dwIn) { pDPA_DeleteAllPtrs(dpa); - + do { pDPA_InsertPtr(dpa, 0, (PVOID)(dwIn & 0xf)); dwIn >>= 4; } while(dwIn); - + return FALSE; } - + return TRUE; } @@ -200,16 +203,17 @@ static void test_dpa(void) PVOID p; DWORD dw, dw2, dw3; HRESULT hRes; - + BOOL rc; + GetSystemInfo(&si); hHeap = HeapCreate(0, 1, 2); - ok(hHeap != NULL, "error=%ld\n", GetLastError()); + ok(hHeap != NULL, "error=%d\n", GetLastError()); 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, - "ret=%d error=%ld\n", ret, GetLastError()); - + todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "ret=%d error=%d\n", ret, GetLastError()); + dpa = pDPA_Create(0); ok(dpa != NULL, "\n"); @@ -217,8 +221,9 @@ static void test_dpa(void) ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n"); /* Fill the greated gap */ ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n"); - ok(CheckDPA(dpa, 0x56, &dw), "dw=0x%lx\n", dw); - + rc=CheckDPA(dpa, 0x56, &dw); + ok(rc, "dw=0x%x\n", dw); + /* Prepend item */ ret = pDPA_InsertPtr(dpa, 1, (PVOID)1); ok(ret == 1, "ret=%d\n", ret); @@ -228,11 +233,12 @@ static void test_dpa(void) /* Append item using out of bound index */ ret = pDPA_InsertPtr(dpa, 5, (PVOID)2); ok(ret == 4, "ret=%d\n", ret); - /* Append item using DPA_APPEND */ + /* Append item using DPA_APPEND */ ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4); ok(ret == 5, "ret=%d\n", ret); - ok(CheckDPA(dpa, 0x516324, &dw), "dw=0x%lx\n", dw); + rc=CheckDPA(dpa, 0x516324, &dw); + ok(rc, "dw=0x%x\n", dw); for(i = 1; i <= 6; i++) { @@ -245,24 +251,29 @@ static void test_dpa(void) /* Sort DPA */ ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n"); - ok(CheckDPA(dpa, 0x654321, &dw), "dw=0x%lx\n", dw); - + rc=CheckDPA(dpa, 0x654321, &dw); + ok(rc, "dw=0x%x\n", dw); + /* Clone into a new DPA */ dpa2 = pDPA_Clone(dpa, NULL); ok(dpa2 != NULL, "\n"); /* The old data should have been preserved */ - ok(CheckDPA(dpa2, 0x654321, &dw2), "dw=0x%lx\n", dw2); + rc=CheckDPA(dpa2, 0x654321, &dw2); + ok(rc, "dw=0x%x\n", dw2); ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n"); - + /* Test if the DPA itself was really copied */ - ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw ); - ok(CheckDPA(dpa2, 0x654321, &dw2), "dw2=0x%lx\n", dw2); + rc=CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw ); + rc=CheckDPA(dpa2, 0x654321, &dw2); + ok(rc, "dw2=0x%x\n", dw2); /* Clone into an old DPA */ p = NULL; SetLastError(ERROR_SUCCESS); p = pDPA_Clone(dpa, dpa3); ok(p == dpa3, "p=%p\n", p); - ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3); + rc=CheckDPA(dpa3, 0x123456, &dw3); + ok(rc, "dw3=0x%x\n", dw3); for(i = 1; i <= 6; i++) { @@ -281,11 +292,11 @@ static void test_dpa(void) j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); todo_wine 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); - + /* Try to delete out of bound indexes */ p = pDPA_DeletePtr(dpa, -1); ok(p == NULL, "p=%p\n", p); @@ -295,10 +306,11 @@ static void test_dpa(void) /* Delete the third item */ p = pDPA_DeletePtr(dpa, 2); ok(p == (PVOID)3, "p=%p\n", p); - ok(CheckDPA(dpa, 0x12456, &dw), "dw=0x%lx\n", dw); + rc=CheckDPA(dpa, 0x12456, &dw); + ok(rc, "dw=0x%x\n", dw); /* Check where to re-insert the deleted item */ - i = pDPA_Search(dpa, (PVOID)3, 0, + i = pDPA_Search(dpa, (PVOID)3, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER); ok(i == 2, "i=%d\n", i); /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */ @@ -313,8 +325,9 @@ static void test_dpa(void) /* Re-insert the item */ ret = pDPA_InsertPtr(dpa, 2, (PVOID)3); ok(ret == 2, "ret=%d i=%d\n", ret, 2); - ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw); - + rc=CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + /* When doing a binary search while claiming reverse order all indexes * should be bogus */ for(i = 0; i < 6; i++) @@ -330,39 +343,49 @@ static void test_dpa(void) p = pDPA_DeletePtr(dpa, 1); p = pDPA_DeletePtr(dpa, 2); p = pDPA_DeletePtr(dpa, 3); - ok(CheckDPA(dpa, 0x135, &dw), "dw=0x%lx\n", dw); - + rc=CheckDPA(dpa, 0x135, &dw); + ok(rc, "dw=0x%x\n", dw); + /* Delete all odd entries from dpa2 */ - pDPA_Merge(dpa2, dpa, DPAM_DELETE, + pDPA_Merge(dpa2, dpa, DPAM_DELETE, CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef); - todo_wine ok(CheckDPA(dpa2, 0x246, &dw2), "dw=0x%lx\n", dw2); - + 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, + pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT, CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); - pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, + pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); - - ok(CheckDPA(dpa, 0x123456, &dw ), "dw=0x%lx\n", dw); - ok(CheckDPA(dpa2, 0x123456, &dw2), "dw2=0x%lx\n", dw2); - ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3); + + rc=CheckDPA(dpa, 0x123456, &dw); + ok(rc, "dw=0x%x\n", dw); + rc=CheckDPA(dpa2, 0x123456, &dw2); + ok(rc, "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, (PVOID)dpa2); - ok(CheckDPA(dpa2, 0x777456, &dw2), "dw=0x%lx\n", dw2); + 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); ok(ret == 0x12345, "ret=%d\n", ret); - + pDPA_DeleteAllPtrs(dpa2); - ok(CheckDPA(dpa2, 0, &dw2), "dw2=0x%lx\n", dw2); + rc=CheckDPA(dpa2, 0, &dw2); + ok(rc, "dw2=0x%x\n", dw2); pDPA_Destroy(dpa2); if(pDPA_DestroyCallback) @@ -388,31 +411,34 @@ static void test_dpa(void) dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE; hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg); - ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + ok(hRes == S_OK, "hRes=0x%x\n", hRes); hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); - ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + 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%lx\n", hRes); + 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%lx\n", hRes); + 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%lx\n", hRes); - todo_wine ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw); - pDPA_Destroy(dpa); + 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(); } - else ok(0, "hResult: %ld\n", hRes); + else ok(0, "hResult: %d\n", hRes); skip_stream_tests: pDPA_Destroy(dpa); @@ -424,12 +450,6 @@ START_TEST(dpa) hcomctl32 = GetModuleHandleA("comctl32.dll"); - if(!hcomctl32) - { - ok(0, "error=%ld\n", GetLastError()); - return; - } - if(InitFunctionPtrs(hcomctl32)) test_dpa(); else diff --git a/rostests/winetests/comctl32/header.c b/rostests/winetests/comctl32/header.c index 3d72e19d20a..e80944fb789 100644 --- a/rostests/winetests/comctl32/header.c +++ b/rostests/winetests/comctl32/header.c @@ -1,6 +1,7 @@ /* Unit test suite for header control. * * Copyright 2005 Vijay Kiran Kamuju + * Copyright 2007 Shanren Zhou * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ #include #include "wine/test.h" +#include "msg.h" typedef struct tagEXPECTEDNOTIFY { @@ -31,16 +33,186 @@ typedef struct tagEXPECTEDNOTIFY HDITEMA hdItem; } EXPECTEDNOTIFY; -EXPECTEDNOTIFY expectedNotify[10]; -INT nExpectedNotify = 0; -INT nReceivedNotify = 0; -INT unexpectedNotify[10]; -INT nUnexpectedNotify = 0; +typedef LRESULT (*CUSTOMDRAWPROC)(int n, NMCUSTOMDRAW *nm); + +static CUSTOMDRAWPROC g_CustomDrawProc; +static int g_CustomDrawCount; +static DRAWITEMSTRUCT g_DrawItem; +static BOOL g_DrawItemReceived; + +static EXPECTEDNOTIFY expectedNotify[10]; +static INT nExpectedNotify = 0; +static INT nReceivedNotify = 0; +static INT unexpectedNotify[10]; +static INT nUnexpectedNotify = 0; static HWND hHeaderParentWnd; static HWND hWndHeader; #define MAX_CHARS 100 +#define compare(val, exp, fmt) ok((val) == (exp), #val " value: " fmt ", expected: " fmt "\n", (val), (exp)) + +#define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got) + +#define NUM_MSG_SEQUENCES 2 +#define PARENT_SEQ_INDEX 0 +#define HEADER_SEQ_INDEX 1 + +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 }, + { 0 } +}; + +static const struct message add_header_to_parent_seq_interactive[] = { + { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, + { WM_QUERYUISTATE, sent }, + { WM_PARENTNOTIFY, sent|wparam, 1 }, + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_ACTIVATE, sent|wparam, 1 }, + { WM_IME_SETCONTEXT, sent|defwinproc|wparam, 1 }, + { WM_IME_NOTIFY, sent|defwinproc|wparam, 2 }, + { WM_SETFOCUS, sent|defwinproc|wparam, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam, 0 }, + { WM_SIZE, sent|wparam, 0 }, + { WM_MOVE, sent|wparam, 0 }, + { 0 } +}; + +static const struct message add_header_to_parent_seq[] = { + { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, + { WM_QUERYUISTATE, sent }, + { WM_PARENTNOTIFY, sent }, + { 0 } +}; + +static const struct message insertItem_seq[] = { + { HDM_INSERTITEM, sent|wparam, 0 }, + { HDM_INSERTITEM, sent|wparam, 1 }, + { HDM_INSERTITEM, sent|wparam, 2 }, + { HDM_INSERTITEM, sent|wparam, 3 }, + { 0 } +}; + +static const struct message getItem_seq[] = { + { HDM_GETITEM, sent|wparam, 3 }, + { HDM_GETITEM, sent|wparam, 0 }, + { 0 } +}; + + +static const struct message deleteItem_getItemCount_seq[] = { + { HDM_DELETEITEM, sent|wparam, 3 }, + { HDM_GETITEMCOUNT, sent }, + { HDM_DELETEITEM, sent|wparam, 3 }, + { HDM_GETITEMCOUNT, sent }, + { HDM_DELETEITEM, sent|wparam, 2 }, + { HDM_GETITEMCOUNT, sent }, + { 0 } +}; + +static const struct message orderArray_seq[] = { + { HDM_GETITEMCOUNT, sent }, + { HDM_SETORDERARRAY, sent|wparam, 2 }, + { HDM_GETORDERARRAY, sent|wparam, 2 }, + { 0 } +}; + +static const struct message setItem_seq[] = { + { HDM_SETITEM, sent|wparam, 0 }, + { HDM_SETITEM, sent|wparam, 1 }, + { 0 } +}; + +static const struct message getItemRect_seq[] = { + { HDM_GETITEMRECT, sent|wparam, 1 }, + { HDM_GETITEMRECT, sent|wparam, 0 }, + { HDM_GETITEMRECT, sent|wparam, 10 }, + { 0 } +}; + +static const struct message layout_seq[] = { + { HDM_LAYOUT, sent }, + { 0 } +}; + +static const struct message orderToIndex_seq[] = { + { HDM_ORDERTOINDEX, sent|wparam, 1 }, + { 0 } +}; + +static const struct message hittest_seq[] = { + { HDM_HITTEST, sent }, + { HDM_HITTEST, sent }, + { HDM_HITTEST, sent }, + { 0 } +}; + +static const struct message setHotDivider_seq_interactive[] = { + { HDM_SETHOTDIVIDER, sent|wparam, TRUE }, + { WM_PAINT, sent|defwinproc}, + { WM_NCPAINT, sent|defwinproc}, + { WM_ERASEBKGND, sent|defwinproc}, + { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 }, + { WM_PAINT, sent|defwinproc}, + { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1}, + { WM_PAINT, sent|defwinproc}, + { 0 } +}; + +static const struct message setHotDivider_seq_noninteractive[] = { + { HDM_SETHOTDIVIDER, sent|wparam, TRUE }, + { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 }, + { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1}, + { 0 } +}; + +static const struct message imageMessages_seq[] = { + { HDM_SETIMAGELIST, sent }, + { HDM_GETIMAGELIST, sent }, + { HDM_CREATEDRAGIMAGE, sent }, + { 0 } +}; + +static const struct message filterMessages_seq_interactive[] = { + { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 }, + { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 }, + { HDM_EDITFILTER, sent|wparam|lparam, 1, 0 }, + { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE }, + { WM_CTLCOLOREDIT, sent|defwinproc }, + { WM_COMMAND, sent|defwinproc }, + { 0 } +}; + +static const struct message filterMessages_seq_noninteractive[] = { + { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 }, + { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 }, + { HDM_EDITFILTER, sent|wparam|lparam, 1, 0 }, + { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE }, + { WM_COMMAND, sent|defwinproc }, + { 0 } +}; + +static const struct message unicodeformatMessages_seq[] = { + { HDM_SETUNICODEFORMAT, sent|wparam, TRUE }, + { HDM_GETUNICODEFORMAT, sent }, + { 0 } +}; + +static const struct message bitmapmarginMessages_seq[] = { + { HDM_GETBITMAPMARGIN, sent }, + { 0 } +}; + + static void expect_notify(INT iCode, BOOL fUnicode, HDITEMA *lpItem) { assert(nExpectedNotify < 10); @@ -64,22 +236,22 @@ static BOOL notifies_received(void) return fRet; } -static LONG addItem(HWND hdex, int idx, LPCSTR text) +static LONG addItem(HWND hdex, int idx, LPSTR text) { HDITEMA hdItem; hdItem.mask = HDI_TEXT | HDI_WIDTH; hdItem.cxy = 100; - hdItem.pszText = (LPSTR)text; + hdItem.pszText = text; hdItem.cchTextMax = 0; return (LONG)SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)idx, (LPARAM)&hdItem); } -static LONG setItem(HWND hdex, int idx, LPCSTR text, BOOL fCheckNotifies) +static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies) { LONG ret; HDITEMA hdexItem; hdexItem.mask = HDI_TEXT; - hdexItem.pszText = (LPSTR)text; + hdexItem.pszText = text; hdexItem.cchTextMax = 0; if (fCheckNotifies) { @@ -92,18 +264,18 @@ static LONG setItem(HWND hdex, int idx, LPCSTR text, BOOL fCheckNotifies) return ret; } -static LONG setItemUnicodeNotify(HWND hdex, int idx, LPCSTR text, LPCWSTR wText) +static LONG setItemUnicodeNotify(HWND hdex, int idx, LPSTR text, LPWSTR wText) { LONG ret; HDITEMA hdexItem; HDITEMW hdexNotify; hdexItem.mask = HDI_TEXT; - hdexItem.pszText = (LPSTR)text; + hdexItem.pszText = text; hdexItem.cchTextMax = 0; - + hdexNotify.mask = HDI_TEXT; - hdexNotify.pszText = (LPWSTR)wText; - + hdexNotify.pszText = 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); @@ -136,7 +308,7 @@ static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA ZeroMemory(phdiRead, sizeof(HDITEMA)); phdiRead->mask = maskRead; ok(SendMessage(hdex, HDM_GETITEMA, (WPARAM)0, (LPARAM)phdiRead)!=0, "Getting item data failed\n"); - ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleteing item failed\n"); + ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleting item failed\n"); } static HWND create_header_control (void) @@ -159,7 +331,7 @@ static HWND create_header_control (void) hlayout.prc = &rectwin; hlayout.pwpos = &winpos; SendMessageA(handle,HDM_LAYOUT,0,(LPARAM) &hlayout); - SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y, + SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y, winpos.cx, winpos.cy, 0); return handle; @@ -198,22 +370,173 @@ static void compare_items(INT iCode, HDITEMA *hdi1, HDITEMA *hdi2, BOOL fUnicode } } -static const char *str_items[] = - {"First Item", "Second Item", "Third Item", "Fourth Item", "Replace Item", "Out Of Range Item"}; +static char pszFirstItem[] = "First Item"; +static char pszSecondItem[] = "Second Item"; +static char pszThirdItem[] = "Third Item"; +static char pszFourthItem[] = "Fourth Item"; +static char pszReplaceItem[] = "Replace Item"; +static char pszOutOfRangeItem[] = "Out Of Range Item"; -static const char pszUniTestA[] = "TST"; -static const WCHAR pszUniTestW[] = {'T','S','T',0}; +static char *str_items[] = + {pszFirstItem, pszSecondItem, pszThirdItem, pszFourthItem, pszReplaceItem, pszOutOfRangeItem}; + +static char pszUniTestA[] = "TST"; +static WCHAR pszUniTestW[] = {'T','S','T',0}; #define TEST_GET_ITEM(i,c)\ { res = getItem(hWndHeader, i, buffer);\ - ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%ld)\n", i, res);\ + ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%d)\n", i, res);\ ok(strcmp(str_items[c], buffer) == 0, "Getting item[%d] returned \"%s\" expecting \"%s\"\n", i, buffer, str_items[c]);\ } #define TEST_GET_ITEMCOUNT(i)\ { res = getItemCount(hWndHeader);\ - ok(res == i, "Got Item Count as %ld\n", res);\ + 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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, HEADER_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + + { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static BOOL register_parent_wnd_class(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = parent_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Header test parent class"; + return RegisterClassA(&cls); +} + +static HWND create_custom_parent_window(void) +{ + if (!register_parent_wnd_class()) + return NULL; + + return CreateWindowExA(0, "Header test parent class", "Header Message Sequence Testing", + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + 672+2*GetSystemMetrics(SM_CXSIZEFRAME), + 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), + NULL, NULL, GetModuleHandleA(NULL), 0); +} + +static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems) +{ + struct subclass_info *info; + HWND childHandle; + HDLAYOUT hlayout; + RECT rectwin; + WINDOWPOS winpos; + int retVal; + int loopcnt; + static char firstHeaderItem[] = "Name"; + static char secondHeaderItem[] = "Size"; + static char *items[] = {secondHeaderItem, firstHeaderItem}; + HDITEM hdItem; + hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT; + hdItem.fmt = HDF_LEFT; + hdItem.cxy = 80; + hdItem.cchTextMax = 260; + + + 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, + 0, 0, 0, 0, + hParent, NULL, NULL, NULL); + assert(childHandle); + if (preloadHeaderItems) + { + for ( loopcnt = 0 ; loopcnt < 2 ; loopcnt++ ) + { + hdItem.pszText = items[loopcnt]; + retVal = SendMessage(childHandle, HDM_INSERTITEM, loopcnt, (LPARAM) &hdItem); + ok(retVal == loopcnt, "Adding item %d failed with return value %d\n", ( loopcnt + 1 ), retVal); + } + } + + if (winetest_interactive) + ShowWindow (hParent, SW_SHOW); + + GetClientRect(hParent,&rectwin); + hlayout.prc = &rectwin; + hlayout.pwpos = &winpos; + SendMessageA(childHandle,HDM_LAYOUT,0,(LPARAM) &hlayout); + 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); + return childHandle; } static void check_auto_format(void) @@ -275,7 +598,7 @@ static void check_auto_fields(void) HDITEMA hdiCreate; HDITEMA hdiRead; static CHAR text[] = "Test"; - LRESULT res; + LONG res; /* Windows stores the format, width, lparam even if they are not in the item's mask */ ZeroMemory(&hdiCreate, sizeof(HDITEMA)); @@ -390,25 +713,25 @@ static void test_header_control (void) { TEST_GET_ITEMCOUNT(3-i); res = addItem(hWndHeader, 0, str_items[i]); - ok(res == 0, "Adding simple item failed (%ld)\n", res); + ok(res == 0, "Adding simple item failed (%d)\n", res); } TEST_GET_ITEMCOUNT(4); res = addItem(hWndHeader, 99, str_items[i+1]); - ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res); + ok(res != -1, "Adding Out of Range item should fail with -1 got (%d)\n", res); TEST_GET_ITEMCOUNT(5); res = addItem(hWndHeader, 5, str_items[i+1]); - ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res); + ok(res != -1, "Adding Out of Range item should fail with -1 got (%d)\n", res); TEST_GET_ITEMCOUNT(6); for (i = 0; i < 4; i++) { TEST_GET_ITEM(i,i); TEST_GET_ITEMCOUNT(6); } res=getItem(hWndHeader, 99, buffer); - ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer); + ok(res == 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res,buffer); res=getItem(hWndHeader, 5, buffer); - ok(res == 1, "Getting Out of Range item should fail with 1 (%ld), got %s\n", res,buffer); + ok(res == 1, "Getting Out of Range item should fail with 1 (%d), got %s\n", res,buffer); res=getItem(hWndHeader, -2, buffer); - ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer); + ok(res == 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res,buffer); if (winetest_interactive) { @@ -418,26 +741,26 @@ static void test_header_control (void) TEST_GET_ITEMCOUNT(6); res=setItem(hWndHeader, 99, str_items[5], FALSE); - ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res); + ok(res == 0, "Setting Out of Range item should fail with 0 (%d)\n", res); res=setItem(hWndHeader, 5, str_items[5], TRUE); - ok(res == 1, "Setting Out of Range item should fail with 1 (%ld)\n", res); + ok(res == 1, "Setting Out of Range item should fail with 1 (%d)\n", res); res=setItem(hWndHeader, -2, str_items[5], FALSE); - ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res); + ok(res == 0, "Setting Out of Range item should fail with 0 (%d)\n", res); TEST_GET_ITEMCOUNT(6); for (i = 0; i < 4; i++) { res = setItem(hWndHeader, i, str_items[4], TRUE); - ok(res != 0, "Setting %d item failed (%ld)\n", i+1, res); + ok(res != 0, "Setting %d item failed (%d)\n", i+1, res); TEST_GET_ITEM(i, 4); TEST_GET_ITEMCOUNT(6); } - + SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, 0); setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW); SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, (LPARAM)NF_REQUERY); setItem(hWndHeader, 3, str_items[4], TRUE); - + dont_expect_notify(HDN_GETDISPINFOA); dont_expect_notify(HDN_GETDISPINFOW); addItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA); @@ -457,30 +780,652 @@ static void test_header_control (void) TEST_GET_ITEMCOUNT(6); res = delItem(hWndHeader, 5); - ok(res == 1, "Deleting Out of Range item should fail with 1 (%ld)\n", res); + ok(res == 1, "Deleting Out of Range item should fail with 1 (%d)\n", res); res = delItem(hWndHeader, -2); - ok(res == 0, "Deleting Out of Range item should fail with 0 (%ld)\n", res); + ok(res == 0, "Deleting Out of Range item should fail with 0 (%d)\n", res); TEST_GET_ITEMCOUNT(5); res = delItem(hWndHeader, 3); - ok(res != 0, "Deleting using out of range index failed (%ld)\n", res); + ok(res != 0, "Deleting using out of range index failed (%d)\n", res); TEST_GET_ITEMCOUNT(4); res = delItem(hWndHeader, 0); - ok(res != 0, "Deleting using out of range index failed (%ld)\n", res); + ok(res != 0, "Deleting using out of range index failed (%d)\n", res); TEST_GET_ITEMCOUNT(3); res = delItem(hWndHeader, 0); - ok(res != 0, "Deleting using out of range index failed (%ld)\n", res); + ok(res != 0, "Deleting using out of range index failed (%d)\n", res); TEST_GET_ITEMCOUNT(2); res = delItem(hWndHeader, 0); - ok(res != 0, "Deleting using out of range index failed (%ld)\n", res); + ok(res != 0, "Deleting using out of range index failed (%d)\n", res); TEST_GET_ITEMCOUNT(1); DestroyWindow(hWndHeader); } +static void test_hdm_getitemrect(HWND hParent) +{ + + HWND hChild; + RECT rect; + int retVal; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + retVal = SendMessage(hChild, HDM_GETITEMRECT, 1, (LPARAM) &rect); + ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal); + /* check bounding rectangle information of 2nd header item */ + expect(80, rect.left); + expect(0, rect.top); + expect(160, rect.right); + todo_wine + { + expect(18, rect.bottom); + } + retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect); + + ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal); + /* check bounding rectangle information of 1st header item */ + expect(0, rect.left); + expect(0, rect.top); + + expect(80, rect.right); + todo_wine + { + expect(18, 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); + + ok_sequence(sequences, HEADER_SEQ_INDEX, getItemRect_seq, "getItemRect sequence testing", FALSE); + DestroyWindow(hChild); +} + +static void test_hdm_layout(HWND hParent) +{ + HWND hChild; + int retVal; + RECT rect; + HDLAYOUT hdLayout; + WINDOWPOS windowPos; + hdLayout.prc = ▭ + hdLayout.pwpos = &windowPos; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + retVal = SendMessage(hChild, HDM_LAYOUT, 0, (LPARAM) &hdLayout); + expect(TRUE, retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, layout_seq, "layout sequence testing", FALSE); + + DestroyWindow(hChild); +} -LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +static void test_hdm_ordertoindex(HWND hParent) { + HWND hChild; + int retVal; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + retVal = SendMessage(hChild, HDM_ORDERTOINDEX, 1, 0); + expect(1, retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, orderToIndex_seq, "orderToIndex sequence testing", FALSE); + DestroyWindow(hChild); +} + +static void test_hdm_hittest(HWND hParent) +{ + HWND hChild; + int retVal; + POINT pt; + HDHITTESTINFO hdHitTestInfo; + const int firstItemRightBoundary = 80; + const int secondItemRightBoundary = 160; + const int bottomBoundary = 18; + + pt.x = firstItemRightBoundary - 1; + pt.y = bottomBoundary - 1; + hdHitTestInfo.pt = pt; + + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); + todo_wine + { + expect(0, retVal); + expect(0, hdHitTestInfo.iItem); + } + + 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, hdHitTestInfo.iItem); + + pt.x = secondItemRightBoundary; + pt.y = bottomBoundary + 1; + hdHitTestInfo.pt = pt; + todo_wine + { + retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); + expect(-1, retVal); + } + + ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE); + + DestroyWindow(hChild); +} + +static void test_hdm_sethotdivider(HWND hParent) +{ + HWND hChild; + int retVal; + /* low word: x coordinate = 5 + * high word: y coordinate = 5 + */ + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + todo_wine + { + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, (LPARAM) 0X00050005); + expect(0, retVal); + } + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100); + expect(100, retVal); + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 1); + expect(1, retVal); + if (winetest_interactive) + ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_interactive, + "setHotDivider sequence testing", TRUE); + else + ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_noninteractive, + "setHotDivider sequence testing", FALSE); + + DestroyWindow(hChild); +} + +static void test_hdm_imageMessages(HWND hParent) +{ + HIMAGELIST hImageList = ImageList_Create (4, 4, 0, 1, 0); + HIMAGELIST hImageListRetVal; + HWND hChild; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList); + ok(hImageListRetVal == NULL, "Expected NULL, got %d\n", (int) hImageListRetVal); + + hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0); + ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal); + + hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0); + ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE); + + DestroyWindow(hChild); +} + +static void test_hdm_filterMessages(HWND hParent) +{ + HWND hChild; + int retVal; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + assert(hChild); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + todo_wine + { + /* msdn incorrecly states that return value + * is the index of the filter control being + * modified. The sendMessage here should + * return previous filter timeout value + */ + retVal = SendMessage(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100); + expect(1000, retVal); + retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1); + expect(1, retVal); + retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0); + expect(1, retVal); + } + if (winetest_interactive) + ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive, + "filterMessages sequence testing", TRUE); + else + ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_noninteractive, + "filterMessages sequence testing", TRUE); + DestroyWindow(hChild); + +} + +static void test_hdm_unicodeformatMessages(HWND hParent) +{ + HWND hChild; + int retVal; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + retVal = SendMessage(hChild, HDM_SETUNICODEFORMAT, TRUE, 0); + expect(0, retVal); + retVal = SendMessage(hChild, HDM_GETUNICODEFORMAT, 0, 0); + expect(1, retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, unicodeformatMessages_seq, + "unicodeformatMessages sequence testing", FALSE); + DestroyWindow(hChild); +} + +static void test_hdm_bitmapmarginMessages(HWND hParent) +{ + HWND hChild; + int retVal; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0); + expect(6, retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq, + "bitmapmarginMessages sequence testing", FALSE); + DestroyWindow(hChild); +} + +static void test_hdm_index_messages(HWND hParent) +{ + + HWND hChild; + int retVal; + int loopcnt; + int strcmpResult; + int iSize; + static const int lpiarray[2] = {1, 0}; + static int lpiarrayReceived[2]; + static char firstHeaderItem[] = "Name"; + static char secondHeaderItem[] = "Size"; + static char thirdHeaderItem[] = "Type"; + static char fourthHeaderItem[] = "Date Modified"; + static char *items[] = {firstHeaderItem, secondHeaderItem, thirdHeaderItem, fourthHeaderItem}; + HDITEM hdItem; + hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT; + hdItem.fmt = HDF_LEFT; + hdItem.cxy = 80; + hdItem.cchTextMax = 260; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + hChild = create_custom_header_control(hParent, FALSE); + if (winetest_interactive) + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq_interactive, + "adder header control to parent", TRUE); + else + ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, + "adder header control to parent", TRUE); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + for ( loopcnt = 0 ; loopcnt < 4 ; loopcnt++ ) + { + hdItem.pszText = items[loopcnt]; + retVal = SendMessage(hChild, HDM_INSERTITEM, loopcnt, (LPARAM) &hdItem); + ok(retVal == loopcnt, "Adding item %d failed with return value %d\n", ( loopcnt + 1 ), retVal); + } + ok_sequence(sequences, HEADER_SEQ_INDEX, insertItem_seq, "insertItem sequence testing", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + 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); + 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); + 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); + ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq, + "deleteItem_getItemCount sequence testing", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + retVal = SendMessage(hChild, HDM_GETITEM, 3, (LPARAM) &hdItem); + ok(retVal == FALSE, "Getting already-deleted item should return FALSE, got %d\n", retVal); + + retVal = SendMessage(hChild, HDM_GETITEM, 0, (LPARAM) &hdItem); + ok(retVal == TRUE, "Getting the 1st header item should return TRUE, got %d\n", retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, getItem_seq, "getItem sequence testing", FALSE); + + /* check if the item is the right one */ + strcmpResult = strcmp(hdItem.pszText, firstHeaderItem); + expect(0, strcmpResult); + expect(80, hdItem.cxy); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); + retVal = SendMessage(hChild, HDM_SETORDERARRAY, (WPARAM) iSize , (LPARAM) (LPINT) lpiarray ); + ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal); + + retVal = SendMessage(hChild, HDM_GETORDERARRAY, (WPARAM) iSize, (LPARAM) (LPINT) lpiarrayReceived ); + ok(retVal == TRUE, "Getting header items order should return TRUE, got %d\n", retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, orderArray_seq, "set_get_orderArray sequence testing", FALSE); + + /* check if the array order is set correctly and the size of the array is corret. */ + expect(2, iSize); + expect(lpiarray[0], lpiarrayReceived[0]); + expect(lpiarray[1], lpiarrayReceived[1]); + + hdItem.mask = HDI_FORMAT; + hdItem.fmt = HDF_CENTER | HDF_STRING; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + retVal = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM) &hdItem); + ok(retVal == TRUE, "Aligning 1st header item to center should return TRUE, got %d\n", retVal); + hdItem.fmt = HDF_RIGHT | HDF_STRING; + retVal = SendMessage(hChild, HDM_SETITEM, 1, (LPARAM) &hdItem); + ok(retVal == TRUE, "Aligning 2nd header item to right should return TRUE, got %d\n", retVal); + + ok_sequence(sequences, HEADER_SEQ_INDEX, setItem_seq, "setItem sequence testing", FALSE); + 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, \ + "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); + +static LRESULT customdraw_1(int n, NMCUSTOMDRAW *nm) +{ + if (nm == NULL) { /* test ended */ + ok(n==1, "NM_CUSTOMDRAW messages: %d, expected: 1\n", n); + return 0; + } + + switch (n) + { + case 0: + /* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */ + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + return 0; + } + + ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage); + return -1; +} + +static LRESULT customdraw_2(int n, NMCUSTOMDRAW *nm) +{ + if (nm == NULL) { /* test ended */ + ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n); + return 0; + } + + switch (n) + { + case 0: + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + return CDRF_NOTIFYITEMDRAW; + case 1: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + return 0; + case 2: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18); + return 0; + case 3: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + return 0; + } + + ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage); + return 0; +} + +static LRESULT customdraw_3(int n, NMCUSTOMDRAW *nm) +{ + if (nm == NULL) { /* test ended */ + ok(n==5, "NM_CUSTOMDRAW messages: %d, expected: 5\n", n); + return 0; + } + + switch (n) + { + case 0: + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTERASE|CDRF_NOTIFYPOSTPAINT|CDRF_SKIPDEFAULT; + case 1: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + return 0; + case 2: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18); + return 0; + case 3: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + return 0; + case 4: + TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18); + return 0; + } + + ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage); + return 0; +} + + +static LRESULT customdraw_4(int n, NMCUSTOMDRAW *nm) +{ + if (nm == NULL) { /* test ended */ + ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n); + return 0; + } + + switch (n) + { + case 0: + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT; + case 1: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + return 0; + case 2: + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + return 0; + case 3: + TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18); + return 0; + } + + ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage); + return 0; +} + +static void run_customdraw_scenario(CUSTOMDRAWPROC proc) +{ + g_CustomDrawProc = proc; + g_CustomDrawCount = 0; + InvalidateRect(hWndHeader, NULL, TRUE); + UpdateWindow(hWndHeader); + proc(g_CustomDrawCount, NULL); + g_CustomDrawProc = NULL; +} + +static void test_customdraw(void) +{ + int i; + HDITEM item; + RECT rect; + CHAR name[] = "Test"; + hWndHeader = create_header_control(); + GetClientRect(hWndHeader, &rect); + ok(rect.right - rect.left == 670 && rect.bottom - rect.top == 18, + "Tests will fail as header size is %dx%d instead of 670x18\n", + rect.right - rect.left, rect.bottom - rect.top); + + for (i = 0; i < 3; i++) + { + ZeroMemory(&item, sizeof(item)); + item.mask = HDI_TEXT|HDI_WIDTH; + item.cxy = 50*(i+1); + item.pszText = name; + item.lParam = i*5; + SendMessage(hWndHeader, HDM_INSERTITEM, i, (LPARAM)&item); + } + + run_customdraw_scenario(customdraw_1); + run_customdraw_scenario(customdraw_2); + run_customdraw_scenario(customdraw_3); + + ZeroMemory(&item, sizeof(item)); + item.mask = HDI_FORMAT; + item.fmt = HDF_OWNERDRAW; + SendMessage(hWndHeader, HDM_SETITEM, 1, (LPARAM)&item); + g_DrawItem.CtlID = 0; + g_DrawItem.CtlType = ODT_HEADER; + g_DrawItem.hwndItem = hWndHeader; + g_DrawItem.itemID = 1; + g_DrawItem.itemState = 0; + SendMessage(hWndHeader, HDM_GETITEMRECT, 1, (LPARAM)&g_DrawItem.rcItem); + run_customdraw_scenario(customdraw_4); + ok(g_DrawItemReceived, "WM_DRAWITEM not received\n"); + DestroyWindow(hWndHeader); + hWndHeader = NULL; + g_DrawItem.CtlType = 0; + g_DrawItemReceived = FALSE; +} + +static void check_order(const int expected_id[], const int expected_order[], + int count, const char *type) +{ + int i; + HDITEMA hdi; + + ok(getItemCount(hWndHeader) == count, "Invalid item count in order tests\n"); + for (i = 0; i < count; i++) + { + hdi.mask = HDI_LPARAM|HDI_ORDER; + SendMessage(hWndHeader, HDM_GETITEMA, i, (LPARAM)&hdi); + ok(hdi.lParam == expected_id[i], + "Invalid item ids after '%s'- item %d has lParam %d\n", type, i, (int)hdi.lParam); + ok(hdi.iOrder == expected_order[i], + "Invalid item order after '%s'- item %d has iOrder %d\n", type, i, hdi.iOrder); + } +} + +static void test_header_order (void) +{ + const int rand1[] = {0, 1, 1, 0, 4}; + const int rand2[] = {4, 5, 6, 7, 4}; + const int rand3[] = {5, 5, 1, 6, 1}; + const int rand4[] = {1, 5, 2, 7, 6, 1, 4, 2, 3, 2}; + const int rand5[] = {7, 8, 5, 6, 7, 2, 1, 9, 10, 10}; + const int rand6[] = {2, 8, 3, 4, 0}; + + const int ids1[] = {3, 0, 2, 1, 4}; + const int ord1[] = {0, 1, 2, 3, 4}; + const int ids2[] = {3, 9, 7, 0, 2, 1, 4, 8, 6, 5}; + const int ord2[] = {0, 4, 7, 1, 2, 3, 9, 8, 6, 5}; + const int ord3[] = {0, 3, 9, 2, 1, 8, 7, 6, 5, 4}; + const int ids4[] = {9, 0, 1, 8, 6}; + const int ord4[] = {1, 0, 4, 3, 2}; + + char buffer[20]; + HDITEMA hdi; + int i; + + hWndHeader = create_header_control(); + + ZeroMemory(&hdi, sizeof(HDITEMA)); + hdi.mask = HDI_TEXT | HDI_LPARAM; + hdi.pszText = buffer; + strcpy(buffer, "test"); + + for (i = 0; i < 5; i++) + { + hdi.lParam = i; + SendMessage(hWndHeader, HDM_INSERTITEMA, rand1[i], (LPARAM)&hdi); + rand(); + } + check_order(ids1, ord1, 5, "insert without iOrder"); + + hdi.mask |= HDI_ORDER; + for (i = 0; i < 5; i++) + { + hdi.lParam = i + 5; + hdi.iOrder = rand2[i]; + SendMessage(hWndHeader, HDM_INSERTITEMA, rand3[i], (LPARAM)&hdi); + rand(); rand(); + } + check_order(ids2, ord2, 10, "insert with order"); + + hdi.mask = HDI_ORDER; + for (i=0; i<10; i++) + { + hdi.iOrder = rand5[i]; + SendMessage(hWndHeader, HDM_SETITEMA, rand4[i], (LPARAM)&hdi); + rand(); rand(); + } + check_order(ids2, ord3, 10, "setitems changing order"); + + for (i=0; i<5; i++) + SendMessage(hWndHeader, HDM_DELETEITEM, rand6[i], 0); + check_order(ids4, ord4, 5, "deleteitem"); + + DestroyWindow(hWndHeader); +} + +static LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DRAWITEMSTRUCT *di; switch(msg) { case WM_NOTIFY: @@ -489,29 +1434,49 @@ LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP EXPECTEDNOTIFY *expected; int i; + if (hdr->hdr.code == NM_CUSTOMDRAW) + if (g_CustomDrawProc) + return g_CustomDrawProc(g_CustomDrawCount++, (NMCUSTOMDRAW*)hdr); + for (i=0; ihdr.code != unexpectedNotify[i], "Received invalid notify %d\n", hdr->hdr.code); - + if (nReceivedNotify >= nExpectedNotify || hdr->hdr.hwndFrom != hWndHeader ) break; expected = &expectedNotify[nReceivedNotify]; if (hdr->hdr.code != expected->iCode) break; - + nReceivedNotify++; compare_items(hdr->hdr.code, &expected->hdItem, hdr->pitem, expected->fUnicode); break; } + case WM_DRAWITEM: + di = (DRAWITEMSTRUCT *)lParam; + ok(g_DrawItem.CtlType != 0, "Unexpected WM_DRAWITEM\n"); + if (g_DrawItem.CtlType == 0) return 0; + g_DrawItemReceived = TRUE; + compare(di->CtlType, g_DrawItem.CtlType, "%d"); + compare(di->CtlID, g_DrawItem.CtlID, "%d"); + compare(di->hwndItem, g_DrawItem.hwndItem, "%p"); + compare(di->itemID, g_DrawItem.itemID, "%d"); + compare(di->itemState, g_DrawItem.itemState, "%d"); + compare(di->rcItem.left, g_DrawItem.rcItem.left, "%d"); + compare(di->rcItem.top, g_DrawItem.rcItem.top, "%d"); + compare(di->rcItem.right, g_DrawItem.rcItem.right, "%d"); + compare(di->rcItem.bottom, g_DrawItem.rcItem.bottom, "%d"); + break; + case WM_DESTROY: PostQuitMessage(0); break; - + default: return DefWindowProcA(hWnd, msg, wParam, lParam); } - + return 0L; } @@ -528,23 +1493,48 @@ static void init(void) { wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW)); + wc.hCursor = LoadCursorA(NULL, IDC_ARROW); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = "HeaderTestClass"; wc.lpfnWndProc = HeaderTestWndProc; RegisterClassA(&wc); - hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); + hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME), + 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), + NULL, NULL, GetModuleHandleA(NULL), 0); assert(hHeaderParentWnd != NULL); + ShowWindow(hHeaderParentWnd, SW_SHOW); } START_TEST(header) { + HWND parent_hwnd; + init(); test_header_control(); + test_header_order(); + test_customdraw(); DestroyWindow(hHeaderParentWnd); + + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + parent_hwnd = create_custom_parent_window(); + ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent windows", FALSE); + + test_hdm_index_messages(parent_hwnd); + test_hdm_getitemrect(parent_hwnd); + test_hdm_hittest(parent_hwnd); + test_hdm_layout(parent_hwnd); + test_hdm_ordertoindex(parent_hwnd); + test_hdm_sethotdivider(parent_hwnd); + test_hdm_imageMessages(parent_hwnd); + test_hdm_filterMessages(parent_hwnd); + test_hdm_unicodeformatMessages(parent_hwnd); + test_hdm_bitmapmarginMessages(parent_hwnd); + + DestroyWindow(parent_hwnd); + } diff --git a/rostests/winetests/comctl32/imagelist.c b/rostests/winetests/comctl32/imagelist.c index 0ecb03a58ea..3d4c3331372 100644 --- a/rostests/winetests/comctl32/imagelist.c +++ b/rostests/winetests/comctl32/imagelist.c @@ -1,7 +1,9 @@ -/* Unit test suite for imagelist control. +/* + * Unit test suite for imagelist control. * * Copyright 2004 Michael Stefaniuc * Copyright 2002 Mike McCormack for CodeWeavers + * Copyright 2007 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,10 +20,19 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include -#include -#include +#define COBJMACROS +#define CONST_VTABLE + +#include #include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "objbase.h" +#include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */ #include "wine/test.h" @@ -35,6 +46,24 @@ #define REDRAW(hwnd) #endif +#define IMAGELIST_MAGIC (('L' << 8) | 'I') + +#include "pshpack2.h" +/* Header used by ImageList_Read() and ImageList_Write() */ +typedef struct _ILHEAD +{ + USHORT usMagic; + USHORT usVersion; + WORD cCurImage; + WORD cMaxImage; + WORD cGrow; + WORD cx; + WORD cy; + COLORREF bkcolor; + WORD flags; + SHORT ovls[4]; +} ILHEAD; +#include "poppack.h" static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*) = NULL; @@ -264,7 +293,7 @@ static void testHotspot (void) /* check new hotspot, it should be the same like the old one */ himlNew = ImageList_GetDragImage(NULL, &ppt); ok(ppt.x == dx1 && ppt.y == dy1, - "Expected drag hotspot [%d,%d] got [%ld,%ld]\n", + "Expected drag hotspot [%d,%d] got [%d,%d]\n", dx1, dy1, ppt.x, ppt.y); /* check size of new dragged image */ ImageList_GetIconSize(himlNew, &newx, &newy); @@ -283,6 +312,8 @@ static void testHotspot (void) #undef SIZEX2 #undef SIZEY2 #undef HOTSPOTS_MAX + ImageList_Destroy(himl2); + ImageList_Destroy(himl1); DestroyWindow(hwnd); } @@ -327,13 +358,20 @@ static BOOL DoTest1(void) /* remove one extra */ ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n"); + /* check SetImageCount/GetImageCount */ + ok(ImageList_SetImageCount(himl, 3), "couldn't increase image count\n"); + ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n"); + ok(ImageList_SetImageCount(himl, 1), "couldn't decrease image count\n"); + ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n"); + ok(ImageList_SetImageCount(himl, 0), "couldn't decrease image count\n"); + ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n"); + /* destroy it */ ok(ImageList_Destroy(himl),"destroy imagelist failed\n"); - /* icons should be deleted by the imagelist */ - ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n"); - ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n"); - ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\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"); return TRUE; } @@ -366,10 +404,9 @@ static BOOL DoTest2(void) /* destroy it */ ok(ImageList_Destroy(himl),"destroy imagelist failed\n"); - /* icons should be deleted by the imagelist */ - ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n"); - ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n"); - ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\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"); return TRUE; } @@ -541,10 +578,395 @@ static void testMerge(void) ImageList_Destroy(himl1); ImageList_Destroy(himl2); - DeleteObject(hicon1); + DestroyIcon(hicon1); DestroyWindow(hwnd); } +/*********************** imagelist storage test ***************************/ + +#define BMP_CX 48 + +struct my_IStream +{ + IStream is; + char *iml_data; /* written imagelist data */ + ULONG iml_data_size; +}; + +static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface( + IStream* This, + REFIID riid, + void** ppvObject) +{ + assert(0); + return E_NOTIMPL; +} + +static ULONG STDMETHODCALLTYPE Test_Stream_AddRef( + IStream* This) +{ + assert(0); + return 2; +} + +static ULONG STDMETHODCALLTYPE Test_Stream_Release( + IStream* This) +{ + assert(0); + return 1; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Read( + IStream* This, + void* pv, + ULONG cb, + ULONG* pcbRead) +{ + assert(0); + return E_NOTIMPL; +} + +static BOOL allocate_storage(struct my_IStream *my_is, ULONG add) +{ + my_is->iml_data_size += add; + + if (!my_is->iml_data) + my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size); + else + my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size); + + return my_is->iml_data ? TRUE : FALSE; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Write( + IStream* This, + const void* pv, + ULONG cb, + ULONG* pcbWritten) +{ + struct my_IStream *my_is = (struct my_IStream *)This; + ULONG current_iml_data_size = my_is->iml_data_size; + + if (!allocate_storage(my_is, cb)) return E_FAIL; + + memcpy(my_is->iml_data + current_iml_data_size, pv, cb); + if (pcbWritten) *pcbWritten = cb; + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Seek( + IStream* This, + LARGE_INTEGER dlibMove, + DWORD dwOrigin, + ULARGE_INTEGER* plibNewPosition) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize( + IStream* This, + ULARGE_INTEGER libNewSize) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo( + IStream* This, + IStream* pstm, + ULARGE_INTEGER cb, + ULARGE_INTEGER* pcbRead, + ULARGE_INTEGER* pcbWritten) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Commit( + IStream* This, + DWORD grfCommitFlags) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Revert( + IStream* This) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion( + IStream* This, + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion( + IStream* This, + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Stat( + IStream* This, + STATSTG* pstatstg, + DWORD grfStatFlag) +{ + assert(0); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Test_Stream_Clone( + IStream* This, + IStream** ppstm) +{ + assert(0); + return E_NOTIMPL; +} + +static const IStreamVtbl Test_Stream_Vtbl = +{ + Test_Stream_QueryInterface, + Test_Stream_AddRef, + Test_Stream_Release, + Test_Stream_Read, + Test_Stream_Write, + Test_Stream_Seek, + Test_Stream_SetSize, + Test_Stream_CopyTo, + Test_Stream_Commit, + Test_Stream_Revert, + Test_Stream_LockRegion, + Test_Stream_UnlockRegion, + Test_Stream_Stat, + Test_Stream_Clone +}; + +static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 }; + +static INT DIB_GetWidthBytes( int width, int bpp ) +{ + int words; + + switch (bpp) + { + case 1: words = (width + 31) / 32; break; + case 4: words = (width + 7) / 8; break; + case 8: words = (width + 3) / 4; break; + case 15: + case 16: words = (width + 1) / 2; break; + case 24: words = (width * 3 + 3)/4; break; + case 32: words = width; break; + + default: + words=0; + trace("Unknown depth %d, please report.\n", bpp ); + assert(0); + break; + } + return 4 * words; +} + +static void check_bitmap_data(const char *bm_data, ULONG bm_data_size, + INT width, INT height, INT bpp, + const char *comment) +{ + const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data; + const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh)); + ULONG hdr_size, image_size; + + hdr_size = sizeof(*bmfh) + sizeof(*bmih); + if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD); + + ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType); + ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize); + ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1); + ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2); + ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits); + + ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize); + ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width); + ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height); + ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes); + ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount); + + image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight; + ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage); +#if 0 +{ + char fname[256]; + FILE *f; + sprintf(fname, "bmp_%s.bmp", comment); + f = fopen(fname, "wb"); + fwrite(bm_data, 1, bm_data_size, f); + fclose(f); +} +#endif +} + +static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max) +{ + ILHEAD *ilh = (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); + ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur); + ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max); + ok(ilh->cGrow == 4, "wrong cGrow %d (expected 4)\n", ilh->cGrow); + ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx); + ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy); + ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor); + ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags); + ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]); + ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]); + ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]); + ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]); +} + +static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment) +{ + HDC hdc; + char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)]; + BITMAPINFO *bmi = (BITMAPINFO *)bmibuf; + HBITMAP hbmp, hbmp_old; + HBRUSH hbrush; + RECT rc = { 0, 0, cx, cy }; + + hdc = CreateCompatibleDC(0); + + memset(bmi, 0, sizeof(*bmi)); + bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader); + bmi->bmiHeader.biHeight = cx; + bmi->bmiHeader.biWidth = cy; + bmi->bmiHeader.biBitCount = 24; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biCompression = BI_RGB; + hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0); + + hbmp_old = SelectObject(hdc, hbmp); + + hbrush = CreateSolidBrush(color); + FillRect(hdc, &rc, hbrush); + DeleteObject(hbrush); + + DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + SelectObject(hdc, hbmp_old); + DeleteDC(hdc); + + return hbmp; +} + +static void image_list_init(HIMAGELIST himl) +{ + HBITMAP hbm; + char comment[16]; + INT n = 1; + +#define add_bitmap(grey) \ + sprintf(comment, "%d", n++); \ + hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \ + ImageList_Add(himl, hbm, NULL); + + add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0); + add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255); + add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0); + add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255); + add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0); + add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255); +#undef add_bitmap +} + +#define iml_clear_stream_data() \ + HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \ + Test_Stream.iml_data = NULL; \ + Test_Stream.iml_data_size = 0; + +static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, + INT width, INT height, INT bpp, const char *comment) +{ + INT ret, cxx, cyy; + + ret = ImageList_GetImageCount(himl); + ok(ret == cur, "expected cur %d got %d\n", cur, ret); + + ret = ImageList_GetIconSize(himl, &cxx, &cyy); + ok(ret, "ImageList_GetIconSize failed\n"); + ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx); + ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy); + + iml_clear_stream_data(); + ret = ImageList_Write(himl, &Test_Stream.is); + ok(ret, "ImageList_Write failed\n"); + + ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n"); + ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n"); + + check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max); + check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD), + Test_Stream.iml_data_size - sizeof(ILHEAD), + width, height, bpp, comment); +} + +static void test_imagelist_storage(void) +{ + HIMAGELIST himl; + BOOL ret; + + himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1); + ok(himl != 0, "ImageList_Create failed\n"); + + check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, BMP_CX * 4, BMP_CX * 1, 24, "empty"); + + image_list_init(himl); + check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, BMP_CX * 4, BMP_CX * 7, 24, "orig"); + + ret = ImageList_Remove(himl, 4); + ok(ret, "ImageList_Remove failed\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, BMP_CX * 4, BMP_CX * 7, 24, "1"); + + ret = ImageList_Remove(himl, 5); + ok(ret, "ImageList_Remove failed\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, BMP_CX * 4, BMP_CX * 7, 24, "2"); + + ret = ImageList_Remove(himl, 6); + ok(ret, "ImageList_Remove failed\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, BMP_CX * 4, BMP_CX * 7, 24, "3"); + + ret = ImageList_Remove(himl, 7); + ok(ret, "ImageList_Remove failed\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "4"); + + ret = ImageList_Remove(himl, -2); + ok(!ret, "ImageList_Remove(-2) should fail\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "5"); + + ret = ImageList_Remove(himl, 20); + ok(!ret, "ImageList_Remove(20) should fail\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "6"); + + ret = ImageList_Remove(himl, -1); + ok(ret, "ImageList_Remove(-1) failed\n"); + check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, BMP_CX * 4, BMP_CX * 1, 24, "7"); + + ret = ImageList_Destroy(himl); + ok(ret, "ImageList_Destroy failed\n"); + + iml_clear_stream_data(); +} + START_TEST(imagelist) { desktopDC=GetDC(NULL); @@ -557,4 +979,5 @@ START_TEST(imagelist) DoTest2(); DoTest3(); testMerge(); + test_imagelist_storage(); } diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index e8d147d7c70..9138442f9ad 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -2,6 +2,7 @@ * ListView tests * * Copyright 2006 Mike McCormack for CodeWeavers + * Copyright 2007 George Gov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,10 +24,318 @@ #include #include "wine/test.h" +#include "msg.h" + +#define PARENT_SEQ_INDEX 0 +#define LISTVIEW_SEQ_INDEX 1 +#define NUM_MSG_SEQUENCES 2 + +#define LISTVIEW_ID 0 +#define HEADER_ID 1 + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) +#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 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_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 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_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 }, + { 0 } +}; + +static const struct message listview_icon_spacing_seq[] = { + { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(20, 30) }, + { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(25, 35) }, + { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(-1, -1) }, + { 0 } +}; + +static const struct message listview_color_seq[] = { + { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) }, + { LVM_GETBKCOLOR, sent }, + { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) }, + { LVM_GETTEXTCOLOR, sent }, + { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) }, + { LVM_GETTEXTBKCOLOR, sent }, + + { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) }, + { LVM_GETBKCOLOR, sent }, + { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) }, + { LVM_GETTEXTCOLOR, sent }, + { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) }, + { LVM_GETTEXTBKCOLOR, sent }, + + { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE }, + { LVM_GETBKCOLOR, sent }, + { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE }, + { LVM_GETTEXTCOLOR, sent }, + { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE }, + { LVM_GETTEXTBKCOLOR, sent }, + + { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) }, + { LVM_GETBKCOLOR, sent }, + { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) }, + { LVM_GETTEXTCOLOR, sent }, + { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) }, + { LVM_GETTEXTBKCOLOR, sent }, + { 0 } +}; + +static const struct message listview_item_count_seq[] = { + { LVM_GETITEMCOUNT, sent }, + { LVM_INSERTITEM, sent }, + { LVM_INSERTITEM, sent }, + { LVM_INSERTITEM, sent }, + { LVM_GETITEMCOUNT, sent }, + { LVM_DELETEITEM, sent|wparam, 2 }, + { LVM_GETITEMCOUNT, sent }, + { LVM_DELETEALLITEMS, sent }, + { LVM_GETITEMCOUNT, sent }, + { LVM_INSERTITEM, sent }, + { LVM_INSERTITEM, sent }, + { LVM_GETITEMCOUNT, sent }, + { LVM_INSERTITEM, sent }, + { LVM_GETITEMCOUNT, sent }, + { 0 } +}; + +static const struct message listview_itempos_seq[] = { + { LVM_INSERTITEM, sent }, + { LVM_INSERTITEM, sent }, + { LVM_INSERTITEM, sent }, + { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) }, + { LVM_GETITEMPOSITION, sent|wparam, 1 }, + { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) }, + { LVM_GETITEMPOSITION, sent|wparam, 2 }, + { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) }, + { LVM_GETITEMPOSITION, sent|wparam, 0 }, + { 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; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static BOOL register_parent_wnd_class(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = parent_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Listview test parent class"; + return RegisterClassA(&cls); +} + +static HWND create_parent_window(void) +{ + if (!register_parent_wnd_class()) + 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); +} + +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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + msg.id = LISTVIEW_ID; + add_message(sequences, LISTVIEW_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND create_listview_control(void) +{ + 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 | LVS_REPORT, + 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, + 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 LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + msg.id = HEADER_ID; + add_message(sequences, LISTVIEW_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND subclass_header(HWND hwndListview) +{ + struct subclass_info *info; + 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); + + return hwnd; +} static void test_images(void) { - HWND hwnd, hwndparent = 0; + HWND hwnd; DWORD r; LVITEM item; HIMAGELIST himl; @@ -43,7 +352,7 @@ static void test_images(void) r = ImageList_Add(himl, hbmp, 0); ok(r == 0, "should be zero\n"); - hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, + hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); ok(hwnd != NULL, "failed to create listview window\n"); @@ -63,6 +372,7 @@ static void test_images(void) item.iItem = 0; item.iSubItem = 1; item.iImage = 0; + item.pszText = 0; r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); ok(r == -1, "should fail\n"); @@ -94,14 +404,14 @@ static void test_images(void) static void test_checkboxes(void) { - HWND hwnd, hwndparent = 0; + HWND hwnd; LVITEMA item; DWORD r; static CHAR text[] = "Text", text2[] = "Text2", text3[] = "Text3"; - hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, + hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); ok(hwnd != NULL, "failed to create listview window\n"); @@ -113,7 +423,7 @@ static void test_checkboxes(void) item.iSubItem = 0; item.pszText = text; r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); - ok(r == 0, "ret %ld\n", r); + ok(r == 0, "ret %d\n", r); item.iItem = 0; item.mask = LVIF_STATE; @@ -129,7 +439,7 @@ static void test_checkboxes(void) item.iSubItem = 0; item.pszText = text; r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); - ok(r == 1, "ret %ld\n", r); + ok(r == 1, "ret %d\n", r); item.iItem = 1; item.mask = LVIF_STATE; @@ -147,13 +457,13 @@ static void test_checkboxes(void) r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); ok(item.state == 0x1ccc, "state %x\n", item.state); - /* Now add an item without specifying a state and check that it's state goes to 0x1000 */ + /* Now add an item without specifying a state and check that its state goes to 0x1000 */ item.iItem = 2; item.mask = LVIF_TEXT; item.state = 0; item.pszText = text2; r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); - ok(r == 2, "ret %ld\n", r); + ok(r == 2, "ret %d\n", r); item.iItem = 2; item.mask = LVIF_STATE; @@ -161,14 +471,14 @@ static void test_checkboxes(void) r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); ok(item.state == 0x1000, "state %x\n", item.state); - /* Add a further item this time specifying a state and still it's state goes to 0x1000 */ + /* Add a further item this time specifying a state and still its state goes to 0x1000 */ item.iItem = 3; item.mask = LVIF_TEXT | LVIF_STATE; item.stateMask = 0xffff; item.state = 0x2aaa; item.pszText = text3; r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); - ok(r == 3, "ret %ld\n", r); + ok(r == 3, "ret %d\n", r); item.iItem = 3; item.mask = LVIF_STATE; @@ -189,9 +499,19 @@ static void test_checkboxes(void) r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); ok(item.state == 0x2aaa, "state %x\n", item.state); + /* Check that only the bits we asked for are returned, + * and that all the others are set to zero + */ + item.iItem = 3; + item.mask = LVIF_STATE; + item.stateMask = 0xf000; + item.state = 0xffff; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(item.state == 0x2000, "state %x\n", item.state); + /* Set the style again and check that doesn't change an item's state */ r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); - ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r); + ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r); item.iItem = 3; item.mask = LVIF_STATE; @@ -201,7 +521,7 @@ static void test_checkboxes(void) /* Unsetting the checkbox extended style doesn't change an item's state */ r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0); - ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r); + ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r); item.iItem = 3; item.mask = LVIF_STATE; @@ -211,7 +531,7 @@ static void test_checkboxes(void) /* Now setting the style again will change an item's state */ r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); - ok(r == 0, "ret %lx\n", r); + ok(r == 0, "ret %x\n", r); item.iItem = 3; item.mask = LVIF_STATE; @@ -222,6 +542,502 @@ static void test_checkboxes(void) DestroyWindow(hwnd); } +static void insert_column(HWND hwnd, int idx) +{ + LVCOLUMN column; + DWORD rc; + + memset(&column, 0xaa, sizeof(column)); + column.mask = LVCF_SUBITEM; + column.iSubItem = idx; + + rc = ListView_InsertColumn(hwnd, idx, &column); + expect(idx, rc); +} + +static void insert_item(HWND hwnd, int idx) +{ + static CHAR text[] = "foo"; + + LVITEMA item; + DWORD rc; + + memset(&item, 0xaa, sizeof (item)); + item.mask = LVIF_TEXT; + item.iItem = idx; + item.iSubItem = 0; + item.pszText = text; + + rc = ListView_InsertItem(hwnd, &item); + expect(idx, rc); +} + +static void test_items(void) +{ + const LPARAM lparamTest = 0x42; + HWND hwnd; + LVITEMA item; + DWORD r; + static CHAR text[] = "Text"; + + hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, + 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); + ok(hwnd != NULL, "failed to create listview window\n"); + + /* + * Test setting/getting item params + */ + + /* Set up two columns */ + insert_column(hwnd, 0); + insert_column(hwnd, 1); + + /* Insert an item with just a param */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_PARAM; + item.iItem = 0; + item.iSubItem = 0; + item.lParam = lparamTest; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + + /* Test getting of the param */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_PARAM; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); + + /* Set up a subitem */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_TEXT; + item.iItem = 0; + item.iSubItem = 1; + item.pszText = text; + r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + + /* Query param from subitem: returns main item param */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_PARAM; + item.iItem = 0; + item.iSubItem = 1; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); + + /* Set up param on first subitem: no effect */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_PARAM; + item.iItem = 0; + item.iSubItem = 1; + item.lParam = lparamTest+1; + r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + + /* Query param from subitem again: should still return main item param */ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_PARAM; + item.iItem = 0; + item.iSubItem = 1; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); + + /**** Some tests of state highlighting ****/ + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_STATE; + item.iItem = 0; + item.iSubItem = 0; + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + item.iSubItem = 1; + item.state = LVIS_DROPHILITED; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + + memset (&item, 0xaa, sizeof (item)); + item.mask = LVIF_STATE; + item.iItem = 0; + item.iSubItem = 0; + item.stateMask = -1; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED); + item.iSubItem = 1; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED); + + DestroyWindow(hwnd); +} + +static void test_columns(void) +{ + HWND hwnd; + LVCOLUMN column; + DWORD rc; + + hwnd = CreateWindowEx(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, 0xaa, sizeof(column)); + column.mask = 0; + rc = ListView_InsertColumn(hwnd, 0, &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, "Inserting column with no mask failed to set width to 10 with %d\n", rc); + + DestroyWindow(hwnd); +} +/* test setting imagelist between WM_NCCREATE and WM_CREATE */ +static WNDPROC listviewWndProc; +static HIMAGELIST test_create_imagelist; + +static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_CREATE) + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; + lpcs->style |= LVS_REPORT; + SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist); + } + return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam); +} + +static void test_create(void) +{ + HWND hList; + HWND hHeader; + WNDCLASSEX cls; + cls.cbSize = sizeof(WNDCLASSEX); + ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n"); + listviewWndProc = cls.lpfnWndProc; + cls.lpfnWndProc = create_test_wndproc; + cls.lpszClassName = "MyListView32"; + ok(RegisterClassEx(&cls), "RegisterClassEx failed\n"); + + test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10); + 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); + ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n"); + DestroyWindow(hList); +} + +static void test_redraw(void) +{ + HWND hwnd, hwndheader; + + hwnd = create_listview_control(); + hwndheader = subclass_header(hwnd); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + trace("invalidate & update\n"); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + DestroyWindow(hwnd); +} + +static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee); + + if(msg == WM_NOTIFY) { + NMHDR *nmhdr = (PVOID)lp; + if(nmhdr->code == NM_CUSTOMDRAW) { + NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr; + trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage); + switch(nmlvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + SetBkColor(nmlvcd->nmcd.hdc, c0ffee); + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + nmlvcd->clrTextBk = CLR_DEFAULT; + return CDRF_NOTIFYSUBITEMDRAW; + case CDDS_ITEMPREPAINT | CDDS_SUBITEM: + clr = GetBkColor(nmlvcd->nmcd.hdc); + todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr); + return CDRF_NOTIFYPOSTPAINT; + case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: + clr = GetBkColor(nmlvcd->nmcd.hdc); + todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr); + return CDRF_DODEFAULT; + } + return CDRF_DODEFAULT; + } + } + + return DefWindowProcA(hwnd, msg, wp, lp); +} + +static void test_customdraw(void) +{ + HWND hwnd; + WNDPROC oldwndproc; + + hwnd = create_listview_control(); + + insert_column(hwnd, 0); + insert_column(hwnd, 1); + insert_item(hwnd, 0); + + oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC, + (LONG_PTR)cd_wndproc); + + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + + SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc); + + DestroyWindow(hwnd); +} + +static void test_icon_spacing(void) +{ + /* LVM_SETICONSPACING */ + /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */ + /* note: the first test will fail if the default icon spacing is not (43,43) */ + + HWND hwnd; + DWORD r; + + hwnd = create_custom_listview_control(LVS_ICON); + ok(hwnd != NULL, "failed to create a listview window\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + trace("test icon spacing\n"); + todo_wine { + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30)); + expect(MAKELONG(43,43), r); + } + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35)); + expect(MAKELONG(20,30), r); + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1)); + expect(MAKELONG(25,35), r); + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); +} + +static void test_color(void) +{ + /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */ + + HWND hwnd; + DWORD r; + int i; + + COLORREF color; + COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)}; + + hwnd = create_listview_control(); + ok(hwnd != NULL, "failed to create a listview window\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + trace("test color seq\n"); + for (i = 0; i < 4; i++) + { + color = colors[i]; + + r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color); + expect(color, r); + + r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color); + expect (TRUE, r); + r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color); + expect(color, r); + + r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color); + expect(color, r); + } + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); +} + +static void test_item_count(void) +{ + /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */ + + HWND hwnd; + DWORD r; + + LVITEM item0; + LVITEM item1; + LVITEM item2; + static CHAR item0text[] = "item0"; + static CHAR item1text[] = "item1"; + static CHAR item2text[] = "item2"; + + hwnd = create_listview_control(); + ok(hwnd != NULL, "failed to create a listview window\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + trace("test item count\n"); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(0, r); + + /* [item0] */ + item0.mask = LVIF_TEXT; + item0.iItem = 0; + item0.iSubItem = 0; + item0.pszText = item0text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0); + expect(0, r); + + /* [item0, item1] */ + item1.mask = LVIF_TEXT; + item1.iItem = 1; + item1.iSubItem = 0; + item1.pszText = item1text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1); + expect(1, r); + + /* [item0, item1, item2] */ + item2.mask = LVIF_TEXT; + item2.iItem = 2; + item2.iSubItem = 0; + item2.pszText = item2text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2); + expect(2, r); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(3, r); + + /* [item0, item1] */ + r = SendMessage(hwnd, LVM_DELETEITEM, (WPARAM) 2, 0); + expect(TRUE, r); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(2, r); + + /* [] */ + r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0); + expect(TRUE, r); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(0, r); + + /* [item0] */ + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1); + expect(0, r); + + /* [item0, item1] */ + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1); + expect(1, r); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(2, r); + + /* [item0, item1, item2] */ + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2); + expect(2, r); + + r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(3, r); + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); +} + +static void test_item_position(void) +{ + /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */ + + HWND hwnd; + DWORD r; + POINT position; + + LVITEM item0; + LVITEM item1; + LVITEM item2; + static CHAR item0text[] = "item0"; + static CHAR item1text[] = "item1"; + static CHAR item2text[] = "item2"; + + hwnd = create_custom_listview_control(LVS_ICON); + ok(hwnd != NULL, "failed to create a listview window\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + trace("test item position\n"); + + /* [item0] */ + item0.mask = LVIF_TEXT; + item0.iItem = 0; + item0.iSubItem = 0; + item0.pszText = item0text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0); + expect(0, r); + + /* [item0, item1] */ + item1.mask = LVIF_TEXT; + item1.iItem = 1; + item1.iSubItem = 0; + item1.pszText = item1text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1); + expect(1, r); + + /* [item0, item1, item2] */ + item2.mask = LVIF_TEXT; + item2.iItem = 2; + item2.iSubItem = 0; + item2.pszText = item2text; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2); + expect(2, r); + + r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5)); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position); + expect(TRUE, r); + expect2(10, 5, position.x, position.y); + + r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0)); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position); + expect(TRUE, r); + expect2(0, 0, position.x, position.y); + + r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20)); + expect(TRUE, r); + r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position); + expect(TRUE, r); + expect2(20, 20, position.x, position.y); + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(hwnd); +} + START_TEST(listview) { INITCOMMONCONTROLSEX icc; @@ -230,6 +1046,22 @@ START_TEST(listview) icc.dwSize = sizeof icc; InitCommonControlsEx(&icc); + 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); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + test_images(); test_checkboxes(); + test_items(); + test_create(); + test_redraw(); + test_customdraw(); + test_icon_spacing(); + test_color(); + test_item_count(); + test_item_position(); + test_columns(); } diff --git a/rostests/winetests/comctl32/misc.c b/rostests/winetests/comctl32/misc.c new file mode 100644 index 00000000000..881f0b0082d --- /dev/null +++ b/rostests/winetests/comctl32/misc.c @@ -0,0 +1,159 @@ +/* + * Misc tests + * + * Copyright 2006 Paul Vriens + * + * 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 +#include + +#include "wine/test.h" + +static PVOID (WINAPI * pAlloc)(LONG); +static PVOID (WINAPI * pReAlloc)(PVOID, LONG); +static BOOL (WINAPI * pFree)(PVOID); +static LONG (WINAPI * pGetSize)(PVOID); + +static INT (WINAPI * pStr_GetPtrA)(LPCSTR, LPSTR, INT); +static BOOL (WINAPI * pStr_SetPtrA)(LPSTR, LPCSTR); +static INT (WINAPI * pStr_GetPtrW)(LPCWSTR, LPWSTR, INT); +static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR); + +static HMODULE hComctl32 = 0; + +#define COMCTL32_GET_PROC(ordinal, func) \ + p ## func = (void*)GetProcAddress(hComctl32, (LPSTR)ordinal); \ + if(!p ## func) { \ + trace("GetProcAddress(%d)(%s) failed\n", ordinal, #func); \ + FreeLibrary(hComctl32); \ + } + +#define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got) + +static BOOL InitFunctionPtrs(void) +{ + hComctl32 = LoadLibraryA("comctl32.dll"); + + if(!hComctl32) + { + trace("Could not load comctl32.dll\n"); + return FALSE; + } + + COMCTL32_GET_PROC(71, Alloc); + COMCTL32_GET_PROC(72, ReAlloc); + COMCTL32_GET_PROC(73, Free); + COMCTL32_GET_PROC(74, GetSize); + + COMCTL32_GET_PROC(233, Str_GetPtrA) + COMCTL32_GET_PROC(234, Str_SetPtrA) + COMCTL32_GET_PROC(235, Str_GetPtrW) + COMCTL32_GET_PROC(236, Str_SetPtrW) + + return TRUE; +} + +static void test_GetPtrAW(void) +{ + if (pStr_GetPtrA) + { + static const char source[] = "Just a source string"; + static const char desttest[] = "Just a destination string"; + static char dest[MAX_PATH]; + int sourcelen; + int destsize = MAX_PATH; + int count = -1; + + sourcelen = strlen(source) + 1; + + count = pStr_GetPtrA(NULL, NULL, 0); + ok (count == 0, "Expected count to be 0, it was %d\n", count); + + if (0) + { + /* Crashes on W98, NT4, W2K, XP, W2K3 + * Our implementation also crashes and we should probably leave + * it like that. + */ + count = -1; + count = pStr_GetPtrA(NULL, NULL, destsize); + trace("count : %d\n", count); + } + + count = 0; + count = pStr_GetPtrA(source, NULL, 0); + ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count); + + count = 0; + strcpy(dest, desttest); + count = pStr_GetPtrA(source, dest, 0); + ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count); + ok (!lstrcmp(dest, desttest), "Expected destination to not have changed\n"); + + count = 0; + count = pStr_GetPtrA(source, NULL, destsize); + ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count); + + count = 0; + count = pStr_GetPtrA(source, dest, destsize); + ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count); + ok (!lstrcmp(source, dest), "Expected source and destination to be the same\n"); + + count = -1; + strcpy(dest, desttest); + count = pStr_GetPtrA(NULL, dest, destsize); + ok (count == 0, "Expected count to be 0, it was %d\n", count); + ok (dest[0] == '\0', "Expected destination to be cut-off and 0 terminated\n"); + + count = 0; + destsize = 15; + count = pStr_GetPtrA(source, dest, destsize); + ok (count == 15, "Expected count to be 15, it was %d\n", count); + ok (!memcmp(source, dest, 14), "Expected first part of source and destination to be the same\n"); + ok (dest[14] == '\0', "Expected destination to be cut-off and 0 terminated\n"); + } +} + +static void test_Alloc(void) +{ + PCHAR p = pAlloc(0); + ok(p != NULL, "p=%p\n", p); + ok(pFree(p), "\n"); + p = pAlloc(1); + ok(p != NULL, "\n"); + *p = '\0'; + expect(1, pGetSize(p)); + p = pReAlloc(p, 2); + ok(p != NULL, "\n"); + expect(2, pGetSize(p)); + ok(pFree(p), "\n"); + ok(pFree(NULL), "\n"); + p = pReAlloc(NULL, 2); + ok(p != NULL, "\n"); + ok(pFree(p), "\n"); +} + +START_TEST(misc) +{ + if(!InitFunctionPtrs()) + return; + + test_GetPtrAW(); + test_Alloc(); + + FreeLibrary(hComctl32); +} diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c index 89c9ae41800..fae4a376c51 100644 --- a/rostests/winetests/comctl32/monthcal.c +++ b/rostests/winetests/comctl32/monthcal.c @@ -2,6 +2,7 @@ * comctl32 month calendar unit tests * * Copyright (C) 2006 Vitaliy Margolen + * Copyright (C) 2007 Farshad Agah * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,13 +21,296 @@ #include -#include "windows.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" #include "commctrl.h" #include "wine/test.h" +#include +#include +#include "msg.h" -void test_monthcal(void) +#define expect(expected, got) ok(expected == got, "Expected %d, got %d\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 const struct message create_parent_window_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_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_monthcal_control_seq[] = { + { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, + { WM_QUERYUISTATE, sent }, + { WM_GETFONT, sent }, + { WM_PARENTNOTIFY, sent|wparam, WM_CREATE}, + { 0 } +}; + +static const struct message create_monthcal_multi_sel_style_seq[] = { + { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, + { WM_QUERYUISTATE, sent }, + { WM_GETFONT, sent }, + { 0 } +}; + +static const struct message monthcal_color_seq[] = { + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0}, + + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0}, + + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0}, + + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0}, + + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0}, + + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0}, + { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)}, + { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0}, + { 0 } +}; + +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}, + { MCM_GETCURSEL, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +static const struct message monthcal_first_day_seq[] = { + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + + { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11}, + { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +static const struct message monthcal_unicode_seq[] = { + { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0}, + { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0}, + { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0}, + { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0}, + { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0}, + { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0}, + { 0 } +}; + +static const struct message monthcal_hit_test_seq[] = { + { MCM_SETCURSEL, sent|wparam, 0}, + { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 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}, + { 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}, + { 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 } +}; + +static const struct message monthcal_todaylink_seq[] = { + { MCM_HITTEST, sent|wparam, 0}, + { 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_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0}, + { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, + { MCM_GETCURSEL, sent|wparam, 0}, + { 0 } +}; + +static const struct message monthcal_today_seq[] = { + { MCM_SETTODAY, sent|wparam, 0}, + { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, + { MCM_GETTODAY, sent|wparam, 0}, + { MCM_SETTODAY, sent|wparam, 0}, + { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0}, + { MCM_GETTODAY, sent|wparam, 0}, + { 0 } +}; + +static const struct message monthcal_scroll_seq[] = { + { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0}, + { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0}, + { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0}, + { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0}, + { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0}, + { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0}, + { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0}, + { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0}, + { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +static const struct message monthcal_monthrange_seq[] = { + { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE}, + { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE}, + { 0 } +}; + +static const struct message monthcal_max_sel_day_seq[] = { + { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0}, + { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0}, + { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0}, + { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0}, + { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0}, + { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +/* expected message sequence for parent*/ +static const struct message destroy_monthcal_parent_msgs_seq[] = { + { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY}, + { 0 } +}; + +/* expected message sequence for child*/ +static const struct message destroy_monthcal_child_msgs_seq[] = { + { 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 } +}; + +static const struct message destroy_monthcal_multi_sel_style_seq[] = { + { WM_DESTROY, sent|wparam|lparam, 0, 0}, + { WM_NCDESTROY, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +/* expected message sequence for parent window*/ +static const struct message destroy_parent_seq[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, 0}, + { WM_WINDOWPOSCHANGED, sent|wparam, 0}, + { WM_NCACTIVATE, sent|wparam|lparam, 0, 0}, + { WM_ACTIVATE, sent|wparam|lparam, 0, 0}, + { WM_ACTIVATEAPP, sent|wparam, 0}, + { WM_KILLFOCUS, sent|wparam|lparam, 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}, + { WM_NCDESTROY, sent|wparam|lparam, 0, 0}, + { 0 } +}; + +static void test_monthcal(void) { HWND hwnd; SYSTEMTIME st[2], st1[2]; @@ -88,9 +372,787 @@ void test_monthcal(void) st[1].wYear += 4; 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"); + + DestroyWindow(hwnd); +} + +static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static BOOL register_parent_wnd_class(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = parent_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Month-Cal test parent class"; + return RegisterClassA(&cls); +} + +static HWND create_parent_window(void) +{ + HWND hwnd; + + InitCommonControls(); + + /* flush message sequences, so we can check the new sequence by the end of function */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + if (!register_parent_wnd_class()) + return NULL; + + hwnd = CreateWindowEx(0, "Month-Cal test parent class", + "Month-Cal test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 500, 500, + GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); + + assert(hwnd); + + /* check for message sequences */ + ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE); + + return hwnd; +} + +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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("monthcal: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, MONTHCAL_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND create_monthcal_control(DWORD style, HWND parent_window) +{ + struct subclass_info *info; + HWND hwnd; + static const INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES}; + + InitCommonControlsEx(&ic); + + info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); + if (!info) + return NULL; + + hwnd = CreateWindowEx(0, + MONTHCAL_CLASS, + "", + style, + 0, 0, 300, 400, + parent_window, NULL, GetModuleHandleA(NULL), NULL); + + if (!hwnd) + { + HeapFree(GetProcessHeap(), 0, info); + return NULL; + } + + info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)monthcal_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info); + + return hwnd; +} + + +/* Setter and Getters Tests */ + +static void test_monthcal_color(HWND hwnd) +{ + int res, temp; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for color*/ + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0); + expect(RGB(255,255,255), temp); + + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0); + expect(RGB(255,255,255), temp); + + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0); + expect(RGB(255,255,255), temp); + + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0); + expect(RGB(255,255,255), temp); + + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0); + expect(RGB(255,255,255), temp); + + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0); + expect(RGB(0,0,0), temp); + res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255)); + expect(temp, res); + temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0); + expect(RGB(255,255,255), temp); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE); +} + +static void test_monthcal_currDate(HWND hwnd) +{ + SYSTEMTIME st_original, st_new, st_test; + int res; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for current date selected */ + st_original.wYear = 2000; + st_original.wMonth = 11; + st_original.wDay = 28; + st_original.wHour = 11; + st_original.wMinute = 59; + st_original.wSecond = 30; + st_original.wMilliseconds = 0; + st_original.wDayOfWeek = 0; + + st_new = st_test = st_original; + + /* Should not validate the time */ + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test); + expect(1,res); + + /* Overflow matters, check for wDay */ + st_test.wDay += 4; + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test); + expect(0,res); + + /* correct wDay before checking for wMonth */ + st_test.wDay -= 4; + expect(st_original.wDay, st_test.wDay); + + /* Overflow matters, check for wMonth */ + st_test.wMonth += 4; + res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test); + expect(0,res); + + /* checking if gets the information right, modify st_new */ + st_new.wYear += 4; + st_new.wMonth += 4; + st_new.wDay += 4; + st_new.wHour += 4; + st_new.wMinute += 4; + st_new.wSecond += 4; + + res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new); + expect(1, res); + + /* st_new change to st_origin, above settings with overflow */ + /* should not change the current settings */ + 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); + + /* lparam cannot be NULL */ + res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM) NULL); + expect(0, res); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE); } +static void test_monthcal_firstDay(HWND hwnd) +{ + int res, fday, i, prev; + TCHAR b[128]; + LCID lcid = LOCALE_USER_DEFAULT; + + 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)){ + fday = atoi(b); + res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); + expect(fday, res); + prev = fday; + + /* 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); + expect(prev, res); + res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); + prev = res; + + if (i == -1){ + expect(MAKELONG(fday, FALSE), res); + }else if (i >= 7){ + expect(MAKELONG(fday, TRUE), res); + }else{ + expect(MAKELONG(i, TRUE), res); + } + } + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE); + + }else{ + skip("Cannot retrieve first day of the week\n"); + } + +} + +static void test_monthcal_unicode(HWND hwnd) +{ + int res, temp; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for Unicode format */ + + /* getting the current settings */ + temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); + + /* setting to 1, should return previous settings */ + res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0); + expect(temp, res); + + /* current setting is 1, so, should return 1 */ + res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); + todo_wine {expect(1, res);} + + /* setting to 0, should return previous settings */ + res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0); + todo_wine {expect(1, res);} + + /* current setting is 0, so, it should return 0 */ + res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); + expect(0, res); + + /* should return previous settings */ + res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0); + expect(0, res); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE); +} + +static void test_monthcal_HitTest(HWND hwnd) +{ + MCHITTESTINFO mchit; + int res; + SYSTEMTIME st; + + memset(&mchit, 0, sizeof(MCHITTESTINFO)); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + st.wYear = 2007; + st.wMonth = 4; + st.wDay = 11; + st.wHour = 1; + st.wMinute = 0; + st.wSecond = 0; + st.wMilliseconds = 0; + st.wDayOfWeek = 0; + + 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); + 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(mchit.uHit, res); + todo_wine {expect(MCHT_NOWHERE, 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); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_NOWHERE, res);} + + /* (500, 500) is completely out of the control and should not be active */ + mchit.pt.x = 500; + mchit.pt.y = 500; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(500, mchit.pt.x); + expect(500, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_NOWHERE, res);} + + /* (120, 180) is in active area - calendar background */ + mchit.pt.x = 120; + mchit.pt.y = 180; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(120, mchit.pt.x); + expect(180, mchit.pt.y); + expect(mchit.uHit, res); + expect(MCHT_CALENDARBK, res); + + /* (50, 40) is in active area - previous month button */ + mchit.pt.x = 50; + mchit.pt.y = 40; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(50, mchit.pt.x); + expect(40, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEBTNPREV, res);} + + /* (90, 40) is in active area - background section of the title */ + mchit.pt.x = 90; + mchit.pt.y = 40; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(90, mchit.pt.x); + expect(40, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLE, res);} + + /* (140, 40) is in active area - month section of the title */ + mchit.pt.x = 140; + mchit.pt.y = 40; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(140, mchit.pt.x); + expect(40, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEMONTH, res);} + + /* (250, 40) is in active area - next month button */ + mchit.pt.x = 250; + mchit.pt.y = 40; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(250, mchit.pt.x); + expect(40, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEBTNNEXT, res);} + + /* (70, 70) is in active area - day of the week */ + mchit.pt.x = 70; + mchit.pt.y = 70; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(70, mchit.pt.x); + expect(70, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_CALENDARDAY, res);} + + /* (70, 90) is in active area - date from prev month */ + mchit.pt.x = 70; + mchit.pt.y = 90; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(70, mchit.pt.x); + expect(90, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_CALENDARDATEPREV, res);} + +#if 0 + /* (125, 115) is in active area - date from this month */ + mchit.pt.x = 125; + mchit.pt.y = 115; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(125, mchit.pt.x); + expect(115, mchit.pt.y); + expect(mchit.uHit, res); + expect(MCHT_CALENDARDATE, res); +#endif + + /* (80, 220) is in active area - background section of the title */ + mchit.pt.x = 80; + mchit.pt.y = 220; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(80, mchit.pt.x); + expect(220, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEBK, res);} + + /* (140, 215) is in active area - month section of the title */ + mchit.pt.x = 140; + mchit.pt.y = 215; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(140, mchit.pt.x); + expect(215, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEMONTH, res);} + + /* (170, 215) is in active area - year section of the title */ + mchit.pt.x = 170; + mchit.pt.y = 215; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(170, mchit.pt.x); + expect(215, mchit.pt.y); + expect(mchit.uHit, res); + todo_wine {expect(MCHT_TITLEYEAR, res);} + + /* (150, 260) is in active area - date from this month */ + mchit.pt.x = 150; + mchit.pt.y = 260; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(150, mchit.pt.x); + expect(260, 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);} + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE); +} + +static void test_monthcal_todaylink(HWND hwnd) +{ + MCHITTESTINFO mchit; + SYSTEMTIME st_test, st_new; + BOOL error = FALSE; + int res; + + memset(&mchit, 0, sizeof(MCHITTESTINFO)); + + 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; + 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);} + if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res + || MCHT_TODAYLINK != res) + error = TRUE; + + 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); + + 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)); + expect(0, res); + + memset(&st_new, 0, sizeof(SYSTEMTIME)); + res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new); + expect(1, res); + expect(1, st_new.wDay); + expect(1, st_new.wMonth); + expect(2005, st_new.wYear); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE); +} + +static void test_monthcal_today(HWND hwnd) +{ + SYSTEMTIME st_test, st_new; + int res; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for "today" information */ + + /* check for overflow, should be ok */ + st_test.wDay = 38; + st_test.wMonth = 38; + + st_new.wDay = 27; + st_new.wMonth = 27; + + SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test); + + res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new); + expect(1, res); + + /* st_test should not change */ + expect(38, st_test.wDay); + expect(38, st_test.wMonth); + + /* st_new should change, overflow does not matter */ + expect(38, st_new.wDay); + expect(38, st_new.wMonth); + + /* check for zero, should be ok*/ + st_test.wDay = 0; + st_test.wMonth = 0; + + SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test); + + res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new); + expect(1, res); + + /* st_test should not change */ + expect(0, st_test.wDay); + expect(0, st_test.wMonth); + + /* st_new should change to zero*/ + expect(0, st_new.wDay); + expect(0, st_new.wMonth); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE); +} + +static void test_monthcal_scroll(HWND hwnd) +{ + int res; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for scroll rate */ + res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0); + expect(0, res); + + res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0); + expect(2, res); + res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0); + expect(3, res); + + res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0); + expect(3, res); + res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0); + expect(12, res); + + res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0); + expect(12, res); + res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0); + expect(15, res); + + res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0); + expect(15, res); + res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0); + expect(-5, res); + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE); +} + +static void test_monthcal_monthrange(HWND hwnd) +{ + int res; + SYSTEMTIME st_visible[2], st_daystate[2]; + + 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]; + + 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(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(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); +} + +static void test_monthcal_MaxSelDay(HWND hwnd) +{ + int res; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Setter and Getters for max selected days */ + res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0); + expect(1, res); + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(5, res); + + res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0); + expect(1, res); + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + expect(15, res); + + res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0); + todo_wine {expect(0, res);} + res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); + todo_wine {expect(15, res);} + + ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE); +} + + START_TEST(monthcal) { + HWND hwnd, parent_wnd; test_monthcal(); + + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + + 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); + + 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); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(parent_wnd); + ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE); } diff --git a/rostests/winetests/comctl32/mru.c b/rostests/winetests/comctl32/mru.c index 5b51736ab39..2893a1015fe 100644 --- a/rostests/winetests/comctl32/mru.c +++ b/rostests/winetests/comctl32/mru.c @@ -111,7 +111,7 @@ static void check_reg_entries(const char *mrulist, const char**items) buff[0] = '\0'; ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size); - ok(!ret && buff[0], "Checking MRU: got %ld from RegQueryValueExW\n", ret); + ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret); if(ret || !buff[0]) return; ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n", @@ -128,7 +128,7 @@ static void check_reg_entries(const char *mrulist, const char**items) buff[0] = '\0'; ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size); ok(!ret && buff[0], - "Checking MRU item %d ('%c'): got %ld from RegQueryValueExW\n", + "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n", i, mrulist[i], ret); if(ret || !buff[0]) return; ok(!strcmp(buff, items[mrulist[i]-'a']), @@ -165,37 +165,39 @@ static void test_MRUListA(void) if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA) return; -#if 0 /* Create (NULL) - crashes native */ + if (0) + { + /* Create (NULL) - crashes native */ hMRU = pCreateMRUListA(NULL); -#endif + } /* Create (size too small) */ mruA.cbSize = sizeof(mruA) - 2; - hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA); + hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA); ok (!hMRU && !GetLastError(), - "CreateMRUListA(too small) expected NULL,0 got %p,%ld\n", + "CreateMRUListA(too small) expected NULL,0 got %p,%d\n", hMRU, GetLastError()); mruA.cbSize = sizeof(mruA); /* Create (size too big) */ mruA.cbSize = sizeof(mruA) + 2; - hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA); + hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA); ok (!hMRU && !GetLastError(), - "CreateMRUListA(too big) expected NULL,0 got %p,%ld\n", + "CreateMRUListA(too big) expected NULL,0 got %p,%d\n", hMRU, GetLastError()); mruA.cbSize = sizeof(mruA); /* Create (NULL hKey) */ - hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA); + hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA); ok (!hMRU && !GetLastError(), - "CreateMRUListA(NULL key) expected NULL,0 got %p,%ld\n", + "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n", hMRU, GetLastError()); /* Create (NULL name) */ mruA.lpszSubKey = NULL; - hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA); + hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA); ok (!hMRU && !GetLastError(), - "CreateMRUListA(NULL name) expected NULL,0 got %p,%ld\n", + "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n", hMRU, GetLastError()); mruA.lpszSubKey = REG_TEST_SUBKEYA; @@ -204,9 +206,9 @@ static void test_MRUListA(void) "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); if (!hKey) return; - hMRU = create_mruA(hKey, MRUF_STRING_LIST, cmp_mru_strA); + hMRU = create_mruA(hKey, MRUF_STRING_LIST, (PROC)cmp_mru_strA); ok(hMRU && !GetLastError(), - "CreateMRUListA(string) expected non-NULL,0 got %p,%ld\n", + "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n", hMRU, GetLastError()); if (hMRU) @@ -220,38 +222,39 @@ static void test_MRUListA(void) SetLastError(0); iRet = pAddMRUStringA(NULL, checks[0]); ok(iRet == -1 && !GetLastError(), - "AddMRUStringA(NULL list) expected -1,0 got %d,%ld\n", + "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n", iRet, GetLastError()); /* Add (NULL string) */ -#if 0 + if (0) + { /* Some native versions crash when passed NULL or fail to SetLastError() */ SetLastError(0); iRet = pAddMRUStringA(hMRU, NULL); ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER, - "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%ld\n", + "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n", iRet, GetLastError()); -#endif + } /* Add 3 strings. Check the registry is correct after each add */ SetLastError(0); iRet = pAddMRUStringA(hMRU, checks[0]); ok(iRet == 0 && !GetLastError(), - "AddMRUStringA(1) expected 0,0 got %d,%ld\n", + "AddMRUStringA(1) expected 0,0 got %d,%d\n", iRet, GetLastError()); check_reg_entries("a", checks); SetLastError(0); iRet = pAddMRUStringA(hMRU, checks[1]); ok(iRet == 1 && !GetLastError(), - "AddMRUStringA(2) expected 1,0 got %d,%ld\n", + "AddMRUStringA(2) expected 1,0 got %d,%d\n", iRet, GetLastError()); check_reg_entries("ba", checks); SetLastError(0); iRet = pAddMRUStringA(hMRU, checks[2]); ok(iRet == 2 && !GetLastError(), - "AddMRUStringA(2) expected 2,0 got %d,%ld\n", + "AddMRUStringA(2) expected 2,0 got %d,%d\n", iRet, GetLastError()); check_reg_entries("cba", checks); @@ -261,7 +264,7 @@ static void test_MRUListA(void) SetLastError(0); iRet = pAddMRUStringA(hMRU, checks[1]); ok(iRet == 1 && !GetLastError(), - "AddMRUStringA(re-add 1) expected 1,0 got %d,%ld\n", + "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n", iRet, GetLastError()); check_reg_entries("bca", checks); @@ -269,7 +272,7 @@ static void test_MRUListA(void) SetLastError(0); iRet = pAddMRUStringA(hMRU, checks[3]); ok(iRet == 0 && !GetLastError(), - "AddMRUStringA(add new) expected 0,0 got %d,%ld\n", + "AddMRUStringA(add new) expected 0,0 got %d,%d\n", iRet, GetLastError()); checks[0] = checks[3]; check_reg_entries("abc", checks); @@ -285,8 +288,6 @@ static void test_MRUListA(void) START_TEST(mru) { hComctl32 = GetModuleHandleA("comctl32.dll"); - if (!hComctl32) - return; delete_reg_entries(); if (!create_reg_entries()) diff --git a/rostests/winetests/comctl32/msg.c b/rostests/winetests/comctl32/msg.c new file mode 100644 index 00000000000..2129f222e01 --- /dev/null +++ b/rostests/winetests/comctl32/msg.c @@ -0,0 +1,251 @@ +/* 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 new file mode 100644 index 00000000000..2ec3ea17a85 --- /dev/null +++ b/rostests/winetests/comctl32/msg.h @@ -0,0 +1,73 @@ +/* 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 +#include +#include "wine/test.h" + +/* undocumented SWP flags - from SDK 3.1 */ +#define SWP_NOCLIENTSIZE 0x0800 +#define SWP_NOCLIENTMOVE 0x1000 + +typedef enum +{ + sent = 0x1, + posted = 0x2, + parent = 0x4, + wparam = 0x8, + lparam = 0x10, + defwinproc = 0x20, + beginpaint = 0x40, + optional = 0x80, + hook = 0x100, + winevent_hook =0x200, + id = 0x400 +} msg_flags_t; + +struct message +{ + UINT message; /* the WM_* code */ + msg_flags_t flags; /* message props */ + WPARAM wParam; /* expected value of wParam */ + LPARAM lParam; /* expected value of lParam */ + UINT id; /* id of the window */ +}; + +struct msg_sequence +{ + int count; + int size; + 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); + +#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); + +void init_msg_sequences(struct msg_sequence **seq, int n); diff --git a/rostests/winetests/comctl32/progress.c b/rostests/winetests/comctl32/progress.c index 35b75514daf..42c1e8df5d6 100644 --- a/rostests/winetests/comctl32/progress.c +++ b/rostests/winetests/comctl32/progress.c @@ -24,27 +24,42 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" -#include "commctrl.h" +#include "commctrl.h" #include "wine/test.h" -HWND hProgressParentWnd, hProgressWnd; +static HWND hProgressParentWnd, hProgressWnd; static const char progressTestClass[] = "ProgressBarTestClass"; -LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +/* try to make sure pending X events have been processed before continuing */ +static void flush_events(void) +{ + MSG msg; + int diff = 100; + DWORD time = GetTickCount() + diff; + + while (diff > 0) + { + if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break; + while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg ); + diff = time - GetTickCount(); + } +} + +static LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); break; - + default: return DefWindowProcA(hWnd, msg, wParam, lParam); } - + return 0L; } @@ -52,7 +67,7 @@ static WNDPROC progress_wndproc; static BOOL erased; static RECT last_paint_rect; -LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_PAINT) { @@ -69,7 +84,7 @@ LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM static void update_window(HWND hWnd) { UpdateWindow(hWnd); - ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n"); + ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n"); } @@ -78,29 +93,29 @@ static void init(void) WNDCLASSA wc; INITCOMMONCONTROLSEX icex; RECT rect; - + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_PROGRESS_CLASS; InitCommonControlsEx(&icex); - + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW)); + wc.hCursor = LoadCursorA(NULL, IDC_ARROW); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = progressTestClass; wc.lpfnWndProc = ProgressTestWndProc; RegisterClassA(&wc); - + rect.left = 0; rect.top = 0; rect.right = 400; rect.bottom = 20; assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE)); - + hProgressParentWnd = CreateWindowExA(0, progressTestClass, "Progress Bar Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0); assert(hProgressParentWnd != NULL); @@ -110,23 +125,24 @@ static void init(void) 0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0); assert(hProgressWnd != NULL); progress_wndproc = (WNDPROC)SetWindowLongPtr(hProgressWnd, GWLP_WNDPROC, (LPARAM)ProgressSubclassProc); - + ShowWindow(hProgressParentWnd, SW_SHOWNORMAL); ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n"); - update_window(hProgressParentWnd); + flush_events(); + update_window(hProgressParentWnd); } static void cleanup(void) { MSG msg; - + PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0); while (GetMessageA(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessageA(&msg); } - + UnregisterClassA(progressTestClass, GetModuleHandleA(NULL)); } @@ -147,20 +163,20 @@ static void test_redraw(void) /* PBM_SETPOS */ ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n"); ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n"); - + /* PBM_DELTAPOS */ ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n"); ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n"); - + /* PBM_SETPOS */ ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n"); ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n"); - + /* 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"); - + /* PBM_SETRANGE and PBM_SETRANGE32: Usually the progress bar doesn't repaint itself immediately. If the position is not in the new range, it does. @@ -175,7 +191,7 @@ static void test_redraw(void) SendMessage(hProgressWnd, PBM_SETPOS, 10, 0); GetClientRect(hProgressWnd, &client_rect); ok(EqualRect(&last_paint_rect, &client_rect), - "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n", + "last_paint_rect was { %d, %d, %d, %d } instead of { %d, %d, %d, %d }\n", last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom, client_rect.left, client_rect.top, client_rect.right, client_rect.bottom); update_window(hProgressWnd); @@ -187,7 +203,7 @@ static void test_redraw(void) SendMessage(hProgressWnd, PBM_SETPOS, 0, 0); GetClientRect(hProgressWnd, &client_rect); ok(EqualRect(&last_paint_rect, &client_rect), - "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n", + "last_paint_rect was { %d, %d, %d, %d } instead of { %d, %d, %d, %d }\n", last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom, client_rect.left, client_rect.top, client_rect.right, client_rect.bottom); update_window(hProgressWnd); @@ -198,8 +214,8 @@ static void test_redraw(void) START_TEST(progress) { init(); - + test_redraw(); - + cleanup(); } diff --git a/rostests/winetests/comctl32/propsheet.c b/rostests/winetests/comctl32/propsheet.c index cbf6812fc29..8627351b7fc 100644 --- a/rostests/winetests/comctl32/propsheet.c +++ b/rostests/winetests/comctl32/propsheet.c @@ -17,9 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - #include #include @@ -39,7 +36,7 @@ static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) } return 0; } - + static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -81,8 +78,39 @@ static void test_title(void) psp.dwSize = sizeof(psp); psp.dwFlags = 0; psp.hInstance = GetModuleHandleW(NULL); - psp.u.pszTemplate = "prop_page1"; - psp.u2.pszIcon = 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); + DestroyWindow(hdlg); +} + +static void test_nopage(void) +{ + HPROPSHEETPAGE hpsp[1]; + PROPSHEETPAGEA psp; + PROPSHEETHEADERA psh; + HWND hdlg; + + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.dwFlags = 0; + psp.hInstance = GetModuleHandleW(NULL); + U(psp).pszTemplate = "prop_page1"; + U2(psp).pszIcon = NULL; psp.pfnDlgProc = page_dlg_proc; psp.lParam = 0; @@ -94,14 +122,18 @@ static void test_title(void) psh.pszCaption = "test caption"; psh.nPages = 1; psh.hwndParent = GetDesktopWindow(); - psh.u3.phpage = hpsp; + U3(psh).phpage = hpsp; psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + ShowWindow(hdlg,SW_NORMAL); + SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0); + RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); DestroyWindow(hdlg); } START_TEST(propsheet) { test_title(); + test_nopage(); } diff --git a/rostests/winetests/comctl32/rebar.c b/rostests/winetests/comctl32/rebar.c new file mode 100644 index 00000000000..79da16ee9d2 --- /dev/null +++ b/rostests/winetests/comctl32/rebar.c @@ -0,0 +1,831 @@ +/* Unit tests for rebar. + * + * Copyright 2007 Mikolaj Zalewski + * + * 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 +#include + +#include +#include +#include + +#include "wine/test.h" + +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 && \ + val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \ + val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); + +#define check_rect_no_top(name, val, exp) { \ + ok((val.bottom - val.top == exp.bottom - exp.top) && \ + val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d), ignoring top\n", \ + val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); \ + } + +#define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp)); + +#define expect_eq(expr, value, type, format) { type ret = expr; ok((value) == ret, #expr " expected " format " got " format "\n", (value), (ret)); } + +static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam) +{ + return 0; +} + +static BOOL is_font_installed(const char *name) +{ + HDC hdc = GetDC(0); + BOOL ret = FALSE; + + if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0)) + ret = TRUE; + + ReleaseDC(0, hdc); + return ret; +} + +static void rebuild_rebar(HWND *hRebar) +{ + if (*hRebar) + DestroyWindow(*hRebar); + + *hRebar = 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); +} + +static HWND build_toolbar(int nr, HWND hParent) +{ + TBBUTTON btns[8]; + HWND hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE, 0, 0, 0, 0, + hParent, (HMENU)5, GetModuleHandle(NULL), NULL); + int iBitmapId = 0; + 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_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); + ok(SendMessage(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n"); + + for (i=0; i<5+nr; i++) + { + btns[i].iBitmap = i; + btns[i].idCommand = i; + btns[i].fsStyle = BTNS_BUTTON; + btns[i].fsState = TBSTATE_ENABLED; + btns[i].iString = 0; + } + + switch (nr) + { + case 0: iBitmapId = IDB_HIST_SMALL_COLOR; break; + 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_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n"); + return hToolbar; +} + +static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_NOTIFY: + { + NMHDR *lpnm = (NMHDR *)lParam; + if (lpnm->code == RBN_HEIGHTCHANGE) + GetClientRect(hRebar, &height_change_notify_rect); + } + break; + } + return DefWindowProcA(hWnd, msg, wParam, lParam); +} + +#if 0 /* use this to generate more tests*/ + +static void dump_sizes(HWND hRebar) +{ + SIZE sz; + RECT r; + int count; + int i, h; + + GetClientRect(hRebar, &r); + count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0); + printf(" { {%d, %d, %d, %d}, %d, %d, {", r.left, r.top, r.right, r.bottom, + SendMessageA(hRebar, RB_GETBARHEIGHT, 0, 0), count); + if (count == 0) + printf("0, "); + for (i = 0; i < count; i++) /* rows */ + printf("%d, ", SendMessageA(hRebar, RB_GETROWHEIGHT, i, 0)); + printf("}, "); + + count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0); + printf("%d, {", count); + if (count == 0) + printf("{{0, 0, 0, 0}, 0, 0},"); + for (i=0; ircClient); \ + count = SendMessage(hRebar, RB_GETROWCOUNT, 0, 0); \ + compare(count, res->nRows, "%d"); \ + for (i=0; inRows); i++) { \ + int height = SendMessageA(hRebar, RB_GETROWHEIGHT, 0, 0);\ + ok(height == res->cyRowHeights[i], "Height mismatch for row %d - %d vs %d\n", i, res->cyRowHeights[i], height); \ + } \ + count = SendMessage(hRebar, RB_GETBANDCOUNT, 0, 0); \ + compare(count, res->nBands, "%d"); \ + for (i=0; inBands); i++) { \ + ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_ITEMRECT\n"); \ + if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \ + check_rect("band", rc, res->bands[i].rc); \ + rbi.cbSize = sizeof(REBARBANDINFO); \ + 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"); \ + compare(rbi.cx, res->bands[i].cx, "%d"); \ + } \ + rbsize_numtests++; \ + } + +#define check_sizes() check_sizes_todo(0) + +#endif + +static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal) +{ + CHAR buffer[MAX_PATH]; + REBARBANDINFO rbi; + + if (lpszText != NULL) + strcpy(buffer, lpszText); + rbi.cbSize = sizeof(rbi); + rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT; + rbi.cx = cx; + rbi.cxMinChild = cxMinChild; + rbi.cxIdeal = cxIdeal; + rbi.cyMinChild = 20; + rbi.hwndChild = build_toolbar(1, hRebar); + rbi.lpText = (lpszText ? buffer : NULL); + SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); +} + +static void layout_test(void) +{ + HWND hRebar = NULL; + REBARBANDINFO rbi; + + rebuild_rebar(&hRebar); + check_sizes(); + rbi.cbSize = sizeof(rbi); + rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD; + rbi.cx = 200; + rbi.cxMinChild = 100; + rbi.cyMinChild = 30; + rbi.hwndChild = NULL; + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + rbi.fMask |= RBBIM_STYLE; + rbi.fStyle = RBBS_CHILDEDGE; + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + rbi.fStyle = 0; + rbi.cx = 200; + rbi.cxMinChild = 30; + rbi.cyMinChild = 30; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + rbi.fStyle = RBBS_CHILDEDGE; + rbi.cx = 68; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_BANDBORDERS); + check_sizes(); /* a style change won't start a relayout */ + rbi.fMask = RBBIM_SIZE; + rbi.cx = 66; + SendMessageA(hRebar, RB_SETBANDINFO, 3, (LPARAM)&rbi); + check_sizes(); /* here it will be relayouted */ + + /* this will force a new row */ + rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD; + rbi.cx = 200; + rbi.cxMinChild = 400; + rbi.cyMinChild = 30; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, 1, (LPARAM)&rbi); + check_sizes(); + + rbi.fMask = RBBIM_STYLE; + rbi.fStyle = RBBS_HIDDEN; + SendMessageA(hRebar, RB_SETBANDINFO, 2, (LPARAM)&rbi); + check_sizes(); + + SendMessageA(hRebar, RB_DELETEBAND, 2, 0); + check_sizes(); + SendMessageA(hRebar, RB_DELETEBAND, 0, 0); + check_sizes(); + SendMessageA(hRebar, RB_DELETEBAND, 1, 0); + check_sizes(); + + rebuild_rebar(&hRebar); + add_band_w(hRebar, "ABC", 70, 40, 100); + add_band_w(hRebar, NULL, 40, 70, 100); + add_band_w(hRebar, NULL, 170, 240, 100); + add_band_w(hRebar, "MMMMMMM", 60, 60, 100); + add_band_w(hRebar, NULL, 200, 200, 100); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 2, FALSE); + check_sizes(); + SendMessageA(hRebar, RB_MINIMIZEBAND, 2, 0); + check_sizes(); + SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 0); + check_sizes(); + + /* VARHEIGHT resizing test on a horizontal rebar */ + rebuild_rebar(&hRebar); + SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE); + check_sizes(); + rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE; + rbi.fStyle = RBBS_VARIABLEHEIGHT; + rbi.cxMinChild = 50; + rbi.cyMinChild = 10; + rbi.cyIntegral = 11; + rbi.cyChild = 70; + rbi.cyMaxChild = 200; + rbi.cx = 90; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + + rbi.cyChild = 50; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + + rbi.cyMinChild = 40; + rbi.cyChild = 50; + rbi.cyIntegral = 5; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + /* VARHEIGHT resizing on a vertical rebar */ + rebuild_rebar(&hRebar); + SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE); + check_sizes(); + rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE; + rbi.fStyle = RBBS_VARIABLEHEIGHT; + rbi.cxMinChild = 50; + rbi.cyMinChild = 10; + rbi.cyIntegral = 11; + rbi.cyChild = 70; + rbi.cyMaxChild = 90; + rbi.cx = 90; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + rbi.cyChild = 50; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + rbi.cyMinChild = 40; + rbi.cyChild = 50; + rbi.cyIntegral = 5; + rbi.hwndChild = build_toolbar(0, hRebar); + SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); + check_sizes(); + + DestroyWindow(hRebar); +} + +#if 0 /* use this to generate more tests */ + +static void dump_client(HWND hRebar) +{ + RECT r; + BOOL notify; + GetWindowRect(hRebar, &r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + if (height_change_notify_rect.top != -1) + { + RECT rcClient; + GetClientRect(hRebar, &rcClient); + assert(EqualRect(&rcClient, &height_change_notify_rect)); + notify = TRUE; + } + else + notify = FALSE; + printf(" {{%d, %d, %d, %d}, %d, %s},\n", r.left, r.top, r.right, r.bottom, SendMessage(hRebar, RB_GETROWCOUNT, 0, 0), + notify ? "TRUE" : "FALSE"); + SetRect(&height_change_notify_rect, -1, -1, -1, -1); +} + +#define comment(fmt, arg1) printf("/* " fmt " */\n", arg1); +#define check_client() dump_client(hRebar) + +#else + +typedef struct { + RECT rc; + INT iNumRows; + BOOL heightNotify; +} rbresize_test_result_t; + +rbresize_test_result_t resize_results[] = { +/* style 00000001 */ + {{0, 2, 672, 2}, 0, FALSE}, + {{0, 2, 672, 22}, 1, TRUE}, + {{0, 2, 672, 22}, 1, FALSE}, + {{0, 2, 672, 22}, 1, FALSE}, + {{0, 2, 672, 22}, 1, FALSE}, + {{0, 2, 672, 22}, 0, FALSE}, +/* style 00000041 */ + {{0, 0, 672, 0}, 0, FALSE}, + {{0, 0, 672, 20}, 1, TRUE}, + {{0, 0, 672, 20}, 1, FALSE}, + {{0, 0, 672, 20}, 1, FALSE}, + {{0, 0, 672, 20}, 1, FALSE}, + {{0, 0, 672, 20}, 0, FALSE}, +/* style 00000003 */ + {{0, 226, 672, 226}, 0, FALSE}, + {{0, 206, 672, 226}, 1, TRUE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 0, FALSE}, +/* style 00000043 */ + {{0, 226, 672, 226}, 0, FALSE}, + {{0, 206, 672, 226}, 1, TRUE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 1, FALSE}, + {{0, 206, 672, 226}, 0, FALSE}, +/* style 00000080 */ + {{2, 0, 2, 226}, 0, FALSE}, + {{2, 0, 22, 226}, 1, TRUE}, + {{2, 0, 22, 226}, 1, FALSE}, + {{2, 0, 22, 226}, 1, FALSE}, + {{2, 0, 22, 226}, 1, FALSE}, + {{2, 0, 22, 226}, 0, FALSE}, +/* style 00000083 */ + {{672, 0, 672, 226}, 0, FALSE}, + {{652, 0, 672, 226}, 1, TRUE}, + {{652, 0, 672, 226}, 1, FALSE}, + {{652, 0, 672, 226}, 1, FALSE}, + {{652, 0, 672, 226}, 1, FALSE}, + {{652, 0, 672, 226}, 0, FALSE}, +/* style 00000008 */ + {{10, 11, 510, 11}, 0, FALSE}, + {{10, 15, 510, 35}, 1, TRUE}, + {{10, 17, 510, 37}, 1, FALSE}, + {{10, 14, 110, 54}, 2, TRUE}, + {{0, 4, 0, 44}, 2, FALSE}, + {{0, 6, 0, 46}, 2, FALSE}, + {{0, 8, 0, 48}, 2, FALSE}, + {{0, 12, 0, 32}, 1, TRUE}, + {{0, 4, 100, 24}, 0, FALSE}, +/* style 00000048 */ + {{10, 5, 510, 5}, 0, FALSE}, + {{10, 5, 510, 25}, 1, TRUE}, + {{10, 5, 510, 25}, 1, FALSE}, + {{10, 10, 110, 50}, 2, TRUE}, + {{0, 0, 0, 40}, 2, FALSE}, + {{0, 0, 0, 40}, 2, FALSE}, + {{0, 0, 0, 40}, 2, FALSE}, + {{0, 0, 0, 20}, 1, TRUE}, + {{0, 0, 100, 20}, 0, FALSE}, +/* style 00000004 */ + {{10, 5, 510, 20}, 0, FALSE}, + {{10, 5, 510, 20}, 1, TRUE}, + {{10, 10, 110, 110}, 2, TRUE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 1, TRUE}, + {{0, 0, 100, 100}, 0, FALSE}, +/* style 00000002 */ + {{0, 5, 672, 5}, 0, FALSE}, + {{0, 5, 672, 25}, 1, TRUE}, + {{0, 10, 672, 30}, 1, FALSE}, + {{0, 0, 672, 20}, 1, FALSE}, + {{0, 0, 672, 20}, 1, FALSE}, + {{0, 0, 672, 20}, 0, FALSE}, +/* style 00000082 */ + {{10, 0, 10, 226}, 0, FALSE}, + {{10, 0, 30, 226}, 1, TRUE}, + {{10, 0, 30, 226}, 1, FALSE}, + {{0, 0, 20, 226}, 1, FALSE}, + {{0, 0, 20, 226}, 1, FALSE}, + {{0, 0, 20, 226}, 0, FALSE}, +/* style 00800001 */ + {{-2, 0, 674, 4}, 0, FALSE}, + {{-2, 0, 674, 24}, 1, TRUE}, + {{-2, 0, 674, 24}, 1, FALSE}, + {{-2, 0, 674, 24}, 1, FALSE}, + {{-2, 0, 674, 24}, 1, FALSE}, + {{-2, 0, 674, 24}, 0, FALSE}, +/* style 00800048 */ + {{10, 5, 510, 9}, 0, FALSE}, + {{10, 5, 510, 29}, 1, TRUE}, + {{10, 5, 510, 29}, 1, FALSE}, + {{10, 10, 110, 54}, 2, TRUE}, + {{0, 0, 0, 44}, 2, FALSE}, + {{0, 0, 0, 44}, 2, FALSE}, + {{0, 0, 0, 44}, 2, FALSE}, + {{0, 0, 0, 24}, 1, TRUE}, + {{0, 0, 100, 24}, 0, FALSE}, +/* style 00800004 */ + {{10, 5, 510, 20}, 0, FALSE}, + {{10, 5, 510, 20}, 1, TRUE}, + {{10, 10, 110, 110}, 2, TRUE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 2, FALSE}, + {{0, 0, 0, 0}, 1, TRUE}, + {{0, 0, 100, 100}, 0, FALSE}, +/* style 00800002 */ + {{-2, 5, 674, 9}, 0, FALSE}, + {{-2, 5, 674, 29}, 1, TRUE}, + {{-2, 10, 674, 34}, 1, FALSE}, + {{-2, 0, 674, 24}, 1, FALSE}, + {{-2, 0, 674, 24}, 1, FALSE}, + {{-2, 0, 674, 24}, 0, FALSE}, +}; + +static int resize_numtests = 0; + +#define comment(fmt, arg1) +#define check_client() { \ + RECT r; \ + rbresize_test_result_t *res = &resize_results[resize_numtests++]; \ + assert(resize_numtests <= sizeof(resize_results)/sizeof(resize_results[0])); \ + GetWindowRect(hRebar, &r); \ + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); \ + if ((dwStyles[i] & (CCS_NOPARENTALIGN|CCS_NODIVIDER)) == CCS_NOPARENTALIGN) {\ + check_rect_no_top("client", r, res->rc); /* the top coordinate changes after every layout and is very implementation-dependent */ \ + } else { \ + check_rect("client", r, res->rc); \ + } \ + expect_eq((int)SendMessage(hRebar, RB_GETROWCOUNT, 0, 0), res->iNumRows, int, "%d"); \ + if (res->heightNotify) { \ + RECT rcClient; \ + GetClientRect(hRebar, &rcClient); \ + check_rect("notify", height_change_notify_rect, rcClient); \ + } else ok(height_change_notify_rect.top == -1, "Unexpected RBN_HEIGHTCHANGE received\n"); \ + SetRect(&height_change_notify_rect, -1, -1, -1, -1); \ + } + +#endif + +static void resize_test(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, + CCS_TOP | WS_BORDER, CCS_NOPARENTALIGN | CCS_NODIVIDER | WS_BORDER, CCS_NORESIZE | WS_BORDER, + CCS_NOMOVEY | WS_BORDER}; + + const int styles_count = sizeof(dwStyles) / sizeof(dwStyles[0]); + int i; + + for (i = 0; i < styles_count; i++) + { + 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); + check_client(); + add_band_w(hRebar, NULL, 70, 100, 0); + if (dwStyles[i] & CCS_NOPARENTALIGN) /* the window drifts downward for CCS_NOPARENTALIGN without CCS_NODIVIDER */ + check_client(); + add_band_w(hRebar, NULL, 70, 100, 0); + check_client(); + MoveWindow(hRebar, 10, 10, 100, 100, TRUE); + check_client(); + MoveWindow(hRebar, 0, 0, 0, 0, TRUE); + check_client(); + /* try to fool the rebar by sending invalid width/height - won't work */ + if (dwStyles[i] & (CCS_NORESIZE | CCS_NOPARENTALIGN)) + { + WINDOWPOS pos; + pos.hwnd = hRebar; + pos.hwndInsertAfter = NULL; + pos.cx = 500; + pos.cy = 500; + pos.x = 10; + pos.y = 10; + pos.flags = 0; + SendMessage(hRebar, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pos); + SendMessage(hRebar, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pos); + check_client(); + SendMessage(hRebar, WM_SIZE, SIZE_RESTORED, MAKELONG(500, 500)); + check_client(); + } + SendMessage(hRebar, RB_DELETEBAND, 0, 0); + check_client(); + SendMessage(hRebar, RB_DELETEBAND, 0, 0); + MoveWindow(hRebar, 0, 0, 100, 100, TRUE); + check_client(); + DestroyWindow(hRebar); + } +} + +static void expect_band_content(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) +{ + CHAR buf[MAX_PATH] = "abc"; + REBARBANDINFO rb; + + memset(&rb, 0xdd, sizeof(rb)); + rb.cbSize = sizeof(rb); + 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; + rb.lpText = buf; + 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(strcmp(rb.lpText, lpText), 0, int, "%d"); + expect_eq(rb.iImage, iImage, int, "%x"); + expect_eq(rb.hwndChild, hwndChild, HWND, "%p"); + expect_eq(rb.cxMinChild, cxMinChild, int, "%d"); + expect_eq(rb.cyMinChild, cyMinChild, int, "%d"); + expect_eq(rb.cx, cx, int, "%d"); + expect_eq(rb.hbmBack, hbmBack, HBITMAP, "%p"); + expect_eq(rb.wID, wID, int, "%d"); + /* the values of cyChild, cyMaxChild and cyIntegral can't be read unless the band is RBBS_VARIABLEHEIGHT */ + expect_eq(rb.cyChild, cyChild, int, "%x"); + expect_eq(rb.cyMaxChild, cyMaxChild, int, "%x"); + 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"); +} + +static void bandinfo_test(void) +{ + REBARBANDINFOA rb; + CHAR szABC[] = "ABC"; + CHAR szABCD[] = "ABCD"; + + rebuild_rebar(&hRebar); + rb.cbSize = sizeof(REBARBANDINFO); + 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); + + rb.fMask = RBBIM_CHILDSIZE; + rb.cxMinChild = 15; + rb.cyMinChild = 20; + 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); + + 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); + + rb.cbSize = sizeof(REBARBANDINFO); + 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); + + 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); + + 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); + + 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); + 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); + + DestroyWindow(hRebar); +} + +START_TEST(rebar) +{ + INITCOMMONCONTROLSEX icc; + WNDCLASSA wc; + MSG msg; + RECT rc; + + icc.dwSize = sizeof(icc); + icc.dwICC = ICC_COOL_CLASSES; + InitCommonControlsEx(&icc); + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandleA(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, IDC_IBEAM); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MyTestWnd"; + wc.lpfnWndProc = MyWndProc; + RegisterClassA(&wc); + hMainWnd = 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(); + + if(is_font_installed("System") && is_font_installed("Tahoma")) + { + layout_test(); + resize_test(); + } else + skip("Missing System or Tahoma font\n"); + + PostQuitMessage(0); + while(GetMessageA(&msg,0,0,0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + DestroyWindow(hMainWnd); +} diff --git a/rostests/winetests/comctl32/resources.h b/rostests/winetests/comctl32/resources.h new file mode 100644 index 00000000000..c99633d342d --- /dev/null +++ b/rostests/winetests/comctl32/resources.h @@ -0,0 +1,34 @@ +/* + * Resource IDs + * + * Copyright 2006 Mikolaj Zalewski + * + * 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 + */ + +#ifndef __WINE_COMCTL32_TEST_RESOURCES_H +#define __WINE_COMCTL32_TEST_RESOURCES_H + +#define IDB_BITMAP_128x15 10 +#define IDB_BITMAP_80x15 11 + +#define IDS_TBADD1 16 +#define IDS_TBADD2 17 +#define IDS_TBADD3 18 +#define IDS_TBADD4 19 +#define IDS_TBADD5 20 +#define IDS_TBADD7 22 + +#endif /* __WINE_COMCTL32_TEST_RESOURCES_H */ diff --git a/rostests/winetests/comctl32/propsheet.rc b/rostests/winetests/comctl32/rsrc.rc similarity index 68% rename from rostests/winetests/comctl32/propsheet.rc rename to rostests/winetests/comctl32/rsrc.rc index 2296141f706..bf195b661d1 100644 --- a/rostests/winetests/comctl32/propsheet.rc +++ b/rostests/winetests/comctl32/rsrc.rc @@ -1,6 +1,7 @@ -/* Resources for the unit test suite for property sheet control. +/* Resources for the common control unit test suite. * * Copyright 2006 Huw Davies + * Copyright 2006 Mikolaj Zalewski * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +20,7 @@ #include "windef.h" #include "winuser.h" +#include "resources.h" PROP_PAGE1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215 STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE @@ -27,3 +29,19 @@ FONT 8, "MS Shell Dlg" { LTEXT "Test", -1, 10, 6, 100, 8 } + +STRINGTABLE +{ + IDS_TBADD1 "abc" + IDS_TBADD2 "|p|q|r" + IDS_TBADD3 "*p*q*" + IDS_TBADD4 "#p#q##" + IDS_TBADD5 "|p||q|r|" + IDS_TBADD7 "abracadabra" +} + +/* @makedep: bmp128x15.bmp */ +IDB_BITMAP_128x15 BITMAP bmp128x15.bmp + +/* @makedep: bmp80x15.bmp */ +IDB_BITMAP_80x15 BITMAP bmp80x15.bmp diff --git a/rostests/winetests/comctl32/status.c b/rostests/winetests/comctl32/status.c new file mode 100644 index 00000000000..4e643c1f4fa --- /dev/null +++ b/rostests/winetests/comctl32/status.c @@ -0,0 +1,196 @@ +/* Unit test suite for status control. + * + * Copyright 2007 Google (Lei Zhang) + * Copyright 2007 Alex Arazi + * + * 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 +#include +#include + +#include "wine/test.h" + +#define expect(expected,got) ok (expected == got,"Expected %d, got %d\n",expected,got); + +static HINSTANCE hinst; + +static HWND create_status_control(DWORD style, DWORD exstyle) +{ + HWND hWndStatus; + + /* make the control */ + hWndStatus = CreateWindowEx(exstyle, STATUSCLASSNAME, NULL, style, + /* placement */ + 0, 0, 300, 20, + /* parent, etc */ + NULL, NULL, hinst, NULL); + assert (hWndStatus); + return hWndStatus; +} + +static void test_status_control(void) +{ + HWND hWndStatus; + int r; + int nParts[] = {50, 150, -1}; + int checkParts[] = {0, 0, 0}; + int borders[] = {0, 0, 0}; + RECT rc; + CHAR charArray[20]; + HICON hIcon; + + hWndStatus = create_status_control(WS_VISIBLE, 0); + + /* Divide into parts and set text */ + r = SendMessage(hWndStatus, SB_SETPARTS, 3, (long)nParts); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First"); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"Second"); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"Third"); + expect(TRUE,r); + + /* Get RECT Information */ + r = SendMessage(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc); + expect(TRUE,r); + expect(2,rc.top); + /* The rc.bottom test is system dependent + expect(22,rc.bottom); */ + expect(0,rc.left); + expect(50,rc.right); + r = SendMessage(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc); + expect(FALSE,r); + r = SendMessage(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc); + expect(FALSE,r); + /* Get text length and text */ + r = SendMessage(hWndStatus, SB_GETTEXTLENGTH, 2, 0); + expect(5,LOWORD(r)); + expect(0,HIWORD(r)); + r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray); + ok(strcmp(charArray,"Third") == 0, "Expected Third, got %s\n", charArray); + expect(5,LOWORD(r)); + expect(0,HIWORD(r)); + + /* Get parts and borders */ + r = SendMessage(hWndStatus, SB_GETPARTS, 3, (long)checkParts); + ok(r == 3, "Expected 3, got %d\n", r); + expect(50,checkParts[0]); + expect(150,checkParts[1]); + expect(-1,checkParts[2]); + r = SendMessage(hWndStatus, SB_GETBORDERS, 0, (long)borders); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + expect(0,borders[0]); + expect(2,borders[1]); + expect(2,borders[2]); + + /* Test resetting text with different characters */ + r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First@Again"); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"InvalidChars\\7\7"); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"InvalidChars\\n\n"); + expect(TRUE,r); + + /* Get text again */ + r = SendMessage(hWndStatus, SB_GETTEXT, 0, (LPARAM) charArray); + ok(strcmp(charArray,"First@Again") == 0, "Expected First@Again, got %s\n", charArray); + expect(11,LOWORD(r)); + expect(0,HIWORD(r)); + r = SendMessage(hWndStatus, SB_GETTEXT, 1, (LPARAM) charArray); + todo_wine + { + ok(strcmp(charArray,"InvalidChars\\7 ") == 0, "Expected InvalidChars\\7 , got %s\n", charArray); + } + expect(15,LOWORD(r)); + expect(0,HIWORD(r)); + r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray); + todo_wine + { + ok(strcmp(charArray,"InvalidChars\\n ") == 0, "Expected InvalidChars\\n , got %s\n", charArray); + } + expect(15,LOWORD(r)); + expect(0,HIWORD(r)); + + /* Set background color */ + r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, RGB(255,0,0)); + expect(CLR_DEFAULT,r); + r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, CLR_DEFAULT); + expect(RGB(255,0,0),r); + + /* Add an icon to the status bar */ + hIcon = LoadIcon(NULL, IDI_QUESTION); + r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL); + ok(r != 0, "Expected non-zero, got %d\n", r); + r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) hIcon); + ok(r != 0, "Expected non-zero, got %d\n", r); + r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL); + ok(r != 0, "Expected non-zero, got %d\n", r); + + /* Set the Unicode format */ + r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, FALSE, 0); + r = SendMessage(hWndStatus, SB_GETUNICODEFORMAT, 0, 0); + expect(FALSE,r); + r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, TRUE, 0); + expect(FALSE,r); + r = SendMessage(hWndStatus, SB_GETUNICODEFORMAT, 0, 0); + expect(TRUE,r); + + /* Reset number of parts */ + r = SendMessage(hWndStatus, SB_SETPARTS, 2, (long)nParts); + expect(TRUE,r); + + /* Set the minimum height and get rectangle information again */ + SendMessage(hWndStatus, SB_SETMINHEIGHT, 50, (LPARAM) 0); + r = SendMessage(hWndStatus, WM_SIZE, 0, (LPARAM) 0); + expect(0,r); + r = SendMessage(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc); + expect(TRUE,r); + expect(2,rc.top); + /* The rc.bottom test is system dependent + expect(22,rc.bottom); */ + expect(0,rc.left); + expect(50,rc.right); + r = SendMessage(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc); + expect(FALSE,r); + r = SendMessage(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc); + expect(FALSE,r); + + /* Set the ToolTip text */ + todo_wine + { + SendMessage(hWndStatus, SB_SETTIPTEXT, 0,(LPARAM) "Tooltip Text"); + SendMessage(hWndStatus, SB_GETTIPTEXT, MAKEWPARAM (0, 20),(LPARAM) charArray); + ok(strcmp(charArray,"Tooltip Text") == 0, "Expected Tooltip Text, got %s\n", charArray); + } + + /* Make simple */ + SendMessage(hWndStatus, SB_SIMPLE, TRUE, 0); + r = SendMessage(hWndStatus, SB_ISSIMPLE, 0, 0); + expect(TRUE,r); + + DestroyWindow(hWndStatus); +} + +START_TEST(status) +{ + hinst = GetModuleHandleA(NULL); + + InitCommonControls(); + + test_status_control(); +} diff --git a/rostests/winetests/comctl32/subclass.c b/rostests/winetests/comctl32/subclass.c index 937ec1bf7df..9c879e30395 100644 --- a/rostests/winetests/comctl32/subclass.c +++ b/rostests/winetests/comctl32/subclass.c @@ -156,7 +156,7 @@ static void ok_sequence(const struct message *expected, const char *context) "%s: the procnum %d was expected, but got procnum %d instead\n", context, expected->procnum, actual->procnum); ok(expected->wParam == actual->wParam, - "%s: in procnum %d expecting wParam 0x%x got 0x%x\n", + "%s: in procnum %d expecting wParam 0x%lx got 0x%lx\n", context, expected->procnum, expected->wParam, actual->wParam); expected++; actual++; @@ -169,7 +169,7 @@ static void ok_sequence(const struct message *expected, const char *context) static LRESULT WINAPI WndProc1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct message msg; - + if(message == WM_USER) { msg.wParam = wParam; msg.procnum = 1; @@ -183,7 +183,7 @@ static WNDPROC origProc3; static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct message msg; - + if(message == WM_USER) { msg.wParam = wParam; msg.procnum = 3; @@ -195,12 +195,12 @@ static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lP static LRESULT WINAPI WndProcSub(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uldSubclass, DWORD_PTR dwRefData) { struct message msg; - + if(message == WM_USER) { msg.wParam = wParam; msg.procnum = uldSubclass; add_message(&msg); - + if(lParam) { if(dwRefData & DELETE_SELF) { pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass); @@ -275,20 +275,23 @@ static BOOL RegisterWindowClasses(void) cls.lpszMenuName = NULL; cls.lpszClassName = "TestSubclass"; if(!RegisterClassA(&cls)) return FALSE; - + return TRUE; } START_TEST(subclass) { HMODULE hdll; - + hdll = GetModuleHandleA("comctl32.dll"); assert(hdll); - pSetWindowSubclass = (void*)GetProcAddress(hdll, "SetWindowSubclass"); - pRemoveWindowSubclass = (void*)GetProcAddress(hdll, "RemoveWindowSubclass"); - pDefSubclassProc = (void*)GetProcAddress(hdll, "DefSubclassProc"); - + /* 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); + if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc) return; diff --git a/rostests/winetests/comctl32/tab.c b/rostests/winetests/comctl32/tab.c index d5901c09eda..94893767452 100644 --- a/rostests/winetests/comctl32/tab.c +++ b/rostests/winetests/comctl32/tab.c @@ -1,6 +1,7 @@ /* Unit test suite for tab control. * * Copyright 2003 Vitaliy Margolen + * Copyright 2007 Hagop Hagopian * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,13 +21,24 @@ #include #include #include +#include #include "wine/test.h" +#include "msg.h" #define DEFAULT_MIN_TAB_WIDTH 54 #define TAB_DEFAULT_WIDTH 96 #define TAB_PADDING_X 6 #define EXTRA_ICON_PADDING 3 +#define MAX_TABLEN 32 + +#define NUM_MSG_SEQUENCES 2 +#define PARENT_SEQ_INDEX 0 +#define TAB_SEQ_INDEX 1 + +#define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got) +#define expect_str(expected, got)\ + ok ( strcmp(expected, got) == 0, "Expected '%s', got '%s'\n", expected, got) #define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num) @@ -39,19 +51,222 @@ #define CheckSize(hwnd,width,height,msg)\ SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);\ if ((width >= 0) && (height < 0))\ - ok (width == rTab.right - rTab.left, "%s: Expected width [%d] got [%ld]\n",\ + ok (width == rTab.right - rTab.left, "%s: Expected width [%d] got [%d]\n",\ msg, (int)width, rTab.right - rTab.left);\ else if ((height >= 0) && (width < 0))\ - ok (height == rTab.bottom - rTab.top, "%s: Expected height [%d] got [%ld]\n",\ + ok (height == rTab.bottom - rTab.top, "%s: Expected height [%d] got [%d]\n",\ msg, (int)height, rTab.bottom - rTab.top);\ else\ ok ((width == rTab.right - rTab.left) &&\ (height == rTab.bottom - rTab.top ),\ - "%s: Expected [%d,%d] got [%ld,%ld]\n", msg, (int)width, (int)height,\ + "%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\ rTab.right - rTab.left, rTab.bottom - rTab.top); static HFONT hFont = 0; +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_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}, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, + { WM_SIZE, sent }, + { WM_MOVE, sent }, + { 0 } +}; + +static const struct message add_tab_to_parent[] = { + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { WM_NOTIFYFORMAT, sent|defwinproc }, + { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_PARENTNOTIFY, sent|defwinproc }, + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { 0 } +}; + +static const struct message add_tab_to_parent_interactive[] = { + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { WM_NOTIFYFORMAT, sent|defwinproc }, + { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_PARENTNOTIFY, sent|defwinproc }, + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { TCM_INSERTITEMA, sent }, + { WM_SHOWWINDOW, sent}, + { WM_WINDOWPOSCHANGING, sent}, + { WM_WINDOWPOSCHANGING, sent}, + { WM_NCACTIVATE, sent}, + { WM_ACTIVATE, sent}, + { WM_IME_SETCONTEXT, sent|defwinproc|optional}, + { WM_IME_NOTIFY, sent|defwinproc|optional}, + { WM_SETFOCUS, sent|defwinproc}, + { WM_WINDOWPOSCHANGED, sent}, + { WM_SIZE, sent}, + { WM_MOVE, sent}, + { 0 } +}; + +static const struct message add_tab_control_parent_seq[] = { + { WM_NOTIFYFORMAT, sent }, + { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message add_tab_control_parent_seq_interactive[] = { + { WM_NOTIFYFORMAT, sent }, + { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|optional}, + { WM_NCACTIVATE, sent}, + { WM_ACTIVATE, sent}, + { WM_WINDOWPOSCHANGING, sent|optional}, + { WM_KILLFOCUS, sent}, + { WM_IME_SETCONTEXT, sent|optional}, + { WM_IME_NOTIFY, sent|optional}, + { 0 } +}; + +static const struct message empty_sequence[] = { + { 0 } +}; + +static const struct message set_min_tab_width_seq[] = { + { TCM_SETMINTABWIDTH, sent|wparam, 0 }, + { TCM_SETMINTABWIDTH, sent|wparam, 0 }, + { 0 } +}; + +static const struct message get_item_count_seq[] = { + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message get_row_count_seq[] = { + { TCM_GETROWCOUNT, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message get_item_rect_seq[] = { + { TCM_GETITEMRECT, sent }, + { TCM_GETITEMRECT, sent }, + { 0 } +}; + +static const struct message getset_cur_focus_seq[] = { + { TCM_SETCURFOCUS, sent|lparam, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURFOCUS, sent|lparam, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURSEL, sent|lparam, 0 }, + { TCM_SETCURFOCUS, sent|lparam, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message getset_cur_sel_seq[] = { + { TCM_SETCURSEL, sent|lparam, 0 }, + { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURSEL, sent|lparam, 0 }, + { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURSEL, sent|lparam, 0 }, + { TCM_SETCURSEL, sent|lparam, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message getset_extended_style_seq[] = { + { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 }, + { TCM_SETEXTENDEDSTYLE, sent }, + { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 }, + { TCM_SETEXTENDEDSTYLE, sent }, + { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message getset_unicode_format_seq[] = { + { CCM_SETUNICODEFORMAT, sent|lparam, 0 }, + { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, + { CCM_SETUNICODEFORMAT, sent|lparam, 0 }, + { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 }, + { CCM_SETUNICODEFORMAT, sent|lparam, 0 }, + { 0 } +}; + +static const struct message getset_item_seq[] = { + { TCM_SETITEMA, sent }, + { TCM_GETITEMA, sent }, + { TCM_GETITEMA, sent }, + { 0 } +}; + +static const struct message getset_tooltip_seq[] = { + { WM_NOTIFYFORMAT, sent }, + { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_NOTIFYFORMAT, sent }, + { TCM_SETTOOLTIPS, sent|lparam, 0 }, + { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, + { TCM_SETTOOLTIPS, sent|lparam, 0 }, + { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message getset_tooltip_parent_seq[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { 0 } +}; + +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 }, + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_INSERTITEM, sent|wparam, 2 }, + { WM_NOTIFYFORMAT, sent|defwinproc, }, + { WM_QUERYUISTATE, sent|defwinproc, }, + { WM_PARENTNOTIFY, sent|defwinproc, }, + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_INSERTITEM, sent|wparam, 3 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message delete_focus_seq[] = { + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_DELETEITEM, sent|wparam|lparam, 1, 0 }, + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { TCM_DELETEITEM, sent|wparam|lparam, 0, 0 }, + { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, + { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, + { 0 } +}; + + static HWND create_tabcontrol (DWORD style, DWORD mask) { @@ -94,6 +309,195 @@ create_tabcontrol (DWORD style, DWORD mask) return handle; } +static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static BOOL registerParentWindowClass(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = parentWindowProcess; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Tab test parent class"; + return RegisterClassA(&cls); +} + +static HWND createParentWindow(void) +{ + if (!registerParentWindowClass()) + return NULL; + + return CreateWindowEx(0, "Tab test parent class", + "Tab test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + 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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + trace("tab: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, TAB_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs) +{ + HWND tabHandle; + TCITEM tcNewTab; + struct subclass_info *info; + RECT rect; + INT i; + + info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); + if (!info) + return NULL; + + GetClientRect(parent_wnd, &rect); + + tabHandle = CreateWindow ( + WC_TABCONTROLA, + "TestTab", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style, + 0, 0, rect.right, rect.bottom, + parent_wnd, NULL, NULL, 0); + + assert(tabHandle); + + info->oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess); + SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)info); + + tcNewTab.mask = mask; + + for (i = 0; i < nTabs; i++) + { + char tabName[MAX_TABLEN]; + + sprintf(tabName, "Tab %d", i+1); + tcNewTab.pszText = tabName; + tcNewTab.iImage = i; + SendMessage (tabHandle, TCM_INSERTITEM, i, (LPARAM) &tcNewTab); + } + + if (winetest_interactive) + { + ShowWindow (tabHandle, SW_SHOW); + RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW); + Sleep (1000); + } + + return tabHandle; +} + +static HWND create_tooltip (HWND hTab, char toolTipText[]) +{ + HWND hwndTT; + + TOOLINFO ti; + LPTSTR lptstr = toolTipText; + RECT rect; + + /* Creating a tooltip window*/ + hwndTT = CreateWindowEx( + WS_EX_TOPMOST, + TOOLTIPS_CLASS, + NULL, + WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hTab, NULL, 0, NULL); + + SetWindowPos( + hwndTT, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + GetClientRect (hTab, &rect); + + /* Initialize members of toolinfo*/ + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_SUBCLASS; + ti.hwnd = hTab; + ti.hinst = 0; + ti.uId = 0; + ti.lpszText = lptstr; + + ti.rect = rect; + + /* Add toolinfo structure to the tooltip control */ + SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + + return hwndTT; +} + static void test_tab(INT nMinTabWidth) { HWND hwTab; @@ -110,7 +514,7 @@ static void test_tab(INT nMinTabWidth) hdc = GetDC(hwTab); hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0)); GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size); - trace("Tab1 text size: size.cx=%ld size.cy=%ld\n", size.cx, size.cy); + trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy); SelectObject(hdc, hOldFont); ReleaseDC(hwTab, hdc); @@ -223,8 +627,338 @@ static void test_tab(INT nMinTabWidth) DeleteObject(hFont); } +static void test_getters_setters(HWND parent_wnd, INT nTabs) +{ + HWND hTab; + RECT rTab; + INT nTabsRetrieved; + INT rowCount; + + ok(parent_wnd != NULL, "no parent window!\n"); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + if(!winetest_interactive) + ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent, + "Tab sequence, after adding tab control to parent", TRUE); + else + ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent_interactive, + "Tab sequence, after adding tab control to parent", TRUE); + + if(!winetest_interactive) + ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq, + "Parent after sequence, adding tab control to parent", TRUE); + else + ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq_interactive, + "Parent after sequence, adding tab control to parent", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + todo_wine{ + expect(DEFAULT_MIN_TAB_WIDTH, (int)SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1)); + } + ok_sequence(sequences, TAB_SEQ_INDEX, set_min_tab_width_seq, "Set minTabWidth test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE); + + /* Testing GetItemCount */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(nTabs, nTabsRetrieved); + ok_sequence(sequences, TAB_SEQ_INDEX, get_item_count_seq, "Get itemCount test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset itemCount test parent sequence", FALSE); + + /* Testing GetRowCount */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + rowCount = SendMessage(hTab, TCM_GETROWCOUNT, 0, 0); + expect(1, rowCount); + ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE); + + /* Testing GetItemRect */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n"); + CheckSize(hTab, TAB_DEFAULT_WIDTH, -1 , "Default Width"); + 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; + + 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); + } + + /* 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); + todo_wine{ + 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); + } + + /* 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, (LPARAM) NULL, 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_insert_focus(HWND parent_wnd) +{ + HWND hTab; + INT nTabsRetrieved; + INT r; + TCITEM tcNewTab; + DWORD mask = TCIF_TEXT|TCIF_IMAGE; + static char tabName[] = "TAB"; + tcNewTab.mask = mask; + tcNewTab.pszText = tabName; + + ok(parent_wnd != NULL, "no parent window!\n"); + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(0, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(-1, r); + + tcNewTab.iImage = 1; + r = SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab); + expect(0, r); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(1, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(0, r); + + tcNewTab.iImage = 2; + r = SendMessage(hTab, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab); + expect(1, r); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(2, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(0, r); + + r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0); + expect(0, r); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(-1, r); + + tcNewTab.iImage = 3; + r = SendMessage(hTab, TCM_INSERTITEM, 3, (LPARAM) &tcNewTab); + expect(2, r); + + 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); + + DestroyWindow(hTab); +} + +static void test_delete_focus(HWND parent_wnd) +{ + HWND hTab; + INT nTabsRetrieved; + INT r; + + ok(parent_wnd != NULL, "no parent window!\n"); + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(2, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(0, r); + + r = SendMessage(hTab, TCM_DELETEITEM, 1, 0); + expect(1, r); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(1, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(0, r); + + r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0); + expect(0, r); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(-1, r); + + r = SendMessage(hTab, TCM_DELETEITEM, 0, 0); + expect(1, r); + + nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); + expect(0, nTabsRetrieved); + + r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + 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); + + DestroyWindow(hTab); +} + START_TEST(tab) { + HWND parent_wnd; LOGFONTA logfont; lstrcpyA(logfont.lfFaceName, "Arial"); @@ -246,4 +980,17 @@ START_TEST(tab) test_tab(54); trace ("Testing with MinWidth set to 94\n"); test_tab(94); + + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + + 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_insert_focus(parent_wnd); + test_delete_focus(parent_wnd); + + DestroyWindow(parent_wnd); } diff --git a/rostests/winetests/comctl32/testlist.c b/rostests/winetests/comctl32/testlist.c index 179eefda835..be88bef0a74 100644 --- a/rostests/winetests/comctl32/testlist.c +++ b/rostests/winetests/comctl32/testlist.c @@ -1,3 +1,5 @@ +/* Automatically generated file; DO NOT EDIT!! */ + #define WIN32_LEAN_AND_MEAN #include @@ -5,36 +7,48 @@ #include "wine/test.h" extern void func_comboex(void); +extern void func_datetime(void); extern void func_dpa(void); extern void func_header(void); extern void func_imagelist(void); 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); +extern void func_status(void); extern void func_subclass(void); extern void func_tab(void); extern void func_toolbar(void); extern void func_tooltips(void); +extern void func_trackbar(void); extern void func_treeview(void); extern void func_updown(void); const struct test winetest_testlist[] = { { "comboex", func_comboex }, + { "datetime", func_datetime }, { "dpa", func_dpa }, { "header", func_header }, { "imagelist", func_imagelist }, { "listview", func_listview }, + { "misc", func_misc }, { "monthcal", func_monthcal }, { "mru", func_mru }, + { "msg", func_msg }, { "progress", func_progress }, { "propsheet", func_propsheet }, + { "rebar", func_rebar }, + { "status", func_status }, { "subclass", func_subclass }, { "tab", func_tab }, { "toolbar", func_toolbar }, { "tooltips", func_tooltips }, + { "trackbar", func_trackbar }, { "treeview", func_treeview }, { "updown", func_updown }, { 0, 0 } diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c index 1ccc80c26c1..b094a4bfc0d 100644 --- a/rostests/winetests/comctl32/toolbar.c +++ b/rostests/winetests/comctl32/toolbar.c @@ -1,6 +1,7 @@ /* Unit tests for treeview. * * Copyright 2005 Krzysztof Foltman + * Copyright 2007 Mikolaj Zalewski * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,10 +27,25 @@ #include "winuser.h" #include "winnls.h" #include "winreg.h" -#include "commctrl.h" +#include "commctrl.h" + +#include "resources.h" #include "wine/test.h" +static HWND hMainWnd; +static BOOL g_fBlockHotItemChange; +static BOOL g_fReceivedHotItemChange; +static BOOL g_fExpectedHotItemOld; +static BOOL g_fExpectedHotItemNew; +static DWORD g_dwExpectedDispInfoMask; + +#define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \ + val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \ + val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); + +#define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp)); + static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) { p->iBitmap = -2; p->idCommand = idCommand; @@ -38,71 +54,1038 @@ static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) { p->iString = nString; } +static LRESULT MyWnd_Notify(LPARAM lParam) +{ + NMHDR *hdr = (NMHDR *)lParam; + NMTBHOTITEM *nmhi; + NMTBDISPINFO *nmdisp; + switch (hdr->code) + { + case TBN_HOTITEMCHANGE: + nmhi = (NMTBHOTITEM *)lParam; + g_fReceivedHotItemChange = TRUE; + if (g_fExpectedHotItemOld != g_fExpectedHotItemNew) + { + compare(nmhi->idOld, g_fExpectedHotItemOld, "%d"); + compare(nmhi->idNew, g_fExpectedHotItemNew, "%d"); + } + if (g_fBlockHotItemChange) + return 1; + break; + + case TBN_GETDISPINFOA: + ok(FALSE, "TBN_GETDISPINFOA received\n"); + 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) { - switch(msg) { + switch (msg) + { + case WM_NOTIFY: + return MyWnd_Notify(lParam); + } + return DefWindowProcA(hWnd, msg, wParam, lParam); +} + +static void basic_test(void) +{ + TBBUTTON buttons[9]; + HWND hToolbar; + int i; + for (i=0; i<9; i++) + MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0); + MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0); + MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0); + + hToolbar = CreateToolbarEx(hMainWnd, + WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP | + WS_CHILD | TBSTYLE_LIST, + 100, + 0, NULL, (UINT)0, + buttons, sizeof(buttons)/sizeof(buttons[0]), + 0, 0, 20, 16, sizeof(TBBUTTON)); + ok(hToolbar != NULL, "Toolbar creation\n"); + SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000"); + + /* test for exclusion working inside a separator-separated :-) group */ + SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */ + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n"); + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n"); + + SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */ + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n"); + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n"); + + SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */ + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n"); + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n"); + + /* test for inter-group crosstalk, ie. two radio groups interfering with each other */ + SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */ + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n"); + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n"); + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n"); + + SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */ + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n"); + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n"); + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n"); + + SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */ + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n"); + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n"); + ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n"); + ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n"); + + /* tests with invalid index */ + compare(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 0xdeadbeef, 0), -1L, "%ld"); + compare(SendMessage(hToolbar, TB_ISBUTTONPRESSED, 0xdeadbeef, 0), -1L, "%ld"); + compare(SendMessage(hToolbar, TB_ISBUTTONENABLED, 0xdeadbeef, 0), -1L, "%ld"); + compare(SendMessage(hToolbar, TB_ISBUTTONINDETERMINATE, 0xdeadbeef, 0), -1L, "%ld"); + compare(SendMessage(hToolbar, TB_ISBUTTONHIGHLIGHTED, 0xdeadbeef, 0), -1L, "%ld"); + compare(SendMessage(hToolbar, TB_ISBUTTONHIDDEN, 0xdeadbeef, 0), -1L, "%ld"); + + DestroyWindow(hToolbar); +} + +static void rebuild_toolbar(HWND *hToolbar) +{ + if (*hToolbar != NULL) + DestroyWindow(*hToolbar); + *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, + hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL); + 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_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); + ok(SendMessage(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n"); +} + +static void rebuild_toolbar_with_buttons(HWND *hToolbar) +{ + TBBUTTON buttons[5]; + rebuild_toolbar(hToolbar); + + ZeroMemory(&buttons, sizeof(buttons)); + buttons[0].idCommand = 1; + buttons[0].fsStyle = BTNS_BUTTON; + buttons[0].fsState = TBSTATE_ENABLED; + buttons[0].iString = -1; + buttons[1].idCommand = 3; + buttons[1].fsStyle = BTNS_BUTTON; + buttons[1].fsState = TBSTATE_ENABLED; + buttons[1].iString = -1; + buttons[2].idCommand = 5; + buttons[2].fsStyle = BTNS_SEP; + buttons[2].fsState = TBSTATE_ENABLED; + buttons[2].iString = -1; + buttons[3].idCommand = 7; + buttons[3].fsStyle = BTNS_BUTTON; + buttons[3].fsState = TBSTATE_ENABLED; + buttons[3].iString = -1; + buttons[4].idCommand = 9; + buttons[4].fsStyle = BTNS_BUTTON; + buttons[4].fsState = 0; /* disabled */ + buttons[4].iString = -1; + ok(SendMessage(*hToolbar, TB_ADDBUTTONS, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); +} + + +#define CHECK_IMAGELIST(count, dx, dy) { \ + int cx, cy; \ + HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \ + ok(himl != NULL, "No image list\n"); \ + if (himl != NULL) {\ + ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \ + ImageList_GetIconSize(himl, &cx, &cy); \ + ok(cx == dx && cy == dy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \ + } \ +} + +static void test_add_bitmap(void) +{ + HWND hToolbar = NULL; + TBADDBITMAP bmp128; + TBADDBITMAP bmp80; + TBADDBITMAP stdsmall; + TBADDBITMAP addbmp; + HIMAGELIST himl; + INT ret; + + /* empty 128x15 bitmap */ + bmp128.hInst = GetModuleHandle(NULL); + bmp128.nID = IDB_BITMAP_128x15; + + /* empty 80x15 bitmap */ + bmp80.hInst = GetModuleHandle(NULL); + bmp80.nID = IDB_BITMAP_80x15; + + /* standard bitmap - 240x15 pixels */ + stdsmall.hInst = HINST_COMMCTRL; + stdsmall.nID = IDB_STD_SMALL_COLOR; + + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(8, 16, 16); + + /* adding more bitmaps */ + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(13, 16, 16); + /* adding the same bitmap will simply return the index of the already loaded block */ + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128); + ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(13, 16, 16); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80); + ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(13, 16, 16); + /* even if we increase the wParam */ + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80); + ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(13, 16, 16); + + /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(8, 16, 16); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80); + ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret); + /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */ + CHECK_IMAGELIST(13, 16, 16); + + /* the same for negative wParam */ + rebuild_toolbar(&hToolbar); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128); + ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(8, 16, 16); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80); + ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(13, 16, 16); + + /* for zero only one bitmap will be added */ + rebuild_toolbar(&hToolbar); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80); + ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(1, 16, 16); + + /* if wParam is larger than the amount of icons, the list is grown */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(100, 16, 16); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128); + ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(200, 16, 16); + + /* adding built-in items - the wParam is ignored */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(5, 16, 16); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(20, 16, 16); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(28, 16, 16); + + /* when we increase the bitmap size, less icons will be created */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(6, 20, 20); + ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80); + ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret); + CHECK_IMAGELIST(10, 20, 20); + /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */ + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(26, 8, 8); + /* loading a standard bitmaps automatically resizes the icons */ + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(28, 16, 16); + + /* two more SETBITMAPSIZE tests */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(100, 16, 16); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(200, 16, 16); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(200, 8, 8); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(200, 30, 30); + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(8, 16, 16); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(13, 16, 16); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(8, 30, 30); + /* when the width or height is zero, set it to 1 */ + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(208, 1, 1); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 5)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(208, 1, 5); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(5, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(41, 5, 1); + + /* the control can add bitmaps to an existing image list */ + rebuild_toolbar(&hToolbar); + himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR); + ok(himl != NULL, "failed to create imagelist\n"); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n"); + CHECK_IMAGELIST(4, 20, 15); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(10, 20, 15); + /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change) */ + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(15, 14), "%x"); + CHECK_IMAGELIST(10, 20, 15); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n"); + UpdateWindow(hToolbar); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x"); + CHECK_IMAGELIST(22, 20, 15); + + /* check standard bitmaps */ + addbmp.hInst = HINST_COMMCTRL; + addbmp.nID = IDB_STD_SMALL_COLOR; + rebuild_toolbar(&hToolbar); + 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"); + addbmp.nID = IDB_STD_LARGE_COLOR; + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(15, 24, 24); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(31, 30), "%x"); + + addbmp.nID = IDB_VIEW_SMALL_COLOR; + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(12, 16, 16); + addbmp.nID = IDB_VIEW_LARGE_COLOR; + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(12, 24, 24); + + addbmp.nID = IDB_HIST_SMALL_COLOR; + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(5, 16, 16); + addbmp.nID = IDB_HIST_LARGE_COLOR; + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n"); + CHECK_IMAGELIST(5, 24, 24); + + + DestroyWindow(hToolbar); +} + +#define CHECK_STRING_TABLE(count, tab) { \ + INT _i; \ + CHAR _buf[260]; \ + for (_i = 0; _i < (count); _i++) {\ + ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, _i), (LPARAM)_buf); \ + ok(ret >= 0, "TB_GETSTRING - unexpected return %d while checking string %d\n", ret, _i); \ + if (ret >= 0) \ + 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"); \ + } + +static void test_add_string(void) +{ + LPCSTR test1 = "a\0b\0"; + LPCSTR test2 = "|a|b||\0"; + LPCSTR ret1[] = {"a", "b"}; + LPCSTR ret2[] = {"a", "b", "|a|b||"}; + LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"}; + LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"}; + LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"}; + LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"}; + LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"}; + HWND hToolbar = NULL; + TBBUTTON button; + int ret; + + rebuild_toolbar(&hToolbar); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1); + ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(2, ret1); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2); + ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(3, ret2); + + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1); + ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(3, ret2); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2); + ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(5, ret3); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3); + ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(6, ret4); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4); + ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(8, ret5); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5); + ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(11, ret6); + ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7); + ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret); + CHECK_STRING_TABLE(14, ret7); + + ZeroMemory(&button, sizeof(button)); + button.iString = (UINT_PTR)"Test"; + SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button); + CHECK_STRING_TABLE(14, ret7); + SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button); + CHECK_STRING_TABLE(14, ret7); + + DestroyWindow(hToolbar); +} + +static void expect_hot_notify(int idold, int idnew) +{ + g_fExpectedHotItemOld = idold; + g_fExpectedHotItemNew = idnew; + g_fReceivedHotItemChange = FALSE; +} + +#define check_hot_notify() \ + ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \ + g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0; + +static void test_hotitem(void) +{ + HWND hToolbar = NULL; + TBBUTTONINFO tbinfo; + LRESULT ret; + + g_fBlockHotItemChange = FALSE; + + rebuild_toolbar_with_buttons(&hToolbar); + /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars. + * comctl6 doesn't have this requirement even when theme == NULL */ + SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE)); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == -1, "Hot item: %ld, expected -1\n", ret); + ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0); + ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 1, "Hot item: %ld, expected 1\n", ret); + ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0); + ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret); + + ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0); + ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 2, "Hot item: %lx, expected 2\n", ret); + ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0); + ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == -1, "Hot item: %lx, expected -1\n", ret); + + expect_hot_notify(0, 7); + ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0); + ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret); + check_hot_notify(); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 3, "Hot item: %lx, expected 3\n", ret); + g_fBlockHotItemChange = TRUE; + ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 3, "Hot item: %lx, expected 3\n", ret); + g_fBlockHotItemChange = FALSE; + + g_fReceivedHotItemChange = FALSE; + ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret); + ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n"); + + g_fReceivedHotItemChange = FALSE; + ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret); + ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n"); + + expect_hot_notify(7, 0); + ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret); + check_hot_notify(); + SendMessage(hToolbar, TB_SETHOTITEM, 3, 0); + + /* setting disabled buttons will generate a notify with the button id but no button will be hot */ + expect_hot_notify(7, 9); + ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret); + check_hot_notify(); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == -1, "Hot item: %lx, expected -1\n", ret); + /* enabling the button won't change that */ + SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret); + + /* disabling a hot button works */ + ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0); + ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret); + g_fReceivedHotItemChange = FALSE; + SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret); + ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n"); + + SendMessage(hToolbar, TB_SETHOTITEM, 1, 0); + tbinfo.cbSize = sizeof(TBBUTTONINFO); + tbinfo.dwMask = TBIF_STATE; + tbinfo.fsState = 0; /* disabled */ + g_fReceivedHotItemChange = FALSE; + ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n"); + ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0); + ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret); + ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n"); + + DestroyWindow(hToolbar); +} + +#if 0 /* use this to generate more tests*/ + +static void dump_sizes(HWND hToolbar) +{ + SIZE sz; + RECT r; + int count = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0); + int i; - case WM_CREATE: + GetClientRect(hToolbar, &r); + SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz); + printf(" { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom, + sz.cx, sz.cy, count); + for (i=0; ircClient);*/ \ + buttonCount = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 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)) { \ + check_rect("button", rc, res->rcButtons[i]); \ + } else {\ + todo_wine { check_rect("button", rc, res->rcButtons[i]); } \ + } \ + mask >>= 1; \ + } \ + tbsize_numtests++; \ } - return 0L; + +#define check_sizes() check_sizes_todo(0) + +#endif + +static TBBUTTON buttons1[] = { + {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1}, + {0, 11, 0, 0, {0, }, 0, -1}, +}; +static TBBUTTON buttons2[] = { + {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1}, + {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1}, +}; +static TBBUTTON buttons3[] = { + {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0}, + {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1}, + {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1}, + {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)"Tst"} +}; + +static void test_sizes(void) +{ + HWND hToolbar = NULL; + HIMAGELIST himl; + int style; + int i; + + rebuild_toolbar_with_buttons(&hToolbar); + style = GetWindowLong(hToolbar, GWL_STYLE); + ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style); + check_sizes(); + /* the TBSTATE_WRAP makes a second row */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1); + check_sizes(); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes(); + /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */ + SetWindowLong(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE); + check_sizes(); + /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1); + check_sizes(); + /* only after adding enough buttons the bar will be wrapped on a + * separator and then on the first button */ + for (i=0; i<15; i++) + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1); + check_sizes_todo(0x4); + + rebuild_toolbar_with_buttons(&hToolbar); + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1); + /* setting the buttons vertical will only change the window client size */ + SetWindowLong(hToolbar, GWL_STYLE, style | CCS_VERT); + SendMessage(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes_todo(0x3c); + /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */ + SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT); + SendMessage(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes_todo(0x7c); + + rebuild_toolbar_with_buttons(&hToolbar); + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1); + /* a TB_SETBITMAPSIZE changes button sizes*/ + SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24)); + check_sizes(); + + /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */ + SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes(); + /* but after a TB_SETBITMAPSIZE the top margins is changed */ + SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)); + SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24)); + check_sizes(); + /* some vertical toolbar sizes */ + SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT); + check_sizes_todo(0x7c); + + rebuild_toolbar_with_buttons(&hToolbar); + SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT); + /* newly added buttons will be use the previous margin */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2); + check_sizes(); + /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */ + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n"); + check_sizes(); + /* add some buttons with non-default sizes */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2); + SendMessageA(hToolbar, TB_INSERTBUTTON, -1, (LPARAM)&buttons2[0]); + check_sizes(); + SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]); + /* TB_ADDSTRING resets the size */ + SendMessageA(hToolbar, TB_ADDSTRING, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n"); + check_sizes(); + /* TB_SETBUTTONSIZE can be used to crop the text */ + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + check_sizes(); + /* the default size is bitmap size + padding */ + SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1)); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(17, 17), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3)); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(4, 4), "Unexpected button size\n"); + + rebuild_toolbar(&hToolbar); + /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */ + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n"); + + rebuild_toolbar(&hToolbar); + SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0"); + /* the height is increased after a TB_ADDSTRING */ + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); + /* if a string is in the pool, even adding a button without a string resets the size */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); + /* an BTNS_AUTOSIZE button is also considered when computing the new size */ + SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]); + check_sizes(); + /* delete button doesn't change the buttons size */ + SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0); + SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n"); + /* TB_INSERTBUTTONS will */ + SendMessageA(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons2[0]); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + + /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */ + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); + ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); + /* however changing the hidden flag with TB_SETSTATE does */ + ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); + + /* TB_SETIMAGELIST always changes the height but the width only if necessary */ + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); + himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1)); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n"); + /* the text is taken into account */ + SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0"); + SendMessageA(hToolbar, TB_ADDBUTTONS, 4, (LPARAM)buttons3); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 38), "Unexpected button size\n"); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 24), "Unexpected button size\n"); + /* the style change also comes into effect */ + check_sizes(); + SetWindowLong(hToolbar, GWL_STYLE, GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n"); + check_sizes_todo(0x30); /* some small problems with BTNS_AUTOSIZE button sizes */ + + rebuild_toolbar(&hToolbar); + ImageList_Destroy(himl); + + SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n"); + SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n"); + + DestroyWindow(hToolbar); +} + +static void test_getbuttoninfo(void) +{ + HWND hToolbar = NULL; + int i; + + rebuild_toolbar_with_buttons(&hToolbar); + for (i = 0; i < 128; i++) + { + TBBUTTONINFO tbi; + int ret; + + tbi.cbSize = i; + tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; + ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi); + if (i == sizeof(TBBUTTONINFO)) { + compare(ret, 0, "%d"); + } else { + compare(ret, -1, "%d"); + } + } + DestroyWindow(hToolbar); +} + +static void test_createtoolbarex(void) +{ + HWND hToolbar; + TBBUTTON btns[3]; + ZeroMemory(&btns, sizeof(btns)); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, 20, 20, 16, 16, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 20, 20); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, 4, 4, 16, 16, sizeof(TBBUTTON)); + CHECK_IMAGELIST(32, 4, 4); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, 0, 8, 12, 12, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 12, 12); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, -1, 8, 12, 12, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 12, 8); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, -1, 8, -1, 12, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 16, 8); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, 0, 0, 12, -1, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 12, 16); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x"); + DestroyWindow(hToolbar); + + hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns, + 3, 0, 0, 0, 12, sizeof(TBBUTTON)); + CHECK_IMAGELIST(16, 16, 16); + compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x"); + DestroyWindow(hToolbar); +} + +static void test_dispinfo(void) +{ + HWND hToolbar = NULL; + const TBBUTTON buttons_disp[] = { + {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1}, + {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1}, + }; + BOOL ret; + + 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; + /* 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"); + ShowWindow(hToolbar, SW_SHOW); + UpdateWindow(hToolbar); + + ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, TRUE, 0); + compare(ret, FALSE, "%d"); + compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 1L, "%ld"); + InvalidateRect(hToolbar, NULL, FALSE); + UpdateWindow(hToolbar); + + ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0); + compare(ret, TRUE, "%d"); + compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0L, "%ld"); + InvalidateRect(hToolbar, NULL, FALSE); + UpdateWindow(hToolbar); + + DestroyWindow(hToolbar); + g_dwExpectedDispInfoMask = 0; +} + +typedef struct +{ + int nRows; + BOOL bLarger; + int expectedRows; +} tbrows_result_t; + +static tbrows_result_t tbrows_results[] = +{ + {1, TRUE, 1}, /* 0: Simple case 9 in a row */ + {2, TRUE, 2}, /* 1: Another simple case 5 on one row, 4 on another*/ + {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */ + {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */ + {8, TRUE, 9}, /* 4: 8 lines but grow - should be 9 lines */ + {1, TRUE, 1} /* 5: Back to simple case */ +}; + +static void test_setrows(void) +{ + TBBUTTON buttons[9]; + HWND hToolbar; + int i; + + for (i=0; i<9; i++) + MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0); + + /* Test 1 - 9 buttons */ + hToolbar = CreateToolbarEx(hMainWnd, + WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN + | CCS_NOMOVEY | CCS_TOP, + 0, + 0, NULL, (UINT)0, + buttons, sizeof(buttons)/sizeof(buttons[0]), + 20, 20, 0, 0, sizeof(TBBUTTON)); + ok(hToolbar != NULL, "Toolbar creation\n"); + ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); + + /* test setting rows to each of 1-10 with bLarger true and false */ + for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) { + RECT rc; + int rows; + + memset(&rc, 0xCC, sizeof(rc)); + SendMessageA(hToolbar, TB_SETROWS, + MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger), + (LONG) &rc); + + rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0)); + ok(rows == tbrows_results[i].expectedRows, + "[%d] Unexpected number of rows %d (expected %d)\n", i, rows, + tbrows_results[i].expectedRows); + } + + DestroyWindow(hToolbar); } START_TEST(toolbar) @@ -110,28 +1093,40 @@ START_TEST(toolbar) WNDCLASSA wc; MSG msg; RECT rc; - HWND hMainWnd; - + InitCommonControls(); - + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM)); + wc.hCursor = LoadCursorA(NULL, IDC_IBEAM); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = "MyTestWnd"; wc.lpfnWndProc = MyWndProc; RegisterClassA(&wc); - - hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, + + hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); GetClientRect(hMainWnd, &rc); + ShowWindow(hMainWnd, SW_SHOW); + + basic_test(); + test_add_bitmap(); + test_add_string(); + test_hotitem(); + test_sizes(); + test_getbuttoninfo(); + test_createtoolbarex(); + test_dispinfo(); + test_setrows(); + PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessageA(&msg); } + DestroyWindow(hMainWnd); } diff --git a/rostests/winetests/comctl32/tooltips.c b/rostests/winetests/comctl32/tooltips.c index 7f324713d38..713fa240368 100644 --- a/rostests/winetests/comctl32/tooltips.c +++ b/rostests/winetests/comctl32/tooltips.c @@ -38,10 +38,10 @@ static void test_create_tooltip(void) assert(hwnd); style = GetWindowLong(hwnd, GWL_STYLE); - trace("style = %08lx\n", style); + 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 %08lx/%08lx\n", style, exp_style); + ok(style == exp_style,"wrong style %08x/%08x\n", style, exp_style); DestroyWindow(hwnd); @@ -51,9 +51,9 @@ static void test_create_tooltip(void) assert(hwnd); style = GetWindowLong(hwnd, GWL_STYLE); - trace("style = %08lx\n", style); + trace("style = %08x\n", style); ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER), - "wrong style %08lx\n", style); + "wrong style %08x\n", style); DestroyWindow(hwnd); diff --git a/rostests/winetests/comctl32/trackbar.c b/rostests/winetests/comctl32/trackbar.c new file mode 100644 index 00000000000..13f56fdae78 --- /dev/null +++ b/rostests/winetests/comctl32/trackbar.c @@ -0,0 +1,1012 @@ +/* Unit tests for the track bar control. + * + * Copyright 2007 Keith Stevens + * + * 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 +#include +#include +#include + +#include "wine/test.h" +#include "msg.h" + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) +#define NUM_MSG_SEQUENCE 2 +#define PARENT_SEQ_INDEX 0 +#define TRACKBAR_SEQ_INDEX 1 + + +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_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} +}; + +static const struct message parent_empty_test_seq[] = { + {0} +}; + +static const struct message parent_create_trackbar_wnd_seq[] = { + { WM_NOTIFYFORMAT, sent}, + { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129 */ + { WM_WINDOWPOSCHANGING, sent}, + { WM_NCACTIVATE, sent}, + { PBT_APMRESUMECRITICAL, sent}, + { WM_WINDOWPOSCHANGING, sent}, + { PBT_APMRESUMESTANDBY, sent}, + { WM_IME_SETCONTEXT, sent|optional}, + { WM_IME_NOTIFY, sent|optional}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message parent_new_window_test_seq[] = { + { WM_WINDOWPOSCHANGING, sent}, + { WM_NCACTIVATE, sent}, + { PBT_APMRESUMECRITICAL, sent}, + { WM_IME_SETCONTEXT, sent|defwinproc|optional}, + { WM_IME_NOTIFY, sent|defwinproc|optional}, + { WM_SETFOCUS, sent|defwinproc}, + { WM_NOTIFYFORMAT, sent}, + { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129*/ + {0} +}; + +static const struct message buddy_window_test_seq[] = { + { TBM_GETBUDDY, sent|wparam, TRUE}, + { TBM_SETBUDDY, sent|wparam, FALSE}, + { WM_PAINT, sent|defwinproc}, + { TBM_SETBUDDY, sent|wparam, FALSE}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETBUDDY, sent|wparam, TRUE}, + { TBM_SETBUDDY, sent|wparam, TRUE}, + { WM_PAINT, sent|defwinproc}, + { TBM_SETBUDDY, sent|wparam, TRUE}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETBUDDY, sent|wparam, FALSE}, + { TBM_GETBUDDY, sent|wparam, TRUE}, + {0} +}; + +static const struct message parent_buddy_window_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message line_size_test_seq[] = { + { TBM_SETLINESIZE, sent|lparam, 0, 10}, + { TBM_SETLINESIZE, sent|lparam, 0, 4}, + { TBM_GETLINESIZE, sent}, + {0} +}; + +static const struct message page_size_test_seq[] = { + { TBM_SETPAGESIZE, sent|lparam, 0, 10}, + { TBM_SETPAGESIZE, sent|lparam, 0, -1}, + { TBM_GETPAGESIZE, sent}, + {0} +}; + +static const struct message position_test_seq[] = { + { TBM_SETPOS, sent|wparam|lparam, TRUE, -1}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETPOS, sent}, + { TBM_SETPOS, sent|wparam|lparam, TRUE, 5}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETPOS, sent}, + { TBM_SETPOS, sent|wparam|lparam, TRUE, 1000}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETPOS, sent}, + { TBM_SETPOS, sent|wparam|lparam, FALSE, 20}, + { TBM_GETPOS, sent}, + { TBM_GETPOS, sent}, + {0} +}; + +static const struct message parent_position_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message range_test_seq[] = { + { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(0, 10)}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMAX, sent}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(-1, 1000)}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMAX, sent}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(10, 0)}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMAX, sent}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGE, sent|wparam|lparam, FALSE, MAKELONG(0, 10)}, + { TBM_GETRANGEMAX, sent}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGEMAX, sent|wparam|lparam, TRUE, 10}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMAX, sent}, + { TBM_SETRANGEMAX, sent|wparam|lparam, TRUE, -1}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMAX, sent}, + { TBM_SETRANGEMAX, sent|wparam|lparam, FALSE, 10}, + { TBM_GETRANGEMAX, sent}, + { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, 0}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, 10}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, -10}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETRANGEMIN, sent}, + { TBM_SETRANGEMIN, sent|wparam|lparam, FALSE, 5}, + { TBM_GETRANGEMIN, sent}, + { TBM_GETRANGEMAX, sent}, + { TBM_GETRANGEMIN, sent}, + {0} +}; + +static const struct message parent_range_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message selection_test_seq[] = { + { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(0, 10)}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELEND, sent}, + { TBM_GETSELSTART, sent}, + { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(5, 20)}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELEND, sent}, + { TBM_GETSELSTART, sent}, + { TBM_SETSEL, sent|wparam|lparam, FALSE, MAKELONG(5, 10)}, + { TBM_GETSELEND, sent}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELEND, sent|wparam|lparam, TRUE, 10}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELEND, sent}, + { TBM_SETSELEND, sent|wparam|lparam, TRUE, 20}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELEND, sent}, + { TBM_SETSELEND, sent|wparam|lparam, TRUE, 4}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELEND, sent}, + { TBM_SETSELEND, sent|wparam|lparam, FALSE, 2}, + { TBM_GETSELEND, sent}, + { TBM_GETSELEND, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 5}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 0}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 20}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, FALSE, 8}, + { TBM_GETSELSTART, sent}, + { TBM_GETSELSTART, sent}, + {0} +}; + +static const struct message parent_selection_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message tic_settings_test_seq[] = { + { TBM_SETTIC, sent|lparam, 0, 0}, + { TBM_SETTIC, sent|lparam, 0, 5}, + { TBM_SETTIC, sent|lparam, 0, 10}, + { TBM_SETTIC, sent|lparam, 0, 20}, + { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(0,10)}, + { WM_PAINT, sent|defwinproc}, + { TBM_SETTICFREQ, sent|wparam, 2}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETNUMTICS, sent}, + { TBM_SETTICFREQ, sent|wparam, 5}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETNUMTICS, sent}, + { TBM_SETTICFREQ, sent|wparam, 15}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETNUMTICS, sent}, + { TBM_GETNUMTICS, sent}, + {0} +}; + +static const struct message parent_tic_settings_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message thumb_length_test_seq[] = { + { TBM_SETTHUMBLENGTH, sent|wparam|lparam, 15, 0}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETTHUMBLENGTH, sent}, + { TBM_SETTHUMBLENGTH, sent|wparam|lparam, 20, 0}, + { WM_PAINT, sent|defwinproc}, + { TBM_GETTHUMBLENGTH, sent}, + { TBM_GETTHUMBLENGTH, sent}, + {0} +}; + +static const struct message parent_thumb_length_test_seq[] = { + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + { WM_CTLCOLORSTATIC, sent}, + { WM_NOTIFY, sent}, + {0} +}; + +static const struct message tic_placement_test_seq[] = { + { TBM_GETPTICS, sent}, + { TBM_GETTIC, sent|wparam, 0}, + { TBM_GETTIC, sent|wparam, 4}, + { TBM_GETTIC, sent|wparam, 11}, + { TBM_GETTICPOS, sent|wparam, 0}, + { TBM_GETTICPOS, sent|wparam, 4}, + {0} +}; + +static const struct message tool_tips_test_seq[] = { + { TBM_SETTIPSIDE, sent|wparam, TBTS_TOP}, + { TBM_SETTIPSIDE, sent|wparam, TBTS_LEFT}, + { TBM_SETTIPSIDE, sent|wparam, TBTS_BOTTOM}, + { TBM_SETTIPSIDE, sent|wparam, TBTS_RIGHT}, + { TBM_SETTOOLTIPS, sent}, + { TBM_GETTOOLTIPS, sent}, + { TBM_SETTOOLTIPS, sent}, + { TBM_GETTOOLTIPS, sent}, + { TBM_SETTOOLTIPS, sent}, + { TBM_GETTOOLTIPS, sent}, + { TBM_GETTOOLTIPS, sent}, + {0} +}; + +static const struct message unicode_test_seq[] = { + { TBM_SETUNICODEFORMAT, sent|wparam, TRUE}, + { TBM_SETUNICODEFORMAT, sent|wparam, FALSE}, + { TBM_GETUNICODEFORMAT, sent}, + {0} +}; + +static const struct message ignore_selection_test_seq[] = { + { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(0,10)}, + { TBM_GETSELEND, sent}, + { TBM_GETSELSTART, sent}, + { TBM_SETSEL, sent|wparam|lparam, FALSE, MAKELONG(0,10)}, + { TBM_GETSELEND, sent}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELEND, sent|wparam|lparam, TRUE,0}, + { TBM_GETSELEND, sent}, + { TBM_SETSELEND, sent|wparam|lparam, TRUE, 10}, + { TBM_GETSELEND, sent}, + { TBM_SETSELEND, sent|wparam|lparam, FALSE,0}, + { TBM_GETSELEND, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, TRUE,0}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 10}, + { TBM_GETSELSTART, sent}, + { TBM_SETSELSTART, sent|wparam|lparam, FALSE,0}, + { TBM_GETSELSTART, sent}, + {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; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static BOOL register_parent_wnd_class(void){ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = parent_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Trackbar test parent class"; + return RegisterClassA(&cls); +} + +static HWND create_parent_window(void){ + if (!register_parent_wnd_class()) + return NULL; + + return CreateWindowEx(0, "Trackbar test parent class", + "Trackbar test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); +} + +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); + 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; + add_message(sequences, TRACKBAR_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND create_trackbar(DWORD style, HWND parent){ + struct subclass_info *info; + HWND hWndTrack; + 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; + } + + info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndTrack, GWLP_WNDPROC, (LONG_PTR)trackbar_subclass_proc); + + SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)info); + + return hWndTrack; +} + +/* test functions for setters, getters, and sequences */ + +static void test_trackbar_buddy(HWND hWndTrackbar){ + HWND hWndLeftBuddy; + HWND hWndRightBuddy; + HWND hWndCurrentBuddy; + HWND rTest; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + + hWndLeftBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, + 0,0,300,20, NULL, NULL, NULL, NULL); + ok(hWndLeftBuddy != NULL, "Expected non NULL value\n"); + + if (hWndLeftBuddy != NULL){ + hWndCurrentBuddy = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE, 0); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, FALSE, (LPARAM) hWndLeftBuddy); + ok(rTest == hWndCurrentBuddy, "Expected hWndCurrentBuddy\n"); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, FALSE, (LPARAM) hWndLeftBuddy); + ok(rTest == hWndLeftBuddy, "Expected hWndLeftBuddy\n"); + } else + skip ("left buddy control not present?\n"); + + hWndRightBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, + 0,0,300,20,NULL,NULL, NULL, NULL); + + ok(hWndRightBuddy != NULL, "expected non NULL value\n"); + + /* test TBM_SETBUDDY */ + if (hWndRightBuddy != NULL){ + hWndCurrentBuddy = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE, 0); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, TRUE, (LPARAM) hWndRightBuddy); + ok(rTest == hWndCurrentBuddy, "Expected hWndCurrentBuddy\n"); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, TRUE, (LPARAM) hWndRightBuddy); + ok(rTest == hWndRightBuddy, "Expected hWndRightbuddy\n"); + } else + skip("Right buddy control not present?\n"); + + /* test TBM_GETBUDDY */ + if (hWndLeftBuddy != NULL){ + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, FALSE, 0); + ok(rTest == hWndLeftBuddy, "Expected hWndLeftBuddy\n"); + DestroyWindow(hWndLeftBuddy); + } + if (hWndRightBuddy != NULL){ + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE,0); + ok(rTest == hWndRightBuddy, "Expected hWndRightBuddy\n"); + DestroyWindow(hWndRightBuddy); + } + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, buddy_window_test_seq, "buddy test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_buddy_window_test_seq, "parent buddy test seq", TRUE); + +} + +static void test_line_size(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + + /* test TBM_SETLINESIZE */ + r = SendMessage(hWndTrackbar, TBM_SETLINESIZE, 0, 10); + r = SendMessage(hWndTrackbar, TBM_SETLINESIZE, 0, 4); + expect(10, r); + + /* test TBM_GETLINESIZE */ + r = SendMessage(hWndTrackbar, TBM_GETLINESIZE, 0,0); + expect(4, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, line_size_test_seq, "linesize test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent line test sequence", FALSE); +} + + +static void test_page_size(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + + /* test TBM_SETPAGESIZE */ + r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, 10); + expect(20, r); + r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, -1); + expect(10, r); + + /* test TBM_GETPAGESIZE */ + r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0,0); + todo_wine{ + expect(20, r); + } + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, page_size_test_seq, "page size test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent page size test sequence", FALSE); +} + +static void test_position(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* test TBM_SETPOS */ + SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, -1); + r = SendMessage(hWndTrackbar, TBM_GETPOS, 0, 0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 5); + r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); + expect(5, r); + SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 1000); + r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); + expect(100, r); + SendMessage(hWndTrackbar, TBM_SETPOS, FALSE, 20); + r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); + expect(20, r); + + /* test TBM_GETPOS */ + r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); + expect(20, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, position_test_seq, "position test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_position_test_seq, "parent position test sequence", TRUE); +} + +static void test_range(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* test TBM_SETRANGE */ + SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(0, 10)); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(-1, 1000)); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(1000, r); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(-1, r); + SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(10, 0)); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(0, r); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(10, r); + SendMessage(hWndTrackbar, TBM_SETRANGE, FALSE, MAKELONG(0,10)); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(0, r); + + /*test TBM_SETRANGEMAX */ + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 10); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(10, r); + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, -1); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(-1, r); + SendMessage(hWndTrackbar, TBM_SETRANGEMAX, FALSE, 10); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(10, r); + + /* testing TBM_SETRANGEMIN */ + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 10); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(10, r); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, -10); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(-10, r); + SendMessage(hWndTrackbar, TBM_SETRANGEMIN, FALSE, 5); + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(5, r); + + /* test TBM_GETRANGEMAX */ + r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0); + expect(10, r); + + /* test TBM_GETRANGEMIN */ + r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0); + expect(5, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, range_test_seq, "range test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_range_test_seq, "parent range test sequence", TRUE); +} + +static void test_selection(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* test TBM_SETSEL */ + SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(0,10)); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(5, r); + SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(5, 20)); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(5, r); + SendMessage(hWndTrackbar, TBM_SETSEL, FALSE, MAKELONG(5, 10)); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(10, r); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(5, r); + + /* test TBM_SETSELEND */ + SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 10); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(10, r); + SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 20); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(10, r); + SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 4); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(4, r); + SendMessage(hWndTrackbar, TBM_SETSELEND, FALSE, 2); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(2, r); + + /* test TBM_GETSELEND */ + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(2, r); + + /* testing TBM_SETSELSTART */ + SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 5); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(5, r); + SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 0); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(5, r); + SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 20); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(20, r); + SendMessage(hWndTrackbar, TBM_SETSELSTART, FALSE, 8); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(8, r); + + /* test TBM_GETSELSTART */ + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(8, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, selection_test_seq, "selection test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_selection_test_seq, "parent selection test seqence", TRUE); +} + +static void test_thumb_length(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* testing TBM_SETTHUMBLENGTH */ + SendMessage(hWndTrackbar, TBM_SETTHUMBLENGTH, 15, 0); + r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0); + expect(15, r); + SendMessage(hWndTrackbar, TBM_SETTHUMBLENGTH, 20, 0); + r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0); + expect(20, r); + + /* test TBM_GETTHUMBLENGTH */ + r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0); + expect(20, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, thumb_length_test_seq, "thumb length test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_thumb_length_test_seq, "parent thumb lenth test sequence", TRUE); +} + +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_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); + } + 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); + expect(6, r); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 5, 0); + r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0); + expect(3, r); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 15, 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); + 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); +} + +static void test_tic_placement(HWND hWndTrackbar){ + int r; + DWORD *rPTics; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* test TBM_GETPTICS */ + rPTics = (DWORD *) SendMessage(hWndTrackbar, TBM_GETPTICS, 0,0); + todo_wine{ + expect(1, rPTics[0]); + expect(2, rPTics[1]); + expect(3, rPTics[2]); + expect(4, rPTics[3]); + } + + /* test TBM_GETTIC */ + r = SendMessage(hWndTrackbar, TBM_GETTIC, 0,0); + todo_wine{ + expect(1, r); + r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0); + expect(5, r); + } + r = SendMessage(hWndTrackbar, TBM_GETTIC, 11,0); + expect(-1, r); + + /* test TBM_GETTICPIC */ + r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0); + todo_wine{ + ok(r > 0, "Expected r > 0, got %d\n", r); + r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 4, 0); + ok(r > 0, "Expected r > 0, got %d\n", r); + } + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_placement_test_seq, "get tic placement test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent get tic placement test sequence", FALSE); +} + + +static void test_tool_tips(HWND hWndTrackbar){ + int r; + HWND hWndTooltip; + HWND rTest; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* testing TBM_SETTIPSIDE */ + r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_TOP, 0); + todo_wine{ + expect(0, r); + } + r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_LEFT, 0); + expect(0, r); + r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_BOTTOM, 0); + expect(1, r); + r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_RIGHT, 0); + expect(2, r); + + /* testing TBM_SETTOOLTIPS */ + hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, NULL, NULL); + + ok(hWndTooltip != NULL, "Expected non NULL value\n"); + if (hWndTooltip != NULL){ + SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 0); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); + ok(rTest == hWndTooltip, "Expected hWndToolTip, got\n"); + SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) NULL, 0); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); + ok(rTest == NULL, "Expected NULL\n"); + SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 5); + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); + ok(rTest == hWndTooltip, "Expected hWndTooltip, got\n"); + } else + skip("tool tip control not present?\n"); + + /* test TBM_GETTOOLTIPS */ + rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); + ok(rTest == hWndTooltip, "Expected hWndTooltip\n"); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tool_tips_test_seq, "tool tips test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent tool tips test sequence", FALSE); +} + + +static void test_unicode(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* testing TBM_SETUNICODEFORMAT */ + r = SendMessage(hWndTrackbar, TBM_SETUNICODEFORMAT, TRUE, 0); + ok(r == FALSE, "Expected FALSE, got %d\n",r); + r = SendMessage(hWndTrackbar, TBM_SETUNICODEFORMAT, FALSE, 0); + ok(r == TRUE, "Expected TRUE, got %d\n",r); + + /* test TBM_GETUNICODEFORMAT */ + r = SendMessage(hWndTrackbar, TBM_GETUNICODEFORMAT, 0,0); + ok(r == FALSE, "Expected FALSE, got %d\n",r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, unicode_test_seq, "unicode test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent unicode test sequence", FALSE); +} + +static void test_ignore_selection(HWND hWndTrackbar){ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + /* test TBM_SETSEL ensure that it is ignored */ + SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(0,10)); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(0, r); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETSEL, FALSE, MAKELONG(0,10)); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(0, r); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(0, r); + + /* test TBM_SETSELEND, ensure that it is ignored */ + SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 0); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 10); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(0,r); + SendMessage(hWndTrackbar, TBM_SETSELEND, FALSE, 0); + r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0); + expect(0, r); + + /* test TBM_SETSELSTART, ensure that it is ignored */ + SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 0); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(0, r); + SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 10); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(0,r); + SendMessage(hWndTrackbar, TBM_SETSELSTART, FALSE, 0); + r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0); + expect(0, r); + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, ignore_selection_test_seq, "ignore selection setting test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE); +} + +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"); + + if(!hWndParent){ + skip("parent window not present\n"); + 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 */ + hWndTrackbar = create_trackbar(style, hWndParent); + + ok(hWndTrackbar != NULL, "Expected non NULL value\n"); + + if (!hWndTrackbar){ + skip("trackbar control not present?\n"); + return; + } + + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, create_trackbar_wnd_seq, "create Trackbar Window", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_trackbar_wnd_seq, "parent trackbar window", TRUE); + flush_sequences(sequences, NUM_MSG_SEQUENCE); + + /* TEST OF ALL SETTER and GETTER MESSAGES with required styles turned on*/ + test_trackbar_buddy(hWndTrackbar); + test_line_size(hWndTrackbar); + test_page_size(hWndTrackbar); + test_position(hWndTrackbar); + test_range(hWndTrackbar); + test_selection(hWndTrackbar); + test_thumb_length(hWndTrackbar); + test_tic_settings(hWndTrackbar); + test_tic_placement(hWndTrackbar); + test_tool_tips(hWndTrackbar); + test_unicode(hWndTrackbar); + + flush_sequences(sequences, NUM_MSG_SEQUENCE); + DestroyWindow(hWndTrackbar); + + /* test getters and setters without styles set */ + hWndTrackbar = create_trackbar(0, hWndParent); + + ok(hWndTrackbar != NULL, "Expected non NULL value\n"); + + if (!hWndTrackbar){ + skip("trackbar control not present?\n"); + return; + } + + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_new_window_test_seq, "new trackbar window test sequence", TRUE); + + test_ignore_selection(hWndTrackbar); + + DestroyWindow(hWndTrackbar); + + DestroyWindow(hWndParent); +} diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c index d65155aa36a..2981db74223 100644 --- a/rostests/winetests/comctl32/treeview.c +++ b/rostests/winetests/comctl32/treeview.c @@ -1,6 +1,7 @@ /* Unit tests for treeview. * * Copyright 2005 Krzysztof Foltman + * Copyright 2007 Christopher James Peterson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,13 +27,167 @@ #include "winuser.h" #include "winnls.h" #include "winreg.h" -#include "commctrl.h" +#include "commctrl.h" #include "wine/test.h" +#include "msg.h" + +#define NUM_MSG_SEQUENCES 1 +#define LISTVIEW_SEQ_INDEX 0 + +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 }, + { 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 }, + { 0 } +}; + +static const struct message DoFocusTestSeq[] = { + { TVM_INSERTITEM, sent }, + { TVM_INSERTITEM, sent }, + { WM_WINDOWPOSCHANGING, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, + { 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 }, + { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, + { WM_WINDOWPOSCHANGED, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { 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_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_KILLFOCUS, sent|defwinproc }, + { WM_PAINT, sent|defwinproc }, + { WM_IME_SETCONTEXT, sent|defwinproc|optional }, + { WM_COMMAND, sent|wparam|defwinproc, 0x01000000}, + { WM_ERASEBKGND, sent|defwinproc }, + { 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, 0xffffffff }, + { 0 } +}; + +static const struct message TestGetSetImageListSeq[] = { + { TVM_SETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_GETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { 0 } +}; + +static const struct message TestGetSetIndentSeq[] = { + { TVM_SETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + /* The actual amount to indent is dependent on the system for this message */ + { TVM_SETINDENT, sent }, + { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { 0 } +}; + +static const struct message TestGetSetInsertMarkColorSeq[] = { + { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { 0 } +}; + +static const struct message TestGetSetItemSeq[] = { + { TVM_GETITEM, sent }, + { TVM_SETITEM, sent }, + { TVM_GETITEM, sent }, + { TVM_SETITEM, sent }, + { 0 } +}; + +static const struct message TestGetSetItemHeightSeq[] = { + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam, 0xffffffff, 0x00000000 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0x00000000 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam, 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 }, + { 0 } +}; + +static const struct message TestGetSetScrollTimeSeq[] = { + { TVM_SETSCROLLTIME, sent|wparam|lparam, 0x00000014, 0x00000000 }, + { TVM_GETSCROLLTIME, sent|wparam|lparam, 0x00000000, 0x00000000 }, + { 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, 0xffffffff }, + { 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 }, + { 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 }, + { 0 } +}; static HWND hMainWnd; -static HWND hTree; +static HWND hTree, hEdit; static HTREEITEM hRoot, hChild; static int pos = 0; @@ -70,6 +225,7 @@ static void IdentifyItem(HTREEITEM hItem) static void FillRoot(void) { TVINSERTSTRUCTA ins; + TVITEM tvi; static CHAR root[] = "Root", child[] = "Child"; @@ -82,6 +238,13 @@ static void FillRoot(void) hRoot = TreeView_InsertItem(hTree, &ins); assert(hRoot); + /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */ + tvi.hItem = hRoot; + tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tvi ); + 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; @@ -132,23 +295,326 @@ static void DoTest2(void) ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n"); } -LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +static void DoFocusTest(void) +{ + TVINSERTSTRUCTA ins; + static CHAR child1[] = "Edit", + child2[] = "A really long string"; + HTREEITEM hChild1, hChild2; + + /* This test verifies that when a label is being edited, scrolling + * the treeview does not cause the label to lose focus. To test + * this, first some additional entries are added to generate + * scrollbars. + */ + ins.hParent = hRoot; + ins.hInsertAfter = hChild; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = child1; + hChild1 = TreeView_InsertItem(hTree, &ins); + assert(hChild1); + ins.hInsertAfter = hChild1; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = child2; + hChild2 = TreeView_InsertItem(hTree, &ins); + 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"); +} + +static void TestGetSetBkColor(void) +{ + COLORREF crColor = RGB(0,0,0); + + todo_wine{ + /* 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) ); + 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) ); + 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 ); +} + +static void TestGetSetImageList(void) +{ + HIMAGELIST hImageList = NULL; + + /* Test a NULL HIMAGELIST */ + SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList ); + hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 ); + ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList); + + /* TODO: Test an actual image list */ +} + +static void TestGetSetIndent(void) +{ + int ulIndent = -1; + int ulMinIndent = -1; + int ulMoreThanTwiceMin = -1; + + /* Finding the minimum indent */ + SendMessage( hTree, TVM_SETINDENT, 0, 0 ); + ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 ); + + /* Checking an indent that is more than twice the default indent */ + ulMoreThanTwiceMin = 2*ulMinIndent+1; + 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); +} + +static void TestGetSetInsertMarkColor(void) +{ + COLORREF crColor = RGB(0,0,0); + 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); +} + +static void TestGetSetItem(void) +{ + TVITEM tviRoot = {0}; + int nBufferSize = 80; + char szBuffer[80] = {0}; + + /* Test the root item */ + tviRoot.hItem = hRoot; + tviRoot.mask = TVIF_TEXT; + tviRoot.cchTextMax = nBufferSize; + tviRoot.pszText = szBuffer; + SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot ); + ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer); + + /* Change the root text */ + strncpy(szBuffer, "Testing123", nBufferSize); + SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot ); + memset(szBuffer, 0, nBufferSize); + SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot ); + ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer); + + /* Reset the root text */ + memset(szBuffer, 0, nBufferSize); + strncpy(szBuffer, "Root", nBufferSize); + SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot ); +} + +static void TestGetSetItemHeight(void) +{ + int ulOldHeight = 0; + int ulNewHeight = 0; + + /* Assuming default height to begin with */ + ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 ); + + /* Explicitly setting and getting the default height */ + SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 ); + ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 ); + ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight); + + /* Explicitly setting and getting the height of twice the normal */ + SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 ); + ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 ); + ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight); + + /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */ + 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); +} + +static void TestGetSetScrollTime(void) +{ + int ulExpectedTime = 20; + int ulTime = 0; + 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); +} + +static void TestGetSetTextColor(void) { + /* If the value is -1, the control is using the system color for the text color. */ + COLORREF crColor = RGB(0,0,0); + 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) ); + 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) ); + 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 ); +} + +static void TestGetSetToolTips(void) +{ + HWND hwndLastToolTip = NULL; + HWND hPopupTreeView; + + /* 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); + DestroyWindow(hPopupTreeView); + + /* Testing setting a NULL ToolTip */ + SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 ); + hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 ); + ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip); + + /* TODO: Add a test of an actual tooltip */ +} + +static void TestGetSetUnicodeFormat(void) +{ + BOOL bPreviousSetting = 0; + BOOL bNewSetting = 0; + + /* Set to Unicode */ + bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 ); + bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 ); + ok(bNewSetting == 1, "Unicode setting did not work.\n"); + + /* Set to ANSI */ + SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 ); + bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 ); + ok(bNewSetting == 0, "ANSI setting did not work.\n"); + + /* Revert to original setting */ + SendMessage( hTree, TVM_SETUNICODEFORMAT, (LPARAM)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); + + /* 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; +} + +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, - 0, 0, 300, 50, hWnd, (HMENU)100, GetModuleHandleA(0), 0); + 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; - + + ok(pHdr->code != NM_FIRST - 19, "Treeview should not send NM_TOOLTIPSCREATED\n"); if (pHdr->idFrom == 100) { NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam; switch(pHdr->code) { @@ -166,15 +632,15 @@ LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) } return 0; } - + case WM_SIZE: MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); break; - + case WM_DESTROY: PostQuitMessage(0); break; - + default: return DefWindowProcA(hWnd, msg, wParam, lParam); } @@ -186,18 +652,18 @@ START_TEST(treeview) WNDCLASSA wc; MSG msg; INITCOMMONCONTROLSEX icex; - RECT rc; - + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_TREEVIEW_CLASSES; InitCommonControlsEx(&icex); - + init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES); + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM)); + wc.hCursor = LoadCursorA(NULL, IDC_IBEAM); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = "MyTestWnd"; @@ -206,12 +672,29 @@ START_TEST(treeview) hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); - GetClientRect(hMainWnd, &rc); + CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0); + + if ( !ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n") ) + 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); + DoFocusTest(); + ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoFocusTestSeq, "DoFocusTest", TRUE); + + /* Sequences tested inside due to number */ + TestGetSet(); 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 c69657a625e..6f8e395f26d 100644 --- a/rostests/winetests/comctl32/updown.c +++ b/rostests/winetests/comctl32/updown.c @@ -1,6 +1,8 @@ -/* Unit test suite for updown control. +/* Unit tests for the up-down control * * Copyright 2005 C. Scott Ananian + * Copyright (C) 2007 James Hawkins + * Copyright (C) 2007 Leslie Choong * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,82 +19,574 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +/* TO TEST: + * - send click messages to the up-down control, check the current position + * - up-down control automatically positions itself next to its buddy window + * - up-down control sets the caption of the buddy window + * - test CreateUpDownControl API + * - check UDS_AUTOBUDDY style, up-down control selects previous window in z-order + * - check UDM_SETBUDDY message + * - check UDM_GETBUDDY message + * - up-down control and buddy control must have the same parent + * - up-down control notifies its parent window when its position changes with UDN_DELTAPOS + WM_VSCROLL or WM_HSCROLL + * - check UDS_ALIGN[LEFT,RIGHT]...check that width of buddy window is decreased + * - check that UDS_SETBUDDYINT sets the caption of the buddy window when it is changed + * - check that the thousands operator is set for large numbers + * - check that the thousands operator is not set with UDS_NOTHOUSANDS + * - check UDS_ARROWKEYS, control subclasses the buddy window so that it processes the keys when it has focus + * - check UDS_HORZ + * - check changing past min/max values + * - check UDS_WRAP wraps values past min/max, incrementing past upper value wraps position to lower value + * - can change control's position, min/max pos, radix + * - check UDM_GETPOS, for up-down control with a buddy window, position is the caption of the buddy window, so change the + * caption of the buddy window then call UDM_GETPOS + * - check UDM_SETRANGE, max can be less than min, so clicking the up arrow decreases the current position + * - more stuff to test + */ + #include #include #include #include #include "wine/test.h" +#include "msg.h" + +#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) + +#define NUM_MSG_SEQUENCES 3 +#define PARENT_SEQ_INDEX 0 +#define EDIT_SEQ_INDEX 1 +#define UPDOWN_SEQ_INDEX 2 + +static HWND parent_wnd, edit, updown; + +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_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 }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED /*, MAKELONG(91, 75) exact size depends on font */ }, + { 0 } +}; + +static const struct message add_updown_to_parent_seq[] = { + { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, + { WM_QUERYUISTATE, sent }, + { WM_PARENTNOTIFY, sent|wparam, MAKELONG(WM_CREATE, WM_CREATE) }, + { 0 } +}; + +static const struct message get_edit_text_seq[] = { + { WM_GETTEXT, sent }, + { 0 } +}; + +static const struct message test_updown_pos_seq[] = { + { UDM_SETRANGE, sent|lparam, 0, MAKELONG(100,0) }, + { UDM_GETRANGE, sent}, + { UDM_SETPOS, sent|lparam, 0, 5}, + { UDM_GETPOS, sent}, + { UDM_SETPOS, sent|lparam, 0, 0}, + { UDM_GETPOS, sent}, + { UDM_SETPOS, sent|lparam, 0, MAKELONG(-1,0)}, + { UDM_GETPOS, sent}, + { UDM_SETPOS, sent|lparam, 0, 100}, + { UDM_GETPOS, sent}, + { UDM_SETPOS, sent|lparam, 0, 101}, + { UDM_GETPOS, sent}, + { 0 } +}; + +static const struct message test_updown_pos32_seq[] = { + { UDM_SETRANGE32, sent|lparam, 0, 1000 }, + { UDM_GETRANGE32, sent}, /* Cannot check wparam and lparam as they are ptrs */ + { UDM_SETPOS32, sent|lparam, 0, 500 }, + { UDM_GETPOS32, sent}, + { UDM_SETPOS32, sent|lparam, 0, 0 }, + { UDM_GETPOS32, sent}, + { UDM_SETPOS32, sent|lparam, 0, -1 }, + { UDM_GETPOS32, sent}, + { UDM_SETPOS32, sent|lparam, 0, 1000 }, + { UDM_GETPOS32, sent}, + { UDM_SETPOS32, sent|lparam, 0, 1001 }, + { UDM_GETPOS32, sent}, + { 0 } +}; + +static const struct message test_updown_buddy_seq[] = { + { UDM_GETBUDDY, sent }, + { UDM_SETBUDDY, sent }, + { WM_STYLECHANGING, sent|defwinproc }, + { WM_STYLECHANGED, sent|defwinproc }, + { WM_STYLECHANGING, sent|defwinproc }, + { WM_STYLECHANGED, sent|defwinproc }, + { WM_WINDOWPOSCHANGING, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam|optional|defwinproc, 1 }, + { WM_WINDOWPOSCHANGED, sent|defwinproc }, + { WM_MOVE, sent|defwinproc }, + { UDM_GETBUDDY, sent }, + { 0 } +}; + +static const struct message test_updown_base_seq[] = { + { UDM_SETBASE, sent|wparam, 10 }, + { UDM_GETBASE, sent }, + { UDM_SETBASE, sent|wparam, 80 }, + { UDM_GETBASE, sent }, + { UDM_SETBASE, sent|wparam, 16 }, + { UDM_GETBASE, sent }, + { UDM_SETBASE, sent|wparam, 80 }, + { UDM_GETBASE, sent }, + { UDM_SETBASE, sent|wparam, 10 }, + { UDM_GETBASE, sent }, + { 0 } +}; -static HDC desktopDC; -static HINSTANCE hinst; +static const struct message test_updown_unicode_seq[] = { + { UDM_SETUNICODEFORMAT, sent|wparam, 0 }, + { UDM_GETUNICODEFORMAT, sent }, + { UDM_SETUNICODEFORMAT, sent|wparam, 1 }, + { UDM_GETUNICODEFORMAT, sent }, + { UDM_SETUNICODEFORMAT, sent|wparam, 0 }, + { UDM_GETUNICODEFORMAT, sent }, + { 0 } +}; -static HWND create_edit_control (DWORD style, DWORD exstyle) +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}, + { 0 } +}; + +static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - HWND handle; - - handle = CreateWindowEx(exstyle, - "EDIT", - NULL, - ES_AUTOHSCROLL | ES_AUTOVSCROLL | style, - 10, 10, 300, 300, - NULL, NULL, hinst, NULL); - assert (handle); - if (winetest_interactive) - ShowWindow (handle, SW_SHOW); - return handle; + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + /* do not log painting messages */ + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, PARENT_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; } -static HWND create_updown_control (HWND hWndEdit) +static BOOL register_parent_wnd_class(void) { - HWND hWndUpDown; - - /* make the control */ - hWndUpDown = CreateWindowEx - (0L, UPDOWN_CLASS, NULL, - /* window styles */ - UDS_SETBUDDYINT | UDS_ALIGNRIGHT | - UDS_ARROWKEYS | UDS_NOTHOUSANDS, - /* placement */ - 0, 0, 8, 8, - /* parent, etc */ - NULL, NULL, hinst, NULL); - assert (hWndUpDown); - /* set the buddy. */ - SendMessage (hWndUpDown, UDM_SETBUDDY, (WPARAM)hWndEdit, 0L ); - /* set the range. */ - SendMessage (hWndUpDown, UDM_SETRANGE, 0L, (LPARAM) MAKELONG(32000, 0)); - /* maybe show it. */ - if (winetest_interactive) - ShowWindow (hWndUpDown, SW_SHOW); - return hWndUpDown; + 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, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "Up-Down test parent class"; + return RegisterClassA(&cls); } -static void test_updown_control (void) +static HWND create_parent_window(void) { - HWND hWndUpDown, hWndEdit; - int num; - - hWndEdit = create_edit_control (ES_AUTOHSCROLL | ES_NUMBER, 0); - hWndUpDown = create_updown_control (hWndEdit); - /* before we set a value, it should be '0' */ - num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L); - ok(num == 0, "Expected 0 got %d\n", num); - /* set a value, check it. */ - SendMessage(hWndUpDown, UDM_SETPOS, 0L, MAKELONG( 1, 0)); - num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L); - ok(num == 1, "Expected 1 got %d\n", num); - /* okay, done (short set of tests!) */ - DestroyWindow(hWndUpDown); - DestroyWindow(hWndEdit); + if (!register_parent_wnd_class()) + return NULL; + + return CreateWindowEx(0, "Up-Down test parent class", + "Up-Down test parent window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 0, 0, 100, 100, + GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); } -START_TEST(updown) +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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, EDIT_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND create_edit_control(void) +{ + struct subclass_info *info; + 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, + 0, 0, rect.right, rect.bottom, + parent_wnd, NULL, GetModuleHandleA(NULL), NULL); + if (!edit) + { + HeapFree(GetProcessHeap(), 0, info); + return NULL; + } + + info->oldproc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, + (LONG_PTR)edit_subclass_proc); + SetWindowLongPtrA(edit, GWLP_USERDATA, (LONG_PTR)info); + + return edit; +} + +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); + static long defwndproc_counter = 0; + LRESULT ret; + struct message msg; + + trace("updown: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + add_message(sequences, UPDOWN_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static HWND create_updown_control(void) +{ + struct subclass_info *info; + 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, + 100, 0, 50); + if (!updown) + { + HeapFree(GetProcessHeap(), 0, info); + return NULL; + } + + info->oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC, + (LONG_PTR)updown_subclass_proc); + SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)info); + + return updown; +} + +static void test_updown_pos(void) +{ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Set Range from 0 to 100 */ + SendMessage(updown, UDM_SETRANGE, 0 , MAKELONG(100,0) ); + r = SendMessage(updown, UDM_GETRANGE, 0,0); + expect(100,LOWORD(r)); + expect(0,HIWORD(r)); + + /* Set the position to 5, return is not checked as it was set before func call */ + SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(5,0) ); + /* Since UDM_SETBUDDYINT was not set at creation HIWORD(r) will always be 1 as a return from UDM_GETPOS */ + /* Get the position, which should be 5 */ + r = SendMessage(updown, UDM_GETPOS, 0 , 0 ); + expect(5,LOWORD(r)); + expect(1,HIWORD(r)); + + /* Set the position to 0, return should be 5 */ + r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(0,0) ); + expect(5,r); + /* Get the position, which should be 0 */ + r = SendMessage(updown, UDM_GETPOS, 0 , 0 ); + expect(0,LOWORD(r)); + expect(1,HIWORD(r)); + + /* Set the position to -1, return should be 0 */ + r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(-1,0) ); + expect(0,r); + /* Get the position, which should be 0 */ + r = SendMessage(updown, UDM_GETPOS, 0 , 0 ); + expect(0,LOWORD(r)); + expect(1,HIWORD(r)); + + /* Set the position to 100, return should be 0 */ + r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(100,0) ); + expect(0,r); + /* Get the position, which should be 100 */ + r = SendMessage(updown, UDM_GETPOS, 0 , 0 ); + expect(100,LOWORD(r)); + expect(1,HIWORD(r)); + + /* Set the position to 101, return should be 100 */ + r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(101,0) ); + expect(100,r); + /* Get the position, which should be 100 */ + r = SendMessage(updown, UDM_GETPOS, 0 , 0 ); + expect(100,LOWORD(r)); + expect(1,HIWORD(r)); + + ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE); +} + +static void test_updown_pos32(void) +{ + int r; + int low, high; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Set the position to 0 to 1000 */ + SendMessage(updown, UDM_SETRANGE32, 0 , 1000 ); + + r = SendMessage(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high ); + expect(0,low); + expect(1000,high); + + /* Set position to 500, don't check return since it is unset*/ + SendMessage(updown, UDM_SETPOS32, 0 , 500 ); + + /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */ + + r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); + expect(500,r); + expect(1,high); + + /* Set position to 0, return should be 500 */ + r = SendMessage(updown, UDM_SETPOS32, 0 , 0 ); + expect(500,r); + r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); + expect(0,r); + expect(1,high); + + /* Set position to -1 which should become 0, return should be 0 */ + r = SendMessage(updown, UDM_SETPOS32, 0 , -1 ); + expect(0,r); + r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); + expect(0,r); + expect(1,high); + + /* Set position to 1000, return should be 0 */ + r = SendMessage(updown, UDM_SETPOS32, 0 , 1000 ); + expect(0,r); + r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); + expect(1000,r); + expect(1,high); + + /* Set position to 1001 which should become 1000, return should be 1000 */ + r = SendMessage(updown, UDM_SETPOS32, 0 , 1001 ); + expect(1000,r); + r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); + expect(1000,r); + expect(1,high); + + ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE); +} + +static void test_updown_buddy(void) +{ + HWND buddyReturn; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 ); + ok(buddyReturn == 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_GETBUDDY, 0 , 0 ); + ok(buddyReturn == 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); +} + +static void test_updown_base(void) +{ + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + SendMessage(updown, UDM_SETBASE, 10 , 0); + r = SendMessage(updown, UDM_GETBASE, 0 , 0); + expect(10,r); + + /* Set base to an invalid value, should return 0 and stay at 10 */ + r = SendMessage(updown, UDM_SETBASE, 80 , 0); + expect(0,r); + r = SendMessage(updown, UDM_GETBASE, 0 , 0); + expect(10,r); + + /* Set base to 16 now, should get 16 as the return */ + r = SendMessage(updown, UDM_SETBASE, 16 , 0); + expect(10,r); + r = SendMessage(updown, UDM_GETBASE, 0 , 0); + expect(16,r); + + /* Set base to an invalid value, should return 0 and stay at 16 */ + r = SendMessage(updown, UDM_SETBASE, 80 , 0); + expect(0,r); + r = SendMessage(updown, UDM_GETBASE, 0 , 0); + expect(16,r); + + /* Set base back to 10, return should be 16 */ + r = SendMessage(updown, UDM_SETBASE, 10 , 0); + expect(16,r); + r = SendMessage(updown, UDM_GETBASE, 0 , 0); + expect(10,r); + + ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE); +} + +static void test_updown_unicode(void) { - desktopDC=GetDC(NULL); - hinst = GetModuleHandleA(NULL); + int r; + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Set it to ANSI, don't check return as we don't know previous state */ + SendMessage(updown, UDM_SETUNICODEFORMAT, 0 , 0); + r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0); + expect(0,r); + + /* Now set it to Unicode format */ + r = SendMessage(updown, UDM_SETUNICODEFORMAT, 1 , 0); + expect(0,r); + r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0); + expect(1,r); + + /* And now set it back to ANSI */ + r = SendMessage(updown, UDM_SETUNICODEFORMAT, 0 , 0); + expect(1,r); + r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0); + expect(0,r); + + ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE); +} + +static void test_create_updown_control(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); + + 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(); + 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); + 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); + + test_updown_pos(); + test_updown_pos32(); + test_updown_buddy(); + test_updown_base(); + test_updown_unicode(); +} + +START_TEST(updown) +{ InitCommonControls(); + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); - test_updown_control(); + test_create_updown_control(); }