https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0d320bc25fb266bee81257...
commit 0d320bc25fb266bee81257975cfd81c883fbc69d Author: Amine Khaldi amine.khaldi@reactos.org AuthorDate: Thu Jan 18 23:49:50 2018 +0100 Commit: Amine Khaldi amine.khaldi@reactos.org CommitDate: Thu Jan 18 23:49:50 2018 +0100
[COMCTL32_WINETEST] Sync with Wine 3.0. CORE-14225 --- modules/rostests/winetests/comctl32/CMakeLists.txt | 12 +- modules/rostests/winetests/comctl32/combo.c | 1194 ++++++++ modules/rostests/winetests/comctl32/comboex.c | 608 ---- modules/rostests/winetests/comctl32/edit.c | 3024 ++++++++++++++++++++ modules/rostests/winetests/comctl32/imagelist.c | 885 +++--- modules/rostests/winetests/comctl32/listbox.c | 1851 ++++++++++++ modules/rostests/winetests/comctl32/listview.c | 464 ++- modules/rostests/winetests/comctl32/misc.c | 2 +- modules/rostests/winetests/comctl32/msg.h | 7 +- modules/rostests/winetests/comctl32/propsheet.c | 32 +- modules/rostests/winetests/comctl32/rsrc.rc | 62 +- modules/rostests/winetests/comctl32/static.c | 168 ++ modules/rostests/winetests/comctl32/syslink.c | 114 +- modules/rostests/winetests/comctl32/taskdialog.c | 264 ++ modules/rostests/winetests/comctl32/testlist.c | 10 +- modules/rostests/winetests/comctl32/tooltips.c | 64 +- modules/rostests/winetests/comctl32/treeview.c | 5 + modules/rostests/winetests/comctl32/updown.c | 112 +- 18 files changed, 7661 insertions(+), 1217 deletions(-)
diff --git a/modules/rostests/winetests/comctl32/CMakeLists.txt b/modules/rostests/winetests/comctl32/CMakeLists.txt index f72f87a169..9212bc0fe1 100644 --- a/modules/rostests/winetests/comctl32/CMakeLists.txt +++ b/modules/rostests/winetests/comctl32/CMakeLists.txt @@ -1,16 +1,18 @@
remove_definitions(-D_WIN32_WINNT=0x502 -D_WIN32_IE=0x600)
-add_definitions(-DUSE_WINE_TODOS) +add_definitions(-DUSE_WINE_TODOS -DWINETEST_USE_DBGSTR_LONGLONG)
list(APPEND SOURCE animate.c - comboex.c + combo.c datetime.c dpa.c + edit.c header.c imagelist.c ipaddress.c + listbox.c listview.c misc.c monthcal.c @@ -19,6 +21,7 @@ list(APPEND SOURCE progress.c propsheet.c rebar.c + static.c status.c syslink.c tab.c @@ -43,5 +46,10 @@ endif()
set_module_type(comctl32_winetest win32cui) add_importlibs(comctl32_winetest comctl32 ole32 user32 gdi32 advapi32 msvcrt kernel32) + +if(MSVC) + add_importlibs(comctl32_winetest ntdll) +endif() + add_pch(comctl32_winetest precomp.h SOURCE) add_rostests_file(TARGET comctl32_winetest) diff --git a/modules/rostests/winetests/comctl32/combo.c b/modules/rostests/winetests/comctl32/combo.c new file mode 100644 index 0000000000..ca493c0cea --- /dev/null +++ b/modules/rostests/winetests/comctl32/combo.c @@ -0,0 +1,1194 @@ +/* Unit test suite for ComboBox and ComboBoxEx32 controls. + * + * Copyright 2005 Jason Edmeades + * 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 "precomp.h" + +#define EDITBOX_SEQ_INDEX 0 +#define NUM_MSG_SEQUENCES 1 + +#define EDITBOX_ID 0 +#define COMBO_ID 1995 + +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) + +#define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \ + r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \ + wine_dbgstr_rect(&r), _left, _top, _right, _bottom); + + +static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; + +static HWND hComboExParentWnd, hMainWnd; +static HINSTANCE hMainHinst; +static const char ComboExTestClass[] = "ComboExTestClass"; + +static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); + +#define MAX_CHARS 100 +static char *textBuffer = NULL; + +static BOOL received_end_edit = FALSE; + +static void get_combobox_info(HWND hwnd, COMBOBOXINFO *info) +{ + BOOL ret; + + info->cbSize = sizeof(*info); + ret = GetComboBoxInfo(hwnd, info); + ok(ret, "Failed to get combobox info structure, error %d\n", GetLastError()); +} + +static HWND createComboEx(DWORD style) { + return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300, + hComboExParentWnd, NULL, hMainHinst, NULL); +} + +static LONG addItem(HWND cbex, int idx, const char *text) { + COMBOBOXEXITEMA cbexItem; + memset(&cbexItem, 0x00, sizeof(cbexItem)); + cbexItem.mask = CBEIF_TEXT; + cbexItem.iItem = idx; + cbexItem.pszText = (char*)text; + cbexItem.cchTextMax = 0; + return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem); +} + +static LONG setItem(HWND cbex, int idx, const char *text) { + COMBOBOXEXITEMA cbexItem; + memset(&cbexItem, 0x00, sizeof(cbexItem)); + cbexItem.mask = CBEIF_TEXT; + cbexItem.iItem = idx; + cbexItem.pszText = (char*)text; + cbexItem.cchTextMax = 0; + return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem); +} + +static LONG delItem(HWND cbex, int idx) { + return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0); +} + +static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) { + memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA)); + cbItem->mask = CBEIF_TEXT; + cbItem->pszText = textBuffer; + cbItem->iItem = idx; + cbItem->cchTextMax = 100; + return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem); +} + +static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static LONG defwndproc_counter = 0; + struct message msg = { 0 }; + LRESULT ret; + + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + msg.id = EDITBOX_ID; + + if (message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCPAINT && + message != WM_NCHITTEST && + message != WM_GETTEXT && + message != WM_GETICON && + message != WM_DEVICECHANGE) + { + add_message(sequences, EDITBOX_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + return ret; +} + +static HWND subclass_editbox(HWND hwndComboEx) +{ + WNDPROC oldproc; + HWND hwnd; + + hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0); + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, + (LONG_PTR)editbox_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + return hwnd; +} + +static void test_comboex(void) +{ + HWND myHwnd = 0; + LONG res; + COMBOBOXEXITEMA cbexItem; + static const char *first_item = "First Item", + *second_item = "Second Item", + *third_item = "Third Item", + *middle_item = "Between First and Second Items", + *replacement_item = "Between First and Second Items", + *out_of_range_item = "Out of Range Item"; + + /* Allocate space for result */ + 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 (%d)\n", res); + res = addItem(myHwnd, -1, second_item); + ok(res == 1, "Adding simple item failed (%d)\n", res); + res = addItem(myHwnd, 2, third_item); + ok(res == 2, "Adding simple item failed (%d)\n", res); + res = addItem(myHwnd, 1, middle_item); + 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 (%d)\n", res); + res = addItem(myHwnd, 5, out_of_range_item); + 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 (%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 (%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 (%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 (%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 (%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 */ + res = setItem(myHwnd, 0, replacement_item); + ok(res != 0, "Setting first item failed (%d)\n", res); + res = setItem(myHwnd, 3, replacement_item); + 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 (%d)\n", res); + res = delItem(myHwnd, 4); + 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 (%d)\n", res); + res = delItem(myHwnd, 0); + 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 (%d)\n", res); + res = delItem(myHwnd, 0); + 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 (%d)\n", res); + + + /* Cleanup */ + HeapFree(GetProcessHeap(), 0, textBuffer); + DestroyWindow(myHwnd); +} + +static void test_comboex_WM_LBUTTONDOWN(void) +{ + HWND hComboEx, hCombo, hEdit, hList; + COMBOBOXINFO cbInfo; + UINT x, y, item_height; + LRESULT result; + UINT i; + int idx; + RECT rect; + WCHAR buffer[3]; + static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; + static const WCHAR stringFormat[] = {'%','2','d','\0'}; + + hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL, + WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150, + hComboExParentWnd, NULL, hMainHinst, NULL); + + for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){ + COMBOBOXEXITEMW cbexItem; + wsprintfW(buffer, stringFormat, choices[i]); + + memset(&cbexItem, 0x00, sizeof(cbexItem)); + cbexItem.mask = CBEIF_TEXT; + cbexItem.iItem = i; + cbexItem.pszText = buffer; + cbexItem.cchTextMax = 0; + ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0, + "Failed to add item %d\n", i); + } + + hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); + hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); + + get_combobox_info(hCombo, &cbInfo); + hList = cbInfo.hwndList; + + ok(GetFocus() == hComboExParentWnd, + "Focus not on Main Window, instead on %p\n", GetFocus()); + + /* Click on the button to drop down the list */ + x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; + y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; + result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should have appeared after clicking the button.\n"); + idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0); + ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx); + + result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + + /* Click on the 5th item in the list */ + item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0); + ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n"); + x = rect.left + (rect.right-rect.left)/2; + y = item_height/2 + item_height*4; + result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); + ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + + result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should still be visible.\n"); + + result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + todo_wine ok(GetFocus() == hEdit || + broken(GetFocus() == hCombo), /* win98 */ + "Focus not on ComboBoxEx's Edit Control, instead on %p\n", + GetFocus()); + + result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0); + ok(!result || + broken(result != 0), /* win98 */ + "The dropdown list should have been rolled up.\n"); + idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0); + ok(idx == 4 || + broken(idx == -1), /* win98 */ + "Current Selection: expected %d, got %d\n", 4, idx); + ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n"); + + SetFocus( hComboExParentWnd ); + ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() ); + SetFocus( hComboEx ); + ok( GetFocus() == hEdit, "got %p\n", GetFocus() ); + + DestroyWindow(hComboEx); +} + +static void test_comboex_CB_GETLBTEXT(void) +{ + HWND hCombo; + CHAR buff[1]; + COMBOBOXEXITEMA item; + LRESULT ret; + + hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + /* set text to null */ + addItem(hCombo, 0, NULL); + + buff[0] = 'a'; + item.mask = CBEIF_TEXT; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = 1; + ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item); + ok(ret != 0, "CBEM_GETITEM failed\n"); + ok(buff[0] == 0, "\n"); + + ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); + ok(ret == 0, "Expected zero length\n"); + + ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); + ok(ret == 0, "Expected zero length\n"); + + buff[0] = 'a'; + ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff); + ok(ret == 0, "Expected zero length\n"); + ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff); + + DestroyWindow(hCombo); +} + +static void test_comboex_WM_WINDOWPOSCHANGING(void) +{ + HWND hCombo; + WINDOWPOS wp; + RECT rect; + int combo_height; + int ret; + + hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + ok(hCombo != NULL, "createComboEx failed\n"); + ret = GetWindowRect(hCombo, &rect); + ok(ret, "GetWindowRect failed\n"); + combo_height = rect.bottom - rect.top; + ok(combo_height > 0, "wrong combo height\n"); + + /* Test height > combo_height */ + wp.x = rect.left; + wp.y = rect.top; + wp.cx = (rect.right - rect.left); + wp.cy = combo_height * 2; + wp.flags = 0; + wp.hwnd = hCombo; + wp.hwndInsertAfter = NULL; + + ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); + ok(ret == 0, "expected 0, got %x\n", ret); + ok(wp.cy == combo_height, + "Expected height %d, got %d\n", combo_height, wp.cy); + + /* Test height < combo_height */ + wp.x = rect.left; + wp.y = rect.top; + wp.cx = (rect.right - rect.left); + wp.cy = combo_height / 2; + wp.flags = 0; + wp.hwnd = hCombo; + wp.hwndInsertAfter = NULL; + + ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); + ok(ret == 0, "expected 0, got %x\n", ret); + ok(wp.cy == combo_height, + "Expected height %d, got %d\n", combo_height, wp.cy); + + ret = DestroyWindow(hCombo); + ok(ret, "DestroyWindow failed\n"); +} + +static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + NMHDR *hdr = (NMHDR*)lParam; + switch(hdr->code){ + case CBEN_ENDEDITA: + { + NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr; + if(edit_info->iWhy==CBENF_DROPDOWN){ + received_end_edit = TRUE; + } + break; + } + case CBEN_ENDEDITW: + { + NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr; + if(edit_info->iWhy==CBENF_DROPDOWN){ + received_end_edit = TRUE; + } + break; + } + } + return 0; +} + +static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_NOTIFY: + return ComboExTestOnNotify(hWnd,msg,wParam,lParam); + default: + return DefWindowProcA(hWnd, msg, wParam, lParam); + } + + return 0L; +} + +static BOOL init(void) +{ + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + WNDCLASSA wc; + INITCOMMONCONTROLSEX iccex; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + win_skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return FALSE; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_USEREX_CLASSES; + pInitCommonControlsEx(&iccex); + + pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410); + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandleA(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszMenuName = NULL; + wc.lpszClassName = ComboExTestClass; + wc.lpfnWndProc = ComboExTestWndProc; + RegisterClassA(&wc); + + hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); + ShowWindow(hMainWnd, SW_SHOW); + + hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); + ok(hComboExParentWnd != NULL, "failed to create parent window\n"); + + hMainHinst = GetModuleHandleA(NULL); + + return hComboExParentWnd != NULL; +} + +static void cleanup(void) +{ + MSG msg; + + PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0); + while (GetMessageA(&msg,0,0,0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + DestroyWindow(hComboExParentWnd); + UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); + + DestroyWindow(hMainWnd); +} + +static void test_comboex_subclass(void) +{ + HWND hComboEx, hCombo, hEdit; + + hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); + ok(hCombo != NULL, "Failed to get internal combo\n"); + hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); + ok(hEdit != NULL, "Failed to get internal edit\n"); + + if (pSetWindowSubclass) + { + ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); + ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); + } + + DestroyWindow(hComboEx); +} + +static const struct message test_setitem_edit_seq[] = { + { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID }, + { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID }, + { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID }, + { 0 } +}; + +static void test_comboex_get_set_item(void) +{ + char textA[] = "test"; + HWND hComboEx; + COMBOBOXEXITEMA item; + BOOL ret; + + hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); + + subclass_editbox(hComboEx); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.mask = CBEIF_TEXT; + item.pszText = textA; + item.iItem = -1; + ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + + ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE); + + /* get/set lParam */ + item.mask = CBEIF_LPARAM; + item.iItem = -1; + item.lParam = 0xdeadbeef; + ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam); + + item.lParam = 0x1abe11ed; + ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + + item.lParam = 0; + ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); + expect(TRUE, ret); + ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam); + + DestroyWindow(hComboEx); +} + +static HWND create_combobox(DWORD style) +{ + return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0); +} + +static int font_height(HFONT hFont) +{ + TEXTMETRICA tm; + HFONT hFontOld; + HDC hDC; + + hDC = CreateCompatibleDC(NULL); + hFontOld = SelectObject(hDC, hFont); + GetTextMetricsA(hDC, &tm); + SelectObject(hDC, hFontOld); + DeleteDC(hDC); + + return tm.tmHeight; +} + +static void test_combo_setitemheight(DWORD style) +{ + HWND hCombo = create_combobox(style); + RECT r; + int i; + + GetClientRect(hCombo, &r); + expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + todo_wine expect_rect(r, 5, 5, 105, 105); + + for (i = 1; i < 30; i++) + { + SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, i); + GetClientRect(hCombo, &r); + ok((r.bottom - r.top) == (i + 6), "Unexpected client rect height.\n"); + } + + DestroyWindow(hCombo); +} + +static void test_combo_setfont(DWORD style) +{ + HFONT hFont1, hFont2; + HWND hCombo; + RECT r; + int i; + + hCombo = create_combobox(style); + hFont1 = CreateFontA(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + hFont2 = CreateFontA(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + + GetClientRect(hCombo, &r); + expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + todo_wine expect_rect(r, 5, 5, 105, 105); + + /* The size of the dropped control is initially equal to the size + of the window when it was created. The size of the calculated + dropped area changes only by how much the selection area + changes, not by how much the list area changes. */ + if (font_height(hFont1) == 10 && font_height(hFont2) == 8) + { + SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); + GetClientRect(hCombo, &r); + expect_rect(r, 0, 0, 100, 18); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); + + SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE); + GetClientRect(hCombo, &r); + expect_rect(r, 0, 0, 100, 16); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont2))); + + SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); + GetClientRect(hCombo, &r); + expect_rect(r, 0, 0, 100, 18); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); + MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); + } + else + { + ok(0, "Expected Marlett font heights 10/8, got %d/%d\n", + font_height(hFont1), font_height(hFont2)); + } + + for (i = 1; i < 30; i++) + { + HFONT hFont = CreateFontA(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + int height = font_height(hFont); + + SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE); + GetClientRect(hCombo, &r); + ok((r.bottom - r.top) == (height + 8), "Unexpected client rect height.\n"); + SendMessageA(hCombo, WM_SETFONT, 0, FALSE); + DeleteObject(hFont); + } + + DestroyWindow(hCombo); + DeleteObject(hFont1); + DeleteObject(hFont2); +} + +static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +static LPCSTR expected_edit_text; +static LPCSTR expected_list_text; +static BOOL selchange_fired; + +static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_COMMAND: + switch (wparam) + { + case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE): + { + HWND hCombo = (HWND)lparam; + char list[20], edit[20]; + int idx; + + memset(list, 0, sizeof(list)); + memset(edit, 0, sizeof(edit)); + + idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0); + SendMessageA(hCombo, CB_GETLBTEXT, idx, (LPARAM)list); + SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); + + ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n", + edit, expected_edit_text); + ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n", + list, expected_list_text); + + selchange_fired = TRUE; + } + break; + } + break; + } + + return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam); +} + +static void test_selection(DWORD style, const char * const text[], const int *edit, const int *list) +{ + HWND hCombo; + INT idx; + + hCombo = create_combobox(style); + + SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]); + SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]); + SendMessageA(hCombo, CB_SETCURSEL, -1, 0); + + old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc); + + idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0); + ok(idx == -1, "expected selection -1, got %d\n", idx); + + /* keyboard navigation */ + + expected_list_text = text[list[0]]; + expected_edit_text = text[edit[0]]; + selchange_fired = FALSE; + SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0); + ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); + + expected_list_text = text[list[1]]; + expected_edit_text = text[edit[1]]; + selchange_fired = FALSE; + SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0); + ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); + + expected_list_text = text[list[2]]; + expected_edit_text = text[edit[2]]; + selchange_fired = FALSE; + SendMessageA(hCombo, WM_KEYDOWN, VK_UP, 0); + ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); + + /* programmatic navigation */ + + expected_list_text = text[list[3]]; + expected_edit_text = text[edit[3]]; + selchange_fired = FALSE; + SendMessageA(hCombo, CB_SETCURSEL, list[3], 0); + ok(!selchange_fired, "CBN_SELCHANGE sent!\n"); + + expected_list_text = text[list[4]]; + expected_edit_text = text[edit[4]]; + selchange_fired = FALSE; + SendMessageA(hCombo, CB_SETCURSEL, list[4], 0); + ok(!selchange_fired, "CBN_SELCHANGE sent!\n"); + + SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc); + DestroyWindow(hCombo); +} + +static void test_combo_CBN_SELCHANGE(void) +{ + static const char * const text[] = { "alpha", "beta", "" }; + static const int sel_1[] = { 2, 0, 1, 0, 1 }; + static const int sel_2[] = { 0, 1, 0, 0, 1 }; + + test_selection(CBS_SIMPLE, text, sel_1, sel_2); + test_selection(CBS_DROPDOWN, text, sel_1, sel_2); + test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2); +} + +static void test_combo_changesize(DWORD style) +{ + INT ddheight, clheight, ddwidth, clwidth; + HWND hCombo; + RECT rc; + + hCombo = create_combobox(style); + + /* get initial measurements */ + GetClientRect( hCombo, &rc); + clheight = rc.bottom - rc.top; + clwidth = rc.right - rc.left; + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ddheight = rc.bottom - rc.top; + ddwidth = rc.right - rc.left; + /* use MoveWindow to move & resize the combo */ + /* first make it slightly smaller */ + MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE); + GetClientRect( hCombo, &rc); + ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n", + rc.right - rc.left, clwidth - 2); + ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + rc.bottom - rc.top, clheight); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n", + rc.right - rc.left, clwidth - 2); + ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n", + rc.bottom - rc.top, ddheight); + ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n", + rc.right - rc.left, ddwidth - 2); + /* new cx, cy is slightly bigger than the initial values */ + MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE); + GetClientRect( hCombo, &rc); + ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n", + rc.right - rc.left, clwidth + 2); + ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + rc.bottom - rc.top, clheight); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n", + rc.right - rc.left, clwidth + 2); + todo_wine { + ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n", + rc.bottom - rc.top, clheight + 2); + } + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0); + ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0); + ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); + + ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); + ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); + + DestroyWindow(hCombo); +} + +static void test_combo_editselection(void) +{ + COMBOBOXINFO cbInfo; + INT start, end; + char edit[20]; + HWND hCombo; + HWND hEdit; + DWORD len; + + /* Build a combo */ + hCombo = create_combobox(CBS_SIMPLE); + + get_combobox_info(hCombo, &cbInfo); + hEdit = cbInfo.hwndItem; + + /* Initially combo selection is empty*/ + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); + + /* Set some text, and press a key to replace it */ + edit[0] = 0x00; + SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1"); + SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); + ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit); + + /* Now what is the selection - still empty */ + SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); + ok(start==0, "Unexpected start position for selection %d\n", start); + ok(end==0, "Unexpected end position for selection %d\n", end); + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); + + /* Give it focus, and it gets selected */ + SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); + SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); + ok(start==0, "Unexpected start position for selection %d\n", start); + ok(end==6, "Unexpected end position for selection %d\n", end); + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len)); + + /* Now emulate a key press */ + edit[0] = 0x00; + SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001); + SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); + ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit); + + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len)); + + /* Now what happens when it gets more focus a second time - it doesn't reselect */ + SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len)); + DestroyWindow(hCombo); + + /* Start again - Build a combo */ + hCombo = create_combobox(CBS_SIMPLE); + get_combobox_info(hCombo, &cbInfo); + hEdit = cbInfo.hwndItem; + + /* Set some text and give focus so it gets selected */ + edit[0] = 0x00; + SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2"); + SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); + ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit); + + SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); + + /* Now what is the selection */ + SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); + ok(start==0, "Unexpected start position for selection %d\n", start); + ok(end==6, "Unexpected end position for selection %d\n", end); + len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len)); + + /* Now change the selection to the apparently invalid start -1, end -1 and + show it means no selection (ie start -1) but cursor at end */ + SendMessageA(hCombo, CB_SETEDITSEL, 0, -1); + edit[0] = 0x00; + SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001); + SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); + ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit); + DestroyWindow(hCombo); +} + +static WNDPROC edit_window_proc; +static long setsel_start = 1, setsel_end = 1; +static HWND hCBN_SetFocus, hCBN_KillFocus; + +static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == EM_SETSEL) + { + setsel_start = wParam; + setsel_end = lParam; + } + return CallWindowProcA(edit_window_proc, hwnd, msg, wParam, lParam); +} + +static LRESULT CALLBACK test_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case CBN_SETFOCUS: + hCBN_SetFocus = (HWND)lParam; + break; + case CBN_KILLFOCUS: + hCBN_KillFocus = (HWND)lParam; + break; + } + break; + case WM_NEXTDLGCTL: + SetFocus((HWND)wParam); + break; + } + return CallWindowProcA(old_parent_proc, hwnd, msg, wParam, lParam); +} + +static void test_combo_editselection_focus(DWORD style) +{ + static const char wine_test[] = "Wine Test"; + HWND hCombo, hEdit, hButton; + char buffer[16] = {0}; + COMBOBOXINFO cbInfo; + DWORD len; + + hCombo = create_combobox(style); + get_combobox_info(hCombo, &cbInfo); + hEdit = cbInfo.hwndItem; + + hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, + 5, 50, 100, 20, hMainWnd, NULL, + (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL); + + old_parent_proc = (WNDPROC)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)test_window_proc); + edit_window_proc = (WNDPROC)SetWindowLongPtrA(hEdit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc); + + SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); + ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); + todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); + ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus); + ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n"); + + SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE); + ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); + todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); + ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus); + ok(GetFocus() == hButton, "hButton should have keyboard focus\n"); + + SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)wine_test); + SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hCombo, TRUE); + ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); + todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); + ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus); + ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n"); + SendMessageA(hCombo, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); + ok(!strcmp(buffer, wine_test), "Unexpected text in edit control; got '%s'\n", buffer); + + SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE); + ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); + todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); + ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus); + ok(GetFocus() == hButton, "hButton should have keyboard focus\n"); + len = SendMessageA(hCombo, CB_GETEDITSEL, 0, 0); + ok(len == 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len), HIWORD(len)); + + SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc); + DestroyWindow(hButton); + DestroyWindow(hCombo); +} + +static void test_combo_listbox_styles(DWORD cb_style) +{ + DWORD style, exstyle, expect_style, expect_exstyle; + COMBOBOXINFO info; + HWND combo; + + expect_style = WS_CHILD|WS_CLIPSIBLINGS|LBS_COMBOBOX|LBS_HASSTRINGS|LBS_NOTIFY; + if (cb_style == CBS_SIMPLE) + { + expect_style |= WS_VISIBLE; + expect_exstyle = WS_EX_CLIENTEDGE; + } + else + { + expect_style |= WS_BORDER; + expect_exstyle = WS_EX_TOOLWINDOW; + } + + combo = create_combobox(cb_style); + get_combobox_info(combo, &info); + + style = GetWindowLongW( info.hwndList, GWL_STYLE ); + exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); + ok(style == expect_style, "%08x: got %08x\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + + if (cb_style != CBS_SIMPLE) + expect_exstyle |= WS_EX_TOPMOST; + + SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 ); + style = GetWindowLongW( info.hwndList, GWL_STYLE ); + exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); + ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + + SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 ); + style = GetWindowLongW( info.hwndList, GWL_STYLE ); + exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); + ok(style == expect_style, "%08x: got %08x\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + + DestroyWindow(combo); +} + +static void test_combo_WS_VSCROLL(void) +{ + HWND hCombo, hList; + COMBOBOXINFO info; + DWORD style; + int i; + + hCombo = create_combobox(CBS_DROPDOWNLIST); + + get_combobox_info(hCombo, &info); + hList = info.hwndList; + + for (i = 0; i < 3; i++) + { + char buffer[2]; + sprintf(buffer, "%d", i); + SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer); + } + + style = GetWindowLongA(info.hwndList, GWL_STYLE); + SetWindowLongA(hList, GWL_STYLE, style | WS_VSCROLL); + + SendMessageA(hCombo, CB_SHOWDROPDOWN, TRUE, 0); + SendMessageA(hCombo, CB_SHOWDROPDOWN, FALSE, 0); + + style = GetWindowLongA(hList, GWL_STYLE); + ok((style & WS_VSCROLL) != 0, "Style does not include WS_VSCROLL\n"); + + DestroyWindow(hCombo); +} + +START_TEST(combo) +{ + ULONG_PTR ctx_cookie; + HANDLE hCtx; + + if (!init()) + return; + + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + + /* ComboBoxEx32 tests. */ + test_comboex(); + test_comboex_WM_LBUTTONDOWN(); + test_comboex_CB_GETLBTEXT(); + test_comboex_WM_WINDOWPOSCHANGING(); + test_comboex_subclass(); + test_comboex_get_set_item(); + + if (!load_v6_module(&ctx_cookie, &hCtx)) + { + cleanup(); + return; + } + + /* ComboBox control tests. */ + test_combo_WS_VSCROLL(); + test_combo_setfont(CBS_DROPDOWN); + test_combo_setfont(CBS_DROPDOWNLIST); + test_combo_setitemheight(CBS_DROPDOWN); + test_combo_setitemheight(CBS_DROPDOWNLIST); + test_combo_CBN_SELCHANGE(); + test_combo_changesize(CBS_DROPDOWN); + test_combo_changesize(CBS_DROPDOWNLIST); + test_combo_editselection(); + test_combo_editselection_focus(CBS_SIMPLE); + test_combo_editselection_focus(CBS_DROPDOWN); + test_combo_listbox_styles(CBS_SIMPLE); + test_combo_listbox_styles(CBS_DROPDOWN); + test_combo_listbox_styles(CBS_DROPDOWNLIST); + + cleanup(); + unload_v6_module(ctx_cookie, hCtx); +} diff --git a/modules/rostests/winetests/comctl32/comboex.c b/modules/rostests/winetests/comctl32/comboex.c deleted file mode 100644 index 947a871a6b..0000000000 --- a/modules/rostests/winetests/comctl32/comboex.c +++ /dev/null @@ -1,608 +0,0 @@ -/* Unit test suite for comboex control. - * - * Copyright 2005 Jason Edmeades - * - * 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 "precomp.h" - -#define EDITBOX_SEQ_INDEX 0 -#define NUM_MSG_SEQUENCES 1 - -#define EDITBOX_ID 0 - -#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) - -static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; - -static HWND hComboExParentWnd; -static HINSTANCE hMainHinst; -static const char ComboExTestClass[] = "ComboExTestClass"; - -static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); - -#define MAX_CHARS 100 -static char *textBuffer = NULL; - -static BOOL received_end_edit = FALSE; - -static HWND createComboEx(DWORD style) { - return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300, - hComboExParentWnd, NULL, hMainHinst, NULL); -} - -static LONG addItem(HWND cbex, int idx, const char *text) { - COMBOBOXEXITEMA cbexItem; - memset(&cbexItem, 0x00, sizeof(cbexItem)); - cbexItem.mask = CBEIF_TEXT; - cbexItem.iItem = idx; - cbexItem.pszText = (char*)text; - cbexItem.cchTextMax = 0; - return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem); -} - -static LONG setItem(HWND cbex, int idx, const char *text) { - COMBOBOXEXITEMA cbexItem; - memset(&cbexItem, 0x00, sizeof(cbexItem)); - cbexItem.mask = CBEIF_TEXT; - cbexItem.iItem = idx; - cbexItem.pszText = (char*)text; - cbexItem.cchTextMax = 0; - return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem); -} - -static LONG delItem(HWND cbex, int idx) { - return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0); -} - -static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) { - memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA)); - cbItem->mask = CBEIF_TEXT; - cbItem->pszText = textBuffer; - cbItem->iItem = idx; - cbItem->cchTextMax = 100; - return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem); -} - -static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static LONG defwndproc_counter = 0; - struct message msg = { 0 }; - LRESULT ret; - - msg.message = message; - msg.flags = sent|wparam|lparam; - if (defwndproc_counter) msg.flags |= defwinproc; - msg.wParam = wParam; - msg.lParam = lParam; - msg.id = EDITBOX_ID; - - if (message != WM_PAINT && - message != WM_ERASEBKGND && - message != WM_NCPAINT && - message != WM_NCHITTEST && - message != WM_GETTEXT && - message != WM_GETICON && - message != WM_DEVICECHANGE) - { - add_message(sequences, EDITBOX_SEQ_INDEX, &msg); - } - - defwndproc_counter++; - ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); - defwndproc_counter--; - return ret; -} - -static HWND subclass_editbox(HWND hwndComboEx) -{ - WNDPROC oldproc; - HWND hwnd; - - hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0); - oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, - (LONG_PTR)editbox_subclass_proc); - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); - - return hwnd; -} - -static void test_comboboxex(void) { - HWND myHwnd = 0; - LONG res; - COMBOBOXEXITEMA cbexItem; - static const char *first_item = "First Item", - *second_item = "Second Item", - *third_item = "Third Item", - *middle_item = "Between First and Second Items", - *replacement_item = "Between First and Second Items", - *out_of_range_item = "Out of Range Item"; - - /* Allocate space for result */ - 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 (%d)\n", res); - res = addItem(myHwnd, -1, second_item); - ok(res == 1, "Adding simple item failed (%d)\n", res); - res = addItem(myHwnd, 2, third_item); - ok(res == 2, "Adding simple item failed (%d)\n", res); - res = addItem(myHwnd, 1, middle_item); - 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 (%d)\n", res); - res = addItem(myHwnd, 5, out_of_range_item); - 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 (%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 (%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 (%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 (%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 (%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 */ - res = setItem(myHwnd, 0, replacement_item); - ok(res != 0, "Setting first item failed (%d)\n", res); - res = setItem(myHwnd, 3, replacement_item); - 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 (%d)\n", res); - res = delItem(myHwnd, 4); - 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 (%d)\n", res); - res = delItem(myHwnd, 0); - 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 (%d)\n", res); - res = delItem(myHwnd, 0); - 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 (%d)\n", res); - - - /* Cleanup */ - HeapFree(GetProcessHeap(), 0, textBuffer); - DestroyWindow(myHwnd); -} - -static void test_WM_LBUTTONDOWN(void) -{ - HWND hComboEx, hCombo, hEdit, hList; - COMBOBOXINFO cbInfo; - UINT x, y, item_height; - LRESULT result; - UINT i; - int idx; - RECT rect; - WCHAR buffer[3]; - static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; - static const WCHAR stringFormat[] = {'%','2','d','\0'}; - BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO); - - pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo"); - if (!pGetComboBoxInfo){ - win_skip("GetComboBoxInfo is not available\n"); - return; - } - - hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL, - WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150, - hComboExParentWnd, NULL, hMainHinst, NULL); - - for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){ - COMBOBOXEXITEMW cbexItem; - wsprintfW(buffer, stringFormat, choices[i]); - - memset(&cbexItem, 0x00, sizeof(cbexItem)); - cbexItem.mask = CBEIF_TEXT; - cbexItem.iItem = i; - cbexItem.pszText = buffer; - cbexItem.cchTextMax = 0; - ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0, - "Failed to add item %d\n", i); - } - - hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); - hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); - - cbInfo.cbSize = sizeof(COMBOBOXINFO); - result = pGetComboBoxInfo(hCombo, &cbInfo); - ok(result, "Failed to get combobox info structure. LastError=%d\n", - GetLastError()); - hList = cbInfo.hwndList; - - ok(GetFocus() == hComboExParentWnd, - "Focus not on Main Window, instead on %p\n", GetFocus()); - - /* Click on the button to drop down the list */ - x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; - y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; - result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); - ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", - GetLastError()); - ok(GetFocus() == hCombo || - broken(GetFocus() != hCombo), /* win98 */ - "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", - GetFocus()); - ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), - "The dropdown list should have appeared after clicking the button.\n"); - idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0); - ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx); - - result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); - ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", - GetLastError()); - ok(GetFocus() == hCombo || - broken(GetFocus() != hCombo), /* win98 */ - "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", - GetFocus()); - - /* Click on the 5th item in the list */ - item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0); - ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n"); - x = rect.left + (rect.right-rect.left)/2; - y = item_height/2 + item_height*4; - result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); - ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", - GetLastError()); - ok(GetFocus() == hCombo || - broken(GetFocus() != hCombo), /* win98 */ - "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", - GetFocus()); - - result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); - ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", - GetLastError()); - ok(GetFocus() == hCombo || - broken(GetFocus() != hCombo), /* win98 */ - "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", - GetFocus()); - ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), - "The dropdown list should still be visible.\n"); - - result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); - ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", - GetLastError()); - todo_wine ok(GetFocus() == hEdit || - broken(GetFocus() == hCombo), /* win98 */ - "Focus not on ComboBoxEx's Edit Control, instead on %p\n", - GetFocus()); - - result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0); - ok(!result || - broken(result != 0), /* win98 */ - "The dropdown list should have been rolled up.\n"); - idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0); - ok(idx == 4 || - broken(idx == -1), /* win98 */ - "Current Selection: expected %d, got %d\n", 4, idx); - ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n"); - - SetFocus( hComboExParentWnd ); - ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() ); - SetFocus( hComboEx ); - ok( GetFocus() == hEdit, "got %p\n", GetFocus() ); - - DestroyWindow(hComboEx); -} - -static void test_CB_GETLBTEXT(void) -{ - HWND hCombo; - CHAR buff[1]; - COMBOBOXEXITEMA item; - LRESULT ret; - - hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); - - /* set text to null */ - addItem(hCombo, 0, NULL); - - buff[0] = 'a'; - item.mask = CBEIF_TEXT; - item.iItem = 0; - item.pszText = buff; - item.cchTextMax = 1; - ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item); - ok(ret != 0, "CBEM_GETITEM failed\n"); - ok(buff[0] == 0, "\n"); - - ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); - ok(ret == 0, "Expected zero length\n"); - - ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); - ok(ret == 0, "Expected zero length\n"); - - buff[0] = 'a'; - ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff); - ok(ret == 0, "Expected zero length\n"); - ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff); - - DestroyWindow(hCombo); -} - -static void test_WM_WINDOWPOSCHANGING(void) -{ - HWND hCombo; - WINDOWPOS wp; - RECT rect; - int combo_height; - int ret; - - hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); - ok(hCombo != NULL, "createComboEx failed\n"); - ret = GetWindowRect(hCombo, &rect); - ok(ret, "GetWindowRect failed\n"); - combo_height = rect.bottom - rect.top; - ok(combo_height > 0, "wrong combo height\n"); - - /* Test height > combo_height */ - wp.x = rect.left; - wp.y = rect.top; - wp.cx = (rect.right - rect.left); - wp.cy = combo_height * 2; - wp.flags = 0; - wp.hwnd = hCombo; - wp.hwndInsertAfter = NULL; - - ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); - ok(ret == 0, "expected 0, got %x\n", ret); - ok(wp.cy == combo_height, - "Expected height %d, got %d\n", combo_height, wp.cy); - - /* Test height < combo_height */ - wp.x = rect.left; - wp.y = rect.top; - wp.cx = (rect.right - rect.left); - wp.cy = combo_height / 2; - wp.flags = 0; - wp.hwnd = hCombo; - wp.hwndInsertAfter = NULL; - - ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); - ok(ret == 0, "expected 0, got %x\n", ret); - ok(wp.cy == combo_height, - "Expected height %d, got %d\n", combo_height, wp.cy); - - ret = DestroyWindow(hCombo); - ok(ret, "DestroyWindow failed\n"); -} - -static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - NMHDR *hdr = (NMHDR*)lParam; - switch(hdr->code){ - case CBEN_ENDEDITA: - { - NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr; - if(edit_info->iWhy==CBENF_DROPDOWN){ - received_end_edit = TRUE; - } - break; - } - case CBEN_ENDEDITW: - { - NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr; - if(edit_info->iWhy==CBENF_DROPDOWN){ - received_end_edit = TRUE; - } - break; - } - } - return 0; -} - -static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch(msg) { - - case WM_DESTROY: - PostQuitMessage(0); - break; - case WM_NOTIFY: - return ComboExTestOnNotify(hWnd,msg,wParam,lParam); - default: - return DefWindowProcA(hWnd, msg, wParam, lParam); - } - - return 0L; -} - -static BOOL init(void) -{ - HMODULE hComctl32; - BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); - WNDCLASSA wc; - INITCOMMONCONTROLSEX iccex; - - hComctl32 = GetModuleHandleA("comctl32.dll"); - pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); - if (!pInitCommonControlsEx) - { - win_skip("InitCommonControlsEx() is missing. Skipping the tests\n"); - return FALSE; - } - iccex.dwSize = sizeof(iccex); - iccex.dwICC = ICC_USEREX_CLASSES; - pInitCommonControlsEx(&iccex); - - pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410); - - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandleA(NULL); - wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, (LPCSTR)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|WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); - ok(hComboExParentWnd != NULL, "failed to create parent window\n"); - - hMainHinst = GetModuleHandleA(NULL); - - return hComboExParentWnd != NULL; -} - -static void cleanup(void) -{ - MSG msg; - - PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0); - while (GetMessageA(&msg,0,0,0)) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - - DestroyWindow(hComboExParentWnd); - UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); -} - -static void test_comboboxex_subclass(void) -{ - HWND hComboEx, hCombo, hEdit; - - hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); - - hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); - ok(hCombo != NULL, "Failed to get internal combo\n"); - hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); - ok(hEdit != NULL, "Failed to get internal edit\n"); - - if (pSetWindowSubclass) - { - ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); - ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); - } - - DestroyWindow(hComboEx); -} - -static const struct message test_setitem_edit_seq[] = { - { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID }, - { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID }, - { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID }, - { 0 } -}; - -static void test_get_set_item(void) -{ - char textA[] = "test"; - HWND hComboEx; - COMBOBOXEXITEMA item; - BOOL ret; - - hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); - - subclass_editbox(hComboEx); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - memset(&item, 0, sizeof(item)); - item.mask = CBEIF_TEXT; - item.pszText = textA; - item.iItem = -1; - ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); - expect(TRUE, ret); - - ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE); - - /* get/set lParam */ - item.mask = CBEIF_LPARAM; - item.iItem = -1; - item.lParam = 0xdeadbeef; - ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); - expect(TRUE, ret); - ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam); - - item.lParam = 0x1abe11ed; - ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); - expect(TRUE, ret); - - item.lParam = 0; - ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); - expect(TRUE, ret); - ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam); - - DestroyWindow(hComboEx); -} - -START_TEST(comboex) -{ - if (!init()) - return; - - init_msg_sequences(sequences, NUM_MSG_SEQUENCES); - - test_comboboxex(); - test_WM_LBUTTONDOWN(); - test_CB_GETLBTEXT(); - test_WM_WINDOWPOSCHANGING(); - test_comboboxex_subclass(); - test_get_set_item(); - - cleanup(); -} diff --git a/modules/rostests/winetests/comctl32/edit.c b/modules/rostests/winetests/comctl32/edit.c new file mode 100644 index 0000000000..47196245a4 --- /dev/null +++ b/modules/rostests/winetests/comctl32/edit.c @@ -0,0 +1,3024 @@ +/* Unit test suite for edit control. + * + * Copyright 2004 Vitaliy Margolen + * Copyright 2005 C. Scott Ananian + * + * 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 "precomp.h" + +#ifndef ES_COMBO +#define ES_COMBO 0x200 +#endif + +#define ID_EDITTESTDBUTTON 0x123 +#define ID_EDITTEST2 99 +#define MAXLEN 200 + +struct edit_notify { + int en_change, en_maxtext, en_update; +}; + +static struct edit_notify notifications; + +static INT_PTR CALLBACK multi_edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + static int num_ok_commands = 0; + switch (msg) + { + case WM_INITDIALOG: + { + HWND hedit = GetDlgItem(hdlg, 1000); + SetFocus(hedit); + switch (lparam) + { + /* test cases related to bug 12319 */ + case 0: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 1: + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 2: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + + /* test cases for pressing enter */ + case 3: + num_ok_commands = 0; + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + default: + break; + } + break; + } + + case WM_COMMAND: + if (HIWORD(wparam) != BN_CLICKED) + break; + + switch (LOWORD(wparam)) + { + case IDOK: + num_ok_commands++; + break; + + default: + break; + } + break; + + case WM_USER: + { + HWND hfocus = GetFocus(); + HWND hedit = GetDlgItem(hdlg, 1000); + HWND hedit2 = GetDlgItem(hdlg, 1001); + HWND hedit3 = GetDlgItem(hdlg, 1002); + + if (wparam != 0xdeadbeef) + break; + + switch (lparam) + { + case 0: + if (hfocus == hedit) + EndDialog(hdlg, 1111); + else if (hfocus == hedit2) + EndDialog(hdlg, 2222); + else if (hfocus == hedit3) + EndDialog(hdlg, 3333); + else + EndDialog(hdlg, 4444); + break; + case 1: + if ((hfocus == hedit) && (num_ok_commands == 0)) + EndDialog(hdlg, 11); + else + EndDialog(hdlg, 22); + break; + default: + EndDialog(hdlg, 5555); + } + break; + } + + case WM_CLOSE: + EndDialog(hdlg, 333); + break; + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + HWND hedit = GetDlgItem(hdlg, 1000); + SetFocus(hedit); + switch (lparam) + { + /* from bug 11841 */ + case 0: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + break; + case 1: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + break; + case 2: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + /* more test cases for WM_CHAR */ + case 3: + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 4: + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 5: + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + + /* more test cases for WM_KEYDOWN + WM_CHAR */ + case 6: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 7: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + case 8: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + /* multiple tab tests */ + case 9: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2); + break; + case 10: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2); + break; + + default: + break; + } + break; + } + + case WM_COMMAND: + if (HIWORD(wparam) != BN_CLICKED) + break; + + switch (LOWORD(wparam)) + { + case IDOK: + EndDialog(hdlg, 111); + break; + + case IDCANCEL: + EndDialog(hdlg, 222); + break; + + default: + break; + } + break; + + case WM_USER: + { + int len; + HWND hok = GetDlgItem(hdlg, IDOK); + HWND hcancel = GetDlgItem(hdlg, IDCANCEL); + HWND hedit = GetDlgItem(hdlg, 1000); + HWND hfocus = GetFocus(); + + if (wparam != 0xdeadbeef) + break; + + switch (lparam) + { + case 0: + len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0); + if (len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + case 1: + len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0); + if ((hfocus == hok) && len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + case 2: + if (hfocus == hok) + EndDialog(hdlg, 11); + else if (hfocus == hcancel) + EndDialog(hdlg, 22); + else if (hfocus == hedit) + EndDialog(hdlg, 33); + else + EndDialog(hdlg, 44); + break; + + default: + EndDialog(hdlg, 555); + } + break; + } + + case WM_CLOSE: + EndDialog(hdlg, 333); + break; + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK edit_singleline_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + HWND hedit = GetDlgItem(hdlg, 1000); + SetFocus(hedit); + switch (lparam) + { + /* test cases for WM_KEYDOWN */ + case 0: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + break; + case 1: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + break; + case 2: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + /* test cases for WM_CHAR */ + case 3: + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 4: + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 5: + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + + /* test cases for WM_KEYDOWN + WM_CHAR */ + case 6: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + break; + case 7: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + break; + case 8: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + default: + break; + } + break; + } + + case WM_COMMAND: + if (HIWORD(wparam) != BN_CLICKED) + break; + + switch (LOWORD(wparam)) + { + case IDOK: + EndDialog(hdlg, 111); + break; + + case IDCANCEL: + EndDialog(hdlg, 222); + break; + + default: + break; + } + break; + + case WM_USER: + { + HWND hok = GetDlgItem(hdlg, IDOK); + HWND hedit = GetDlgItem(hdlg, 1000); + HWND hfocus = GetFocus(); + int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0); + + if (wparam != 0xdeadbeef) + break; + + switch (lparam) + { + case 0: + if ((hfocus == hedit) && len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + case 1: + if ((hfocus == hok) && len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + default: + EndDialog(hdlg, 55); + } + break; + } + + case WM_CLOSE: + EndDialog(hdlg, 333); + break; + + default: + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK edit_wantreturn_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + HWND hedit = GetDlgItem(hdlg, 1000); + SetFocus(hedit); + switch (lparam) + { + /* test cases for WM_KEYDOWN */ + case 0: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + break; + case 1: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 2: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + /* test cases for WM_CHAR */ + case 3: + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 4: + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2); + break; + case 5: + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + + /* test cases for WM_KEYDOWN + WM_CHAR */ + case 6: + PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0); + break; + case 7: + PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2); + break; + case 8: + PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001); + PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001); + PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1); + break; + + default: + break; + } + break; + } + + case WM_COMMAND: + if (HIWORD(wparam) != BN_CLICKED) + break; + + switch (LOWORD(wparam)) + { + case IDOK: + EndDialog(hdlg, 111); + break; + + case IDCANCEL: + EndDialog(hdlg, 222); + break; + + default: + break; + } + break; + + case WM_USER: + { + HWND hok = GetDlgItem(hdlg, IDOK); + HWND hedit = GetDlgItem(hdlg, 1000); + HWND hfocus = GetFocus(); + int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0); + + if (wparam != 0xdeadbeef) + break; + + switch (lparam) + { + case 0: + if ((hfocus == hedit) && len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + case 1: + if ((hfocus == hok) && len == 0) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + case 2: + if ((hfocus == hedit) && len == 2) + EndDialog(hdlg, 444); + else + EndDialog(hdlg, 555); + break; + + default: + EndDialog(hdlg, 55); + } + break; + } + + case WM_CLOSE: + EndDialog(hdlg, 333); + break; + + default: + break; + } + + return FALSE; +} + +static HINSTANCE hinst; +static HWND hwndET2; +static const char szEditTest2Class[] = "EditTest2Class"; +static const char szEditTest3Class[] = "EditTest3Class"; +static const char szEditTest4Class[] = "EditTest4Class"; +static const char szEditTextPositionClass[] = "EditTextPositionWindowClass"; + +static HWND create_editcontrol (DWORD style, DWORD exstyle) +{ + HWND handle; + + handle = CreateWindowExA(exstyle, + "EDIT", + "Test Text", + style, + 10, 10, 300, 300, + NULL, NULL, hinst, NULL); + ok (handle != NULL, "CreateWindow EDIT Control failed\n"); + assert (handle); + if (winetest_interactive) + ShowWindow (handle, SW_SHOW); + return handle; +} + +static HWND create_editcontrolW(DWORD style, DWORD exstyle) +{ + static const WCHAR testtextW[] = {'T','e','s','t',' ','t','e','x','t',0}; + HWND handle; + + handle = CreateWindowExW(exstyle, WC_EDITW, testtextW, style, 10, 10, 300, 300, + NULL, NULL, hinst, NULL); + ok(handle != NULL, "Failed to create Edit control.\n"); + return handle; +} + +static HWND create_child_editcontrol (DWORD style, DWORD exstyle) +{ + HWND parentWnd; + HWND editWnd; + RECT rect; + BOOL b; + SetRect(&rect, 0, 0, 300, 300); + b = AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + ok(b, "AdjustWindowRect failed\n"); + + parentWnd = CreateWindowExA(0, + szEditTextPositionClass, + "Edit Test", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + rect.right - rect.left, rect.bottom - rect.top, + NULL, NULL, hinst, NULL); + ok (parentWnd != NULL, "CreateWindow EDIT Test failed\n"); + assert(parentWnd); + + editWnd = CreateWindowExA(exstyle, + "EDIT", + "Test Text", + WS_CHILD | style, + 0, 0, 300, 300, + parentWnd, NULL, hinst, NULL); + ok (editWnd != NULL, "CreateWindow EDIT Test Text failed\n"); + assert(editWnd); + if (winetest_interactive) + ShowWindow (parentWnd, SW_SHOW); + return editWnd; +} + +static void destroy_child_editcontrol (HWND hwndEdit) +{ + if (GetParent(hwndEdit)) + DestroyWindow(GetParent(hwndEdit)); + else { + trace("Edit control has no parent!\n"); + DestroyWindow(hwndEdit); + } +} + +static LONG get_edit_style (HWND hwnd) +{ + return GetWindowLongA( hwnd, GWL_STYLE ) & ( + ES_LEFT | +/* FIXME: not implemented + ES_CENTER | + ES_RIGHT | + ES_OEMCONVERT | +*/ + ES_MULTILINE | + ES_UPPERCASE | + ES_LOWERCASE | + ES_PASSWORD | + ES_AUTOVSCROLL | + ES_AUTOHSCROLL | + ES_NOHIDESEL | + ES_COMBO | + ES_READONLY | + ES_WANTRETURN | + ES_NUMBER + ); +} + +static void set_client_height(HWND Wnd, unsigned Height) +{ + RECT ClientRect, WindowRect; + + GetWindowRect(Wnd, &WindowRect); + GetClientRect(Wnd, &ClientRect); + SetWindowPos(Wnd, NULL, 0, 0, + WindowRect.right - WindowRect.left, + Height + (WindowRect.bottom - WindowRect.top) - + (ClientRect.bottom - ClientRect.top), + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + + /* Workaround for a bug in Windows' edit control + (multi-line mode) */ + GetWindowRect(Wnd, &WindowRect); + SetWindowPos(Wnd, NULL, 0, 0, + WindowRect.right - WindowRect.left + 1, + WindowRect.bottom - WindowRect.top + 1, + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + SetWindowPos(Wnd, NULL, 0, 0, + WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + + GetClientRect(Wnd, &ClientRect); + ok(ClientRect.bottom - ClientRect.top == Height, + "The client height should be %d, but is %d\n", + Height, ClientRect.bottom - ClientRect.top); +} + +static void test_edit_control_1(void) +{ + HWND hwEdit; + MSG msMessage; + int i; + LONG r; + + msMessage.message = WM_KEYDOWN; + + trace("EDIT: Single line\n"); + hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = get_edit_style(hwEdit); + ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%x\n", r); + for (i = 0; i < 65535; i++) + { + msMessage.wParam = i; + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); + ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS), + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r); + } + DestroyWindow(hwEdit); + + trace("EDIT: Single line want returns\n"); + hwEdit = create_editcontrol(ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = get_edit_style(hwEdit); + ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%x\n", r); + for (i = 0; i < 65535; i++) + { + msMessage.wParam = i; + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); + ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS), + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r); + } + DestroyWindow(hwEdit); + + trace("EDIT: Multiline line\n"); + hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = get_edit_style(hwEdit); + ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%x\n", r); + for (i = 0; i < 65535; i++) + { + msMessage.wParam = i; + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); + ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS), + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r); + } + DestroyWindow(hwEdit); + + trace("EDIT: Multi line want returns\n"); + hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = get_edit_style(hwEdit); + ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%x\n", r); + for (i = 0; i < 65535; i++) + { + msMessage.wParam = i; + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); + ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS), + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r); + } + DestroyWindow(hwEdit); +} + +/* WM_SETTEXT is implemented by selecting all text, and then replacing the + * selection. This test checks that the first 'select all' doesn't generate + * an UPDATE message which can escape and (via a handler) change the + * selection, which would cause WM_SETTEXT to break. This old bug + * was fixed 18-Mar-2005; we check here to ensure it doesn't regress. + */ +static void test_edit_control_2(void) +{ + HWND hwndMain, phwnd; + char szLocalString[MAXLEN]; + LONG r, w = 150, h = 50; + POINT cpos; + + /* Create main and edit windows. */ + hwndMain = CreateWindowA(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW, + 0, 0, 200, 200, NULL, NULL, hinst, NULL); + assert(hwndMain); + if (winetest_interactive) + ShowWindow (hwndMain, SW_SHOW); + + hwndET2 = CreateWindowA("EDIT", NULL, + WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, + 0, 0, w, h, /* important this not be 0 size. */ + hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL); + assert(hwndET2); + if (winetest_interactive) + ShowWindow (hwndET2, SW_SHOW); + + trace("EDIT: SETTEXT atomicity\n"); + /* Send messages to "type" in the word 'foo'. */ + r = SendMessageA(hwndET2, WM_CHAR, 'f', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + /* 'foo' should have been changed to 'bar' by the UPDATE handler. */ + GetWindowTextA(hwndET2, szLocalString, MAXLEN); + ok(strcmp(szLocalString, "bar")==0, + "Wrong contents of edit: %s\n", szLocalString); + + /* try setting the caret before it's visible */ + r = SetCaretPos(0, 0); + todo_wine ok(0 == r, "SetCaretPos succeeded unexpectedly, expected: 0, got: %d\n", r); + phwnd = SetFocus(hwndET2); + ok(phwnd != NULL, "SetFocus failed unexpectedly, expected non-zero, got NULL\n"); + r = SetCaretPos(0, 0); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + r = GetCaretPos(&cpos); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%d,%d)\n", cpos.x, cpos.y); + r = SetCaretPos(-1, -1); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + r = GetCaretPos(&cpos); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%d,%d)\n", cpos.x, cpos.y); + r = SetCaretPos(w << 1, h << 1); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + r = GetCaretPos(&cpos); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(cpos.x == (w << 1) && cpos.y == (h << 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w << 1, h << 1, cpos.x, cpos.y); + r = SetCaretPos(w, h); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + r = GetCaretPos(&cpos); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w, h, cpos.x, cpos.y); + r = SetCaretPos(w - 1, h - 1); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + r = GetCaretPos(&cpos); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(cpos.x == (w - 1) && cpos.y == (h - 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w - 1, h - 1, cpos.x, cpos.y); + + DestroyWindow(hwndET2); + DestroyWindow(hwndMain); +} + +static void ET2_check_change(void) +{ + char szLocalString[MAXLEN]; + /* This EN_UPDATE handler changes any 'foo' to 'bar'. */ + GetWindowTextA(hwndET2, szLocalString, MAXLEN); + if (!strcmp(szLocalString, "foo")) + { + strcpy(szLocalString, "bar"); + SendMessageA(hwndET2, WM_SETTEXT, 0, (LPARAM)szLocalString); + } + /* always leave the cursor at the end. */ + SendMessageA(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1); +} + +static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) +{ + if (id == ID_EDITTEST2 && codeNotify == EN_UPDATE) + ET2_check_change(); +} + +static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + switch (iMsg) + { + case WM_COMMAND: + ET2_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam)); + break; + } + return DefWindowProcA(hwnd, iMsg, wParam, lParam); +} + +static void zero_notify(void) +{ + notifications.en_change = 0; + notifications.en_maxtext = 0; + notifications.en_update = 0; +} + +#define test_notify(enchange, enmaxtext, enupdate) \ +do { \ + ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \ + "got %d\n", enchange, notifications.en_change); \ + ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \ + "got %d\n", enmaxtext, notifications.en_maxtext); \ + ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \ + "got %d\n", enupdate, notifications.en_update); \ +} while(0) + +static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case EN_MAXTEXT: + notifications.en_maxtext++; + break; + case EN_UPDATE: + notifications.en_update++; + break; + case EN_CHANGE: + notifications.en_change++; + break; + } + break; + } + return DefWindowProcA(hWnd, msg, wParam, lParam); +} + +/* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notifications sent in response + * to these messages. + */ +static void test_edit_control_3(void) +{ + static const char *str = "this is a long string."; + static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string."; + HWND hWnd, hParent; + int len, dpi; + HDC hDC; + + hDC = GetDC(NULL); + dpi = GetDeviceCaps(hDC, LOGPIXELSY); + ReleaseDC(NULL, hDC); + + trace("EDIT: Test notifications\n"); + + hParent = CreateWindowExA(0, + szEditTest3Class, + NULL, + 0, + CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, + NULL, NULL, NULL, NULL); + assert(hParent); + + trace("EDIT: Single line, no ES_AUTOHSCROLL\n"); + hWnd = CreateWindowExA(0, + "EDIT", + NULL, + 0, + 10, 10, 50, 50, + hParent, NULL, NULL, NULL); + assert(hWnd); + + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + if (len == lstrlenA(str)) /* Win 8 */ + test_notify(1, 0, 1); + else + test_notify(1, 1, 1); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a"); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(1 == len, "wrong text length, expected 1, got %d\n", len); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + len = SendMessageA(hWnd, EM_GETSEL, 0, 0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); + SendMessageA(hParent, WM_SETFOCUS, 0, (LPARAM)hWnd); + len = SendMessageA(hWnd, EM_GETSEL, 0, 0); + ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); + ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); + + SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len); + test_notify(1, 1, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + DestroyWindow(hWnd); + + trace("EDIT: Single line, ES_AUTOHSCROLL\n"); + hWnd = CreateWindowExA(0, + "EDIT", + NULL, + ES_AUTOHSCROLL, + 10, 10, 50, 50, + hParent, NULL, NULL, NULL); + assert(hWnd); + + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len); + test_notify(1, 1, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + DestroyWindow(hWnd); + + trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n"); + hWnd = CreateWindowExA(0, + "EDIT", + NULL, + ES_MULTILINE, + 10, 10, (50 * dpi) / 96, (50 * dpi) / 96, + hParent, NULL, NULL, NULL); + assert(hWnd); + + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + if (len == lstrlenA(str)) /* Win 8 */ + test_notify(1, 0, 1); + else + { + ok(0 == len, "text should have been truncated, expected 0, got %d\n", len); + test_notify(1, 1, 1); + } + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a"); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len); + test_notify(1, 1, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + DestroyWindow(hWnd); + + trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n"); + hWnd = CreateWindowExA(0, + "EDIT", + NULL, + ES_MULTILINE | ES_AUTOHSCROLL, + 10, 10, (50 * dpi) / 96, (50 * dpi) / 96, + hParent, NULL, NULL, NULL); + assert(hWnd); + + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(0 == len, "text should have been truncated, expected 0, got %d\n", len); + test_notify(1, 1, 1); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a"); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len); + test_notify(1, 1, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + DestroyWindow(hWnd); + + trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n"); + hWnd = CreateWindowExA(0, + "EDIT", + NULL, + ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 10, 10, 50, 50, + hParent, NULL, NULL, NULL); + assert(hWnd); + + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(1, 0, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0); + + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)""); + zero_notify(); + SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len); + test_notify(1, 1, 1); + + zero_notify(); + SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n"); + test_notify(0, 0, 0); + + DestroyWindow(hWnd); +} + +static void test_char_from_pos(void) +{ + int lo, hi, mid, ret, i; + HWND hwEdit; + + hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(0 == ret, "expected 0 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(0 == ret, "expected 0 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(0 == ret, "expected 0 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2 + 1; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2 + 1; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa"); + lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); + hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); + mid = lo + (hi - lo) / 2 + 1; + + for (i = lo; i < mid; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + } + + for (i = mid; i <= hi; i++) + { + ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); + ok(1 == ret, "expected 1 got %d\n", ret); + } + + ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); + ok(-1 == ret, "expected -1 got %d\n", ret); + DestroyWindow(hwEdit); +} + +/* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL + * truncates text that doesn't fit. + */ +static void test_edit_control_5(void) +{ + static const char *str = "test\r\ntest"; + HWND parentWnd; + HWND hWnd; + int len; + RECT rc1 = { 10, 10, 11, 11}; + RECT rc; + + /* first show that a non-child won't do for this test */ + hWnd = CreateWindowExA(0, + "EDIT", + str, + 0, + 10, 10, 1, 1, + NULL, NULL, NULL, NULL); + assert(hWnd); + /* size of non-child edit control is (much) bigger than requested */ + GetWindowRect( hWnd, &rc); + ok( rc.right - rc.left > 20, "size of the window (%d) is smaller than expected\n", + rc.right - rc.left); + DestroyWindow(hWnd); + /* so create a parent, and give it edit controls children to test with */ + parentWnd = CreateWindowExA(0, + szEditTextPositionClass, + "Edit Test", WS_VISIBLE | + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + 250, 250, + NULL, NULL, hinst, NULL); + assert(parentWnd); + ShowWindow( parentWnd, SW_SHOW); + /* single line */ + hWnd = CreateWindowExA(0, + "EDIT", + str, WS_VISIBLE | WS_BORDER | + WS_CHILD, + rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, + parentWnd, NULL, NULL, NULL); + assert(hWnd); + GetClientRect( hWnd, &rc); + ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top, + "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc )); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + DestroyWindow(hWnd); + /* multi line */ + hWnd = CreateWindowExA(0, + "EDIT", + str, + WS_CHILD | ES_MULTILINE, + rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, + parentWnd, NULL, NULL, NULL); + assert(hWnd); + GetClientRect( hWnd, &rc); + ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top, + "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc )); + len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); + ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); + DestroyWindow(hWnd); + DestroyWindow(parentWnd); +} + +/* Test WM_GETTEXT processing + * after destroy messages + */ +static void test_edit_control_6(void) +{ + static const char *str = "test\r\ntest"; + char buf[MAXLEN]; + HWND hWnd; + LONG ret; + + hWnd = CreateWindowExA(0, "EDIT", "Test", 0, 10, 10, 1, 1, NULL, NULL, hinst, NULL); + ok(hWnd != NULL, "Failed to create edit control.\n"); + + ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + ok(ret == TRUE, "Expected %d, got %d\n", TRUE, ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret); + ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf); + + buf[0] = 0; + ret = SendMessageA(hWnd, WM_DESTROY, 0, 0); +todo_wine + ok(ret == 1, "Unexpected return value %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret); + ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf); + + buf[0] = 0; + ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); +todo_wine { + ok(ret == strlen("Test"), "Unexpected text length %d\n", ret); + ok(!strcmp(buf, "Test"), "Unexpected text %s\n", buf); +} + DestroyWindow(hWnd); +} + +static void test_edit_control_limittext(void) +{ + HWND hwEdit; + DWORD r; + + /* Test default limit for single-line control */ + trace("EDIT: buffer limit for single-line\n"); + hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); + ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r); + SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); + r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); + ok( r == 2147483646, "got limit %u (expected 2147483646)\n", r); + DestroyWindow(hwEdit); + + /* Test default limit for multi-line control */ + trace("EDIT: buffer limit for multi-line\n"); + hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); + ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r); + SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); + r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); + ok( r == 4294967295U, "got limit %u (expected 4294967295)\n", r); + DestroyWindow(hwEdit); +} + +/* Test EM_SCROLL */ +static void test_edit_control_scroll(void) +{ + static const char *single_line_str = "a"; + static const char *multiline_str = "Test\r\nText"; + HWND hwEdit; + LONG ret; + + /* Check the return value when EM_SCROLL doesn't scroll + * anything. Should not return true unless any lines were actually + * scrolled. */ + hwEdit = CreateWindowA( + "EDIT", + single_line_str, + WS_VSCROLL | ES_MULTILINE, + 1, 1, 100, 100, + NULL, NULL, hinst, NULL); + + assert(hwEdit); + + ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); + ok(!ret, "Returned %x, expected 0.\n", ret); + + ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEUP, 0); + ok(!ret, "Returned %x, expected 0.\n", ret); + + ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEUP, 0); + ok(!ret, "Returned %x, expected 0.\n", ret); + + ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEDOWN, 0); + ok(!ret, "Returned %x, expected 0.\n", ret); + + DestroyWindow (hwEdit); + + /* SB_PAGEDOWN while at the beginning of a buffer with few lines + should not cause EM_SCROLL to return a negative value of + scrolled lines that would put us "before" the beginning. */ + hwEdit = CreateWindowA( + "EDIT", + multiline_str, + WS_VSCROLL | ES_MULTILINE, + 0, 0, 100, 100, + NULL, NULL, hinst, NULL); + assert(hwEdit); + + ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); + ok(!ret, "Returned %x, expected 0.\n", ret); + + DestroyWindow (hwEdit); +} + +static void test_margins_usefontinfo(UINT charset) +{ + INT margins, threshold, expect, empty_expect, small_expect; + HWND hwnd; + HDC hdc; + SIZE size; + BOOL cjk; + LOGFONTA lf; + HFONT hfont; + RECT rect; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -11; + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = charset; + strcpy(lf.lfFaceName, "Tahoma"); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != NULL, "got %p\n", hfont); + + /* Big window rectangle */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + hdc = GetDC(hwnd); + hfont = SelectObject(hdc, hfont); + size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy ); + expect = MAKELONG(size.cx / 2, size.cx / 2); + small_expect = 0; + empty_expect = size.cx >= 28 ? small_expect : expect; + + charset = GetTextCharset(hdc); + switch (charset) + { + case SHIFTJIS_CHARSET: + case HANGUL_CHARSET: + case GB2312_CHARSET: + case CHINESEBIG5_CHARSET: + cjk = TRUE; + break; + default: + cjk = FALSE; + } + + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + if (!cjk) + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + else + { + ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + expect = empty_expect = small_expect = margins; + } + DestroyWindow(hwnd); + + threshold = (size.cx / 2 + size.cx) * 2; + + /* Size below which non-cjk margins are zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Size at which non-cjk margins become non-zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Empty rect */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + DeleteObject(hfont); +} + +static void test_margins(void) +{ + DWORD old_margins, new_margins; + RECT old_rect, new_rect; + INT old_right_margin; + HWND hwEdit; + + hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + old_right_margin = HIWORD(old_margins); + + /* Check if setting the margins works */ + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0)); + new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins)); + ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10)); + new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins)); + ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins)); + + /* The size of the rectangle must decrease if we increase the margin */ + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5)); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect); + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20)); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n"); + ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n"); + ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n"); + ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n"); + + /* If we set the margin to same value as the current margin, + the rectangle must not change */ + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10)); + SetRect(&old_rect, 1, 1, 99, 99); + SendMessageA(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect); + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10)); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n"); + + /* The lParam argument of the WM_SIZE message should be ignored. */ + + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect); + SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, 0); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n"); + SendMessageA(hwEdit, WM_SIZE, SIZE_MINIMIZED, 0); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n"); + SendMessageA(hwEdit, WM_SIZE, SIZE_MAXIMIZED, 0); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n"); + SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, MAKELONG(10, 10)); + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect); + ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n"); + + DestroyWindow (hwEdit); + + test_margins_usefontinfo(ANSI_CHARSET); + test_margins_usefontinfo(EASTEUROPE_CHARSET); + + test_margins_usefontinfo(SHIFTJIS_CHARSET); + test_margins_usefontinfo(HANGUL_CHARSET); + test_margins_usefontinfo(CHINESEBIG5_CHARSET); + /* Don't test JOHAB_CHARSET. Treated as CJK by Win 8, + but not by < Win 8 and Win 10. */ + + test_margins_usefontinfo(DEFAULT_CHARSET); +} + +static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) +{ + return 0; +} + +static void test_margins_font_change(void) +{ + DWORD margins, font_margins, ret; + HFONT hfont, hfont2; + HWND hwEdit; + LOGFONTA lf; + HDC hdc; + + hdc = GetDC(0); + ret = EnumFontFamiliesA(hdc, "Arial", find_font_proc, 0); + ReleaseDC(0, hdc); + if (ret) + { + trace("Arial not found - skipping font change margin tests\n"); + return; + } + + hwEdit = create_child_editcontrol(0, 0); + + SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE); + + memset(&lf, 0, sizeof(lf)); + strcpy(lf.lfFaceName, "Arial"); + lf.lfHeight = 16; + lf.lfCharSet = DEFAULT_CHARSET; + hfont = CreateFontIndirectA(&lf); + lf.lfHeight = 30; + hfont2 = CreateFontIndirectA(&lf); + + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + font_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(font_margins) != 0, "got %d\n", LOWORD(font_margins)); + ok(HIWORD(font_margins) != 0, "got %d\n", HIWORD(font_margins)); + + /* With 'small' edit controls, test that the margin doesn't get set */ + SetWindowPos(hwEdit, NULL, 10, 10, 16, 100, SWP_NOZORDER | SWP_NOACTIVATE); + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO)); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + + /* Above a certain size threshold then the margin is updated */ + SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE); + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); + margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); + ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins)); + + SendMessageA(hwEdit, WM_SETFONT, 0, 0); + + DeleteObject(hfont2); + DeleteObject(hfont); + destroy_child_editcontrol(hwEdit); + +} + +#define edit_pos_ok(exp, got, txt) \ + ok(exp == got, "wrong " #txt " expected %d got %d\n", exp, got); + +#define check_pos(hwEdit, set_height, test_top, test_height, test_left) \ +do { \ + RECT format_rect; \ + int left_margin; \ + set_client_height(hwEdit, set_height); \ + SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \ + left_margin = LOWORD(SendMessageA(hwEdit, EM_GETMARGINS, 0, 0)); \ + edit_pos_ok(test_top, format_rect.top, vertical position); \ + edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \ + edit_pos_ok(test_left, format_rect.left - left_margin, left); \ +} while(0) + +static void test_text_position_style(DWORD style) +{ + HWND hwEdit; + HFONT font, oldFont; + HDC dc; + TEXTMETRICA metrics; + INT b, bm, b2, b3; + BOOL xb, single_line = !(style & ES_MULTILINE); + + b = GetSystemMetrics(SM_CYBORDER) + 1; + b2 = 2 * b; + b3 = 3 * b; + bm = b2 - 1; + + /* Get a stock font for which we can determine the metrics */ + font = GetStockObject(SYSTEM_FONT); + ok (font != NULL, "GetStockObject SYSTEM_FONT failed\n"); + dc = GetDC(NULL); + ok (dc != NULL, "GetDC() failed\n"); + oldFont = SelectObject(dc, font); + xb = GetTextMetricsA(dc, &metrics); + ok (xb, "GetTextMetrics failed\n"); + SelectObject(dc, oldFont); + ReleaseDC(NULL, dc); + + /* Windows' edit control has some bugs in multi-line mode: + * - Sometimes the format rectangle doesn't get updated + * (see workaround in set_client_height()) + * - If the height of the control is smaller than the height of a text + * line, the format rectangle is still as high as a text line + * (higher than the client rectangle) and the caret is not shown + */ + + /* Edit controls that are in a parent window */ + + hwEdit = create_child_editcontrol(style | WS_VISIBLE, 0); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0); + destroy_child_editcontrol(hwEdit); + + hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, 0); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b); + destroy_child_editcontrol(hwEdit); + + hwEdit = create_child_editcontrol(style | WS_VISIBLE, WS_EX_CLIENTEDGE); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1); + destroy_child_editcontrol(hwEdit); + + hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, WS_EX_CLIENTEDGE); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1); + destroy_child_editcontrol(hwEdit); + + + /* Edit controls that are popup windows */ + + hwEdit = create_editcontrol(style | WS_POPUP, 0); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0); + check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b); + check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1); + DestroyWindow(hwEdit); + + hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE); + if (single_line) + check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); + check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1); + check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1); + DestroyWindow(hwEdit); +} + +static void test_text_position(void) +{ + trace("EDIT: Text position (Single line)\n"); + test_text_position_style(ES_AUTOHSCROLL | ES_AUTOVSCROLL); + trace("EDIT: Text position (Multi line)\n"); + test_text_position_style(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL); +} + +static void test_espassword(void) +{ + HWND hwEdit; + LONG r; + char buffer[1024]; + const char* password = "secret"; + + hwEdit = create_editcontrol(ES_PASSWORD, 0); + r = get_edit_style(hwEdit); + ok(r == ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%x\n", r); + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) password); + ok(r == TRUE, "Expected: %d, got: %d\n", TRUE, r); + + /* select all, cut (ctrl-x) */ + SendMessageA(hwEdit, EM_SETSEL, 0, -1); + r = SendMessageA(hwEdit, WM_CHAR, 24, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(r == strlen(password), "Expected: %s, got len %d\n", password, r); + ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer); + + r = OpenClipboard(hwEdit); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = EmptyClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = CloseClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + + /* select all, copy (ctrl-c) and paste (ctrl-v) */ + SendMessageA(hwEdit, EM_SETSEL, 0, -1); + r = SendMessageA(hwEdit, WM_CHAR, 3, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessageA(hwEdit, WM_CHAR, 22, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(r == 0, "Expected: 0, got: %d\n", r); + ok(strcmp(buffer, "") == 0, "expected empty string, got %s\n", buffer); + + DestroyWindow(hwEdit); +} + +static void test_undo(void) +{ + HWND hwEdit; + LONG r; + DWORD cpMin, cpMax; + char buffer[1024]; + const char* text = "undo this"; + + hwEdit = create_editcontrol(0, 0); + r = get_edit_style(hwEdit); + ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) text); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + /* select all, */ + cpMin = cpMax = 0xdeadbeef; + SendMessageA(hwEdit, EM_SETSEL, 0, -1); + r = SendMessageA(hwEdit, EM_GETSEL, (WPARAM) &cpMin, (LPARAM) &cpMax); + ok((strlen(text) << 16) == r, "Unexpected length %d\n", r); + ok(0 == cpMin, "Expected: %d, got %d\n", 0, cpMin); + ok(9 == cpMax, "Expected: %d, got %d\n", 9, cpMax); + + /* cut (ctrl-x) */ + r = SendMessageA(hwEdit, WM_CHAR, 24, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer); + + /* undo (ctrl-z) */ + r = SendMessageA(hwEdit, WM_CHAR, 26, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(strlen(text) == r, "Unexpected length %d\n", r); + ok(0 == strcmp(buffer, text), "expected %s, got %s\n", text, buffer); + + /* undo again (ctrl-z) */ + r = SendMessageA(hwEdit, WM_CHAR, 26, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(r == 0, "Expected: %d, got len %d\n", 0, r); + ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer); + + DestroyWindow(hwEdit); +} + +static void test_enter(void) +{ + char buffer[16]; + HWND hwEdit; + LONG r; + + /* multiline */ + hwEdit = create_editcontrol(ES_MULTILINE, 0); + r = get_edit_style(hwEdit); + ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); + ok(2 == r, "Expected: %d, got len %d\n", 2, r); + ok(0 == strcmp(buffer, "\r\n"), "expected "\r\n", got "%s"\n", buffer); + + DestroyWindow (hwEdit); + + /* single line */ + hwEdit = create_editcontrol(0, 0); + r = get_edit_style(hwEdit); + ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); + ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == strcmp(buffer, ""), "expected "", got "%s"\n", buffer); + + DestroyWindow(hwEdit); + + /* single line with ES_WANTRETURN */ + hwEdit = create_editcontrol(ES_WANTRETURN, 0); + r = get_edit_style(hwEdit); + ok(ES_WANTRETURN == r, "Wrong style expected ES_WANTRETURN got: 0x%x\n", r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); + ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == strcmp(buffer, ""), "expected "", got "%s"\n", buffer); + + DestroyWindow(hwEdit); +} + +static void test_tab(void) +{ + char buffer[16]; + HWND hwEdit; + LONG r; + + /* multiline */ + hwEdit = create_editcontrol(ES_MULTILINE, 0); + r = get_edit_style(hwEdit); + ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); + ok(1 == r, "Expected: %d, got len %d\n", 1, r); + ok(0 == strcmp(buffer, "\t"), "expected "\t", got "%s"\n", buffer); + + DestroyWindow(hwEdit); + + /* single line */ + hwEdit = create_editcontrol(0, 0); + r = get_edit_style(hwEdit); + ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + + /* set text */ + r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); + ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + /* get text */ + buffer[0] = 0; + r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); + ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == strcmp(buffer, ""), "expected "", got "%s"\n", buffer); + + DestroyWindow(hwEdit); +} + +static void test_edit_dialog(void) +{ + int r; + + /* from bug 11841 */ + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 0); + ok(333 == r, "Expected %d, got %d\n", 333, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 1); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 2); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* more tests for WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 3); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 4); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 5); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* more tests for WM_KEYDOWN + WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 6); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 7); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 8); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests with an editable edit control */ + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 0); + ok(333 == r, "Expected %d, got %d\n", 333, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 1); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 2); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 3); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 4); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 5); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_KEYDOWN + WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 6); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 7); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 8); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* multiple tab tests */ + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 9); + ok(22 == r, "Expected %d, got %d\n", 22, r); + r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 10); + ok(33 == r, "Expected %d, got %d\n", 33, r); +} + +static void test_multi_edit_dialog(void) +{ + int r; + + /* test for multiple edit dialogs (bug 12319) */ + r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 0); + ok(2222 == r, "Expected %d, got %d\n", 2222, r); + r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 1); + ok(1111 == r, "Expected %d, got %d\n", 1111, r); + r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 2); + ok(2222 == r, "Expected %d, got %d\n", 2222, r); + r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 3); + ok(11 == r, "Expected %d, got %d\n", 11, r); +} + +static void test_wantreturn_edit_dialog(void) +{ + int r; + + /* tests for WM_KEYDOWN */ + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 0); + ok(333 == r, "Expected %d, got %d\n", 333, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 1); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 2); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 3); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 4); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 5); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_KEYDOWN + WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 6); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 7); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 8); + ok(444 == r, "Expected %d, got %d\n", 444, r); +} + +static void test_singleline_wantreturn_edit_dialog(void) +{ + int r; + + /* tests for WM_KEYDOWN */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 0); + ok(222 == r, "Expected %d, got %d\n", 222, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 1); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 2); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 3); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 4); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 5); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_KEYDOWN + WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 6); + ok(222 == r, "Expected %d, got %d\n", 222, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 7); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 8); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_KEYDOWN */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 0); + ok(222 == r, "Expected %d, got %d\n", 222, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 1); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 2); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 3); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 4); + ok(444 == r, "Expected %d, got %d\n", 444, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 5); + ok(444 == r, "Expected %d, got %d\n", 444, r); + + /* tests for WM_KEYDOWN + WM_CHAR */ + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 6); + ok(222 == r, "Expected %d, got %d\n", 222, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 7); + ok(111 == r, "Expected %d, got %d\n", 111, r); + r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 8); + ok(444 == r, "Expected %d, got %d\n", 444, r); +} + +static int child_edit_wmkeydown_num_messages = 0; +static INT_PTR CALLBACK child_edit_wmkeydown_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DESTROY: + case WM_NCDESTROY: + break; + + default: + child_edit_wmkeydown_num_messages++; + break; + } + + return FALSE; +} + +static void test_child_edit_wmkeydown(void) +{ + HWND hwEdit, hwParent; + int r; + + hwEdit = create_child_editcontrol(0, 0); + hwParent = GetParent(hwEdit); + SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)child_edit_wmkeydown_proc); + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + ok(0 == child_edit_wmkeydown_num_messages, "expected 0, got %d\n", child_edit_wmkeydown_num_messages); + destroy_child_editcontrol(hwEdit); +} + +static BOOL got_en_setfocus = FALSE; +static BOOL got_wm_capturechanged = FALSE; +static LRESULT (CALLBACK *p_edit_proc)(HWND, UINT, WPARAM, LPARAM); + +static LRESULT CALLBACK edit4_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case EN_SETFOCUS: + got_en_setfocus = TRUE; + break; + } + break; + case WM_CAPTURECHANGED: + if (hWnd != (HWND)lParam) + { + got_wm_capturechanged = TRUE; + EndMenu(); + } + break; + } + return DefWindowProcA(hWnd, msg, wParam, lParam); +} + +struct context_menu_messages +{ + unsigned int wm_command, em_setsel; +}; + +static struct context_menu_messages menu_messages; + +static LRESULT CALLBACK child_edit_menu_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_ENTERIDLE: + if (wParam == MSGF_MENU) + { + HWND hwndMenu = (HWND)lParam; + MENUBARINFO mbi = { sizeof(mbi) }; + if (GetMenuBarInfo(hwndMenu, OBJID_CLIENT, 0, &mbi)) + { + MENUITEMINFOA mii = { sizeof(MENUITEMINFOA), MIIM_STATE }; + if (GetMenuItemInfoA(mbi.hMenu, EM_SETSEL, FALSE, &mii)) + { + if (mii.fState & MFS_HILITE) + { + PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0x1c0001); + PostMessageA(hwnd, WM_KEYUP, VK_RETURN, 0x1c0001); + } + else + { + PostMessageA(hwnd, WM_KEYDOWN, VK_DOWN, 0x500001); + PostMessageA(hwnd, WM_KEYUP, VK_DOWN, 0x500001); + } + } + } + } + break; + case WM_COMMAND: + menu_messages.wm_command++; + break; + case EM_SETSEL: + menu_messages.em_setsel++; + break; + } + return CallWindowProcA(p_edit_proc, hwnd, msg, wParam, lParam); +} + +static void test_contextmenu(void) +{ + HWND hwndMain, hwndEdit; + MSG msg; + + hwndMain = CreateWindowA(szEditTest4Class, "ET4", WS_OVERLAPPEDWINDOW|WS_VISIBLE, + 0, 0, 200, 200, NULL, NULL, hinst, NULL); + assert(hwndMain); + + hwndEdit = CreateWindowA("EDIT", NULL, + WS_CHILD|WS_BORDER|WS_VISIBLE|ES_LEFT|ES_AUTOHSCROLL, + 0, 0, 150, 50, /* important this not be 0 size. */ + hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL); + assert(hwndEdit); + + SetFocus(NULL); + SetCapture(hwndMain); + SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(10, 10)); + ok(got_en_setfocus, "edit box didn't get focused\n"); + ok(got_wm_capturechanged, "main window capture did not change\n"); + + DestroyWindow(hwndEdit); + + hwndEdit = CreateWindowA("EDIT", "Test Text", + WS_CHILD | WS_BORDER | WS_VISIBLE, + 0, 0, 100, 100, + hwndMain, NULL, hinst, NULL); + memset(&menu_messages, 0, sizeof(menu_messages)); + p_edit_proc = (void*)SetWindowLongPtrA(hwndEdit, GWLP_WNDPROC, + (ULONG_PTR)child_edit_menu_proc); + + SetFocus(hwndEdit); + SendMessageA(hwndEdit, WM_SETTEXT, 0, (LPARAM)"foo"); + SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(-1, -1)); + while (PeekMessageA(&msg, hwndEdit, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok(menu_messages.wm_command == 0, + "Expected no WM_COMMAND messages, got %d\n", menu_messages.wm_command); + ok(menu_messages.em_setsel == 1, + "Expected 1 EM_SETSEL message, got %d\n", menu_messages.em_setsel); + + DestroyWindow(hwndEdit); + DestroyWindow(hwndMain); +} + +static BOOL register_classes(void) +{ + WNDCLASSA test2; + WNDCLASSA test3; + WNDCLASSA test4; + WNDCLASSA text_position; + + test2.style = 0; + test2.lpfnWndProc = ET2_WndProc; + test2.cbClsExtra = 0; + test2.cbWndExtra = 0; + test2.hInstance = hinst; + test2.hIcon = NULL; + test2.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW); + test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + test2.lpszMenuName = NULL; + test2.lpszClassName = szEditTest2Class; + if (!RegisterClassA(&test2)) return FALSE; + + test3.style = 0; + test3.lpfnWndProc = edit3_wnd_procA; + test3.cbClsExtra = 0; + test3.cbWndExtra = 0; + test3.hInstance = hinst; + test3.hIcon = 0; + test3.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + test3.hbrBackground = GetStockObject(WHITE_BRUSH); + test3.lpszMenuName = NULL; + test3.lpszClassName = szEditTest3Class; + if (!RegisterClassA(&test3)) return FALSE; + + test4.style = 0; + test4.lpfnWndProc = edit4_wnd_procA; + test4.cbClsExtra = 0; + test4.cbWndExtra = 0; + test4.hInstance = hinst; + test4.hIcon = NULL; + test4.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW); + test4.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + test4.lpszMenuName = NULL; + test4.lpszClassName = szEditTest4Class; + if (!RegisterClassA(&test4)) return FALSE; + + text_position.style = CS_HREDRAW | CS_VREDRAW; + text_position.cbClsExtra = 0; + text_position.cbWndExtra = 0; + text_position.hInstance = hinst; + text_position.hIcon = NULL; + text_position.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + text_position.lpszMenuName = NULL; + text_position.lpszClassName = szEditTextPositionClass; + text_position.lpfnWndProc = DefWindowProcA; + if (!RegisterClassA(&text_position)) return FALSE; + + return TRUE; +} + +static void UnregisterWindowClasses (void) +{ + UnregisterClassA(szEditTest2Class, hinst); + UnregisterClassA(szEditTest3Class, hinst); + UnregisterClassA(szEditTest4Class, hinst); + UnregisterClassA(szEditTextPositionClass, hinst); +} + +static void test_fontsize(void) +{ + HWND hwEdit; + HFONT hfont; + HDC hDC; + LOGFONTA lf; + LONG r; + char szLocalString[MAXLEN]; + int dpi; + + hDC = GetDC(NULL); + dpi = GetDeviceCaps(hDC, LOGPIXELSY); + ReleaseDC(NULL, hDC); + + memset(&lf,0,sizeof(LOGFONTA)); + strcpy(lf.lfFaceName,"Arial"); + lf.lfHeight = -300; /* taller than the edit box */ + lf.lfWeight = 500; + hfont = CreateFontIndirectA(&lf); + + trace("EDIT: Oversized font (Multi line)\n"); + hwEdit= CreateWindowA("EDIT", NULL, ES_MULTILINE|ES_AUTOHSCROLL, + 0, 0, (150 * dpi) / 96, (50 * dpi) / 96, NULL, NULL, + hinst, NULL); + + SendMessageA(hwEdit,WM_SETFONT,(WPARAM)hfont,0); + + if (winetest_interactive) + ShowWindow (hwEdit, SW_SHOW); + + r = SendMessageA(hwEdit, WM_CHAR, 'A', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessageA(hwEdit, WM_CHAR, 'B', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessageA(hwEdit, WM_CHAR, 'C', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + GetWindowTextA(hwEdit, szLocalString, MAXLEN); + ok(strcmp(szLocalString, "ABC")==0, + "Wrong contents of edit: %s\n", szLocalString); + + r = SendMessageA(hwEdit, EM_POSFROMCHAR,0,0); + ok(r != -1,"EM_POSFROMCHAR failed index 0\n"); + r = SendMessageA(hwEdit, EM_POSFROMCHAR,1,0); + ok(r != -1,"EM_POSFROMCHAR failed index 1\n"); + r = SendMessageA(hwEdit, EM_POSFROMCHAR,2,0); + ok(r != -1,"EM_POSFROMCHAR failed index 2\n"); + r = SendMessageA(hwEdit, EM_POSFROMCHAR,3,0); + ok(r == -1,"EM_POSFROMCHAR succeeded index 3\n"); + + DestroyWindow (hwEdit); + DeleteObject(hfont); +} + +struct dialog_mode_messages +{ + int wm_getdefid, wm_close, wm_command, wm_nextdlgctl; +}; + +static struct dialog_mode_messages dm_messages; + +static void zero_dm_messages(void) +{ + dm_messages.wm_command = 0; + dm_messages.wm_close = 0; + dm_messages.wm_getdefid = 0; + dm_messages.wm_nextdlgctl = 0; +} + +#define test_dm_messages(wmcommand, wmclose, wmgetdefid, wmnextdlgctl) \ + ok(dm_messages.wm_command == wmcommand, "expected %d WM_COMMAND messages, " \ + "got %d\n", wmcommand, dm_messages.wm_command); \ + ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE messages, " \ + "got %d\n", wmclose, dm_messages.wm_close); \ + ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID messages, " \ + "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\ + ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL messages, " \ + "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl) + +static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + switch (iMsg) + { + case WM_COMMAND: + dm_messages.wm_command++; + break; + case DM_GETDEFID: + dm_messages.wm_getdefid++; + return MAKELONG(ID_EDITTESTDBUTTON, DC_HASDEFID); + case WM_NEXTDLGCTL: + dm_messages.wm_nextdlgctl++; + break; + case WM_CLOSE: + dm_messages.wm_close++; + break; + } + + return DefWindowProcA(hwnd, iMsg, wParam, lParam); +} + +static void test_dialogmode(void) +{ + HWND hwEdit, hwParent, hwButton; + MSG msg= {0}; + int len, r; + hwEdit = create_child_editcontrol(ES_MULTILINE, 0); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, 0); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + destroy_child_editcontrol(hwEdit); + + hwEdit = create_editcontrol(ES_MULTILINE, 0); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_BACK; + msg.lParam = 0xe0001; + r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_BACK, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + + r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + DestroyWindow(hwEdit); + + hwEdit = create_child_editcontrol(0, 0); + hwParent = GetParent(hwEdit); + SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc); + + zero_dm_messages(); + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_TAB; + msg.lParam = 0xf0001; + r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_TAB, (LPARAM)&msg); + ok(0x89 == r, "expected 0x89, got 0x%x\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + destroy_child_editcontrol(hwEdit); + + hwEdit = create_child_editcontrol(ES_MULTILINE, 0); + hwParent = GetParent(hwEdit); + SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_ESCAPE; + msg.lParam = 0x10001; + r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_ESCAPE, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 1); + zero_dm_messages(); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 1, 0); + zero_dm_messages(); + + hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, + 100, 100, 50, 20, hwParent, (HMENU)ID_EDITTESTDBUTTON, hinst, NULL); + ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); + + r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 1, 1); + zero_dm_messages(); + + DestroyWindow(hwButton); + destroy_child_editcontrol(hwEdit); +} + +static void test_EM_GETHANDLE(void) +{ + static const WCHAR str1W[] = {'1','1','1','1','+','1','1','1','1','+','1','1','1','1','#',0}; + static const WCHAR str2W[] = {'2','2','2','2','-','2','2','2','2','-','2','2','2','2','-','2','2','2','2','#',0}; + static const char str0[] = "untouched"; + static const char str1[] = "1111+1111+1111#"; + static const char str1_1[] = "2111+1111+1111#"; + static const char str2[] = "2222-2222-2222-2222#"; + static const char str3[] = "3333*3333*3333*3333*3333#"; + CHAR current[42]; + HWND hEdit; + HLOCAL hmem; + HLOCAL hmem2; + HLOCAL halloc; + WCHAR *buffer; + int len; + int r; + + trace("EDIT: EM_GETHANDLE\n"); + + /* EM_GETHANDLE is not supported for a single line edit control */ + hEdit = create_editcontrol(WS_BORDER, 0); + ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit); + + hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem == NULL, "got %p (expected NULL)\n", hmem); + DestroyWindow(hEdit); + + /* EM_GETHANDLE needs a multiline edit control */ + hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0); + ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit); + + /* set some text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1), + "got %d and "%s" (expected %d and "%s")\n", r, current, lstrlenA(str1), str1); + + hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem != NULL, "got %p (expected != NULL)\n", hmem); + /* The buffer belongs to the app now. According to MSDN, the app has to LocalFree the + buffer, LocalAlloc a new buffer and pass it to the edit control with EM_SETHANDLE. */ + + buffer = LocalLock(hmem); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + len = lstrlenW(buffer); +todo_wine + ok(len == lstrlenW(str1W) && !lstrcmpW(buffer, str1W), "Unexpected buffer contents %s, length %d.\n", + wine_dbgstr_w(buffer), len); + LocalUnlock(hmem); + + /* See if WM_GETTEXTLENGTH/WM_GETTEXT still work. */ + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok(len == lstrlenA(str1), "Unexpected text length %d.\n", len); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1), + "Unexpected retval %d and text "%s" (expected %d and "%s")\n", r, current, lstrlenA(str1), str1); + + /* Application altered buffer contents, see if WM_GETTEXTLENGTH/WM_GETTEXT pick that up. */ + buffer = LocalLock(hmem); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + buffer[0] = '2'; + LocalUnlock(hmem); + + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok(len == lstrlenA(str1_1), "Unexpected text length %d.\n", len); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); +todo_wine + ok(r == lstrlenA(str1_1) && !lstrcmpA(current, str1_1), + "Unexpected retval %d and text "%s" (expected %d and "%s")\n", r, current, lstrlenA(str1_1), str1_1); + + /* See if WM_SETTEXT/EM_REPLACESEL work. */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1); + ok(r, "Failed to set text.\n"); + + buffer = LocalLock(hmem); +todo_wine + ok(buffer != NULL && buffer[0] == '1', "Unexpected buffer contents\n"); + LocalUnlock(hmem); + + r = SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)str1_1); + ok(r, "Failed to replace selection.\n"); + + buffer = LocalLock(hmem); +todo_wine + ok(buffer != NULL && buffer[0] == '2', "Unexpected buffer contents\n"); + LocalUnlock(hmem); + + /* use LocalAlloc first to get a different handle */ + halloc = LocalAlloc(LMEM_MOVEABLE, 42); + ok(halloc != NULL, "got %p (expected != NULL)\n", halloc); + /* prepare our new memory */ + buffer = LocalLock(halloc); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + lstrcpyW(buffer, str2W); + LocalUnlock(halloc); + + /* LocalFree the old memory handle before EM_SETHANDLE the new handle */ + LocalFree(hmem); + /* use LocalAlloc after the LocalFree to likely consume the handle */ + hmem2 = LocalAlloc(LMEM_MOVEABLE, 42); + ok(hmem2 != NULL, "got %p (expected != NULL)\n", hmem2); + + SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)halloc, 0); + + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); +todo_wine + ok(len == lstrlenA(str2), "got %d (expected %d)\n", len, lstrlenA(str2)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); +todo_wine + ok(r == lstrlenA(str2) && !lstrcmpA(current, str2), + "got %d and "%s" (expected %d and "%s")\n", r, current, lstrlenA(str2), str2); + + /* set a different text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str3); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str3)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str3)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str3)) && !lstrcmpA(current, str3), + "got %d and "%s" (expected %d and "%s")\n", r, current, lstrlenA(str3), str3); + + LocalFree(hmem2); + DestroyWindow(hEdit); + + /* Some apps have bugs ... */ + hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0); + + /* set some text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1)); + + /* everything is normal up to EM_GETHANDLE */ + hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0); + /* Some messages still work while other messages fail. + After LocalFree the memory handle, messages can crash the app */ + + /* A buggy editor used EM_GETHANDLE twice */ + hmem2 = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem2 == hmem, "got %p (expected %p)\n", hmem2, hmem); + + /* Let the edit control free the memory handle */ + SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)hmem2, 0); + + DestroyWindow(hEdit); +} + +static void test_paste(void) +{ + static const char *str = "this is a simple text"; + static const char *str2 = "first line\r\nsecond line"; + HWND hEdit, hMultilineEdit; + HANDLE hmem, hmem_ret; + char *buffer; + int r, len; + + hEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + hMultilineEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0); + + /* Prepare clipboard data with simple text */ + hmem = GlobalAlloc(GMEM_MOVEABLE, 255); + ok(hmem != NULL, "got %p (expected != NULL)\n", hmem); + buffer = GlobalLock(hmem); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + strcpy(buffer, str); + GlobalUnlock(hmem); + + r = OpenClipboard(hEdit); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = EmptyClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + hmem_ret = SetClipboardData(CF_TEXT, hmem); + ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret); + r = CloseClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + + /* Paste single line */ + SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); + r = SendMessageA(hEdit, WM_PASTE, 0, 0); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok(strlen(str) == len, "got %d\n", len); + + /* Prepare clipboard data with multiline text */ + hmem = GlobalAlloc(GMEM_MOVEABLE, 255); + ok(hmem != NULL, "got %p (expected != NULL)\n", hmem); + buffer = GlobalLock(hmem); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + strcpy(buffer, str2); + GlobalUnlock(hmem); + + r = OpenClipboard(hEdit); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = EmptyClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + hmem_ret = SetClipboardData(CF_TEXT, hmem); + ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret); + r = CloseClipboard(); + ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + + /* Paste multiline text in singleline edit - should be cut */ + SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); + r = SendMessageA(hEdit, WM_PASTE, 0, 0); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok(strlen("first line") == len, "got %d\n", len); + + /* Paste multiline text in multiline edit */ + SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)""); + r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0); + len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0); + ok(strlen(str2) == len, "got %d\n", len); + + /* Cleanup */ + DestroyWindow(hEdit); + DestroyWindow(hMultilineEdit); +} + +static void test_EM_GETLINE(void) +{ + HWND hwnd[2]; + int i; + + hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + for (i = 0; i < sizeof(hwnd)/sizeof(hwnd[0]); i++) + { + static const WCHAR strW[] = {'t','e','x','t',0}; + static const char *str = "text"; + WCHAR buffW[16]; + char buff[16]; + int r; + + todo_wine_if(i == 0) + ok(IsWindowUnicode(hwnd[i]), "Expected unicode window.\n"); + + SendMessageA(hwnd[i], WM_SETTEXT, 0, (LPARAM)str); + + memset(buff, 0, sizeof(buff)); + *(WORD *)buff = sizeof(buff); + r = SendMessageA(hwnd[i], EM_GETLINE, 0, (LPARAM)buff); + ok(r == strlen(str), "Failed to get a line %d.\n", r); + ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff); + + memset(buff, 0, sizeof(buff)); + *(WORD *)buff = sizeof(buff); + r = SendMessageA(hwnd[i], EM_GETLINE, 1, (LPARAM)buff); + ok(r == strlen(str), "Failed to get a line %d.\n", r); + ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff); + + memset(buffW, 0, sizeof(buffW)); + *(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]); + r = SendMessageW(hwnd[i], EM_GETLINE, 0, (LPARAM)buffW); + ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r); + ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW)); + + memset(buffW, 0, sizeof(buffW)); + *(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]); + r = SendMessageW(hwnd[i], EM_GETLINE, 1, (LPARAM)buffW); + ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r); + ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW)); + + DestroyWindow(hwnd[i]); + } +} + +START_TEST(edit) +{ + ULONG_PTR ctx_cookie; + HANDLE hCtx; + BOOL b; + + if (!load_v6_module(&ctx_cookie, &hCtx)) + return; + + hinst = GetModuleHandleA(NULL); + b = register_classes(); + ok(b, "Failed to register test classes.\n"); + if (!b) return; + + test_edit_control_1(); + test_edit_control_2(); + test_edit_control_3(); + test_char_from_pos(); + test_edit_control_5(); + test_edit_control_6(); + test_edit_control_limittext(); + test_edit_control_scroll(); + test_margins(); + test_margins_font_change(); + test_text_position(); + test_espassword(); + test_undo(); + test_enter(); + test_tab(); + test_edit_dialog(); + test_multi_edit_dialog(); + test_wantreturn_edit_dialog(); + test_singleline_wantreturn_edit_dialog(); + test_child_edit_wmkeydown(); + test_fontsize(); + test_dialogmode(); + test_contextmenu(); + test_EM_GETHANDLE(); + test_paste(); + test_EM_GETLINE(); + + UnregisterWindowClasses(); + + unload_v6_module(ctx_cookie, hCtx); +} diff --git a/modules/rostests/winetests/comctl32/imagelist.c b/modules/rostests/winetests/comctl32/imagelist.c index 57e7f5c069..55466ac37a 100644 --- a/modules/rostests/winetests/comctl32/imagelist.c +++ b/modules/rostests/winetests/comctl32/imagelist.c @@ -49,6 +49,7 @@ typedef struct _ILHEAD #include "poppack.h"
static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int); +static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST); static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP); static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*); static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT); @@ -56,6 +57,22 @@ static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *, REFIID,void **); static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **); static int (WINAPI *pImageList_SetColorTable)(HIMAGELIST,int,int,RGBQUAD*); +static DWORD (WINAPI *pImageList_GetFlags)(HIMAGELIST); +static BOOL (WINAPI *pImageList_BeginDrag)(HIMAGELIST, int, int, int); +static HIMAGELIST (WINAPI *pImageList_GetDragImage)(POINT *, POINT *); +static void (WINAPI *pImageList_EndDrag)(void); +static INT (WINAPI *pImageList_GetImageCount)(HIMAGELIST); +static BOOL (WINAPI *pImageList_SetDragCursorImage)(HIMAGELIST, int, int, int); +static BOOL (WINAPI *pImageList_GetIconSize)(HIMAGELIST, int *, int *); +static BOOL (WINAPI *pImageList_Remove)(HIMAGELIST, int); +static INT (WINAPI *pImageList_ReplaceIcon)(HIMAGELIST, int, HICON); +static BOOL (WINAPI *pImageList_Replace)(HIMAGELIST, int, HBITMAP, HBITMAP); +static HIMAGELIST (WINAPI *pImageList_Merge)(HIMAGELIST, int, HIMAGELIST, int, int, int); +static BOOL (WINAPI *pImageList_GetImageInfo)(HIMAGELIST, int, IMAGEINFO *); +static BOOL (WINAPI *pImageList_Write)(HIMAGELIST, IStream *); +static HIMAGELIST (WINAPI *pImageList_Read)(IStream *); +static BOOL (WINAPI *pImageList_Copy)(HIMAGELIST, int, HIMAGELIST, int, UINT); +static HIMAGELIST (WINAPI *pImageList_LoadImageW)(HINSTANCE, LPCWSTR, int, int, COLORREF, UINT, UINT);
static HINSTANCE hinst;
@@ -69,6 +86,11 @@ static void force_redraw(HWND hwnd) Sleep(1000); }
+static BOOL is_v6_test(void) +{ + return pHIMAGELIST_QueryInterface != NULL; +} + /* These macros build cursor/bitmap data in 4x4 pixel blocks */ #define B(x,y) ((x?0xf0:0)|(y?0xf:0)) #define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h) @@ -112,14 +134,16 @@ static const BYTE bitmap_bits[48*48/8] = static HIMAGELIST createImageList(int cx, int cy) { /* Create an ImageList and put an image into it */ - HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1); + HIMAGELIST himl = pImageList_Create(cx, cy, ILC_COLOR, 1, 1); HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits); - ImageList_Add(himl, hbm, NULL); + + ok(himl != NULL, "Failed to create image list, %d x %d.\n", cx, cy); + pImageList_Add(himl, hbm, NULL); DeleteObject(hbm); return himl; }
-static HWND create_a_window(void) +static HWND create_window(void) { char className[] = "bmwnd"; char winName[] = "Test Bitmap"; @@ -246,41 +270,41 @@ static void test_begindrag(void) int count; POINT hotspot;
- count = ImageList_GetImageCount(himl); + count = pImageList_GetImageCount(himl); ok(count > 2, "Tests need an ImageList with more than 2 images\n");
/* Two BeginDrag() without EndDrag() in between */ - ret = ImageList_BeginDrag(himl, 1, 0, 0); - drag = ImageList_GetDragImage(NULL, NULL); + ret = pImageList_BeginDrag(himl, 1, 0, 0); + drag = pImageList_GetDragImage(NULL, NULL); ok(ret && drag, "ImageList_BeginDrag() failed\n"); - ret = ImageList_BeginDrag(himl, 0, 3, 5); + ret = pImageList_BeginDrag(himl, 0, 3, 5); ok(!ret, "ImageList_BeginDrag() returned TRUE\n"); ... 5112 lines suppressed ...