| /* 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 <windows.h> | |
| #include <commctrl.h> | |
| #include <imm.h> | |
| #include "wine/test.h" | |
| #include "v6util.h" | |
| #include "msg.h" | |
| #ifndef ES_COMBO | |
| #define ES_COMBO 0x200 | |
| #endif | |
| #define ID_EDITTESTDBUTTON 0x123 | |
| #define ID_EDITTEST2 99 | |
| #define MAXLEN 200 | |
| enum seq_index | |
| { | |
| COMBINED_SEQ_INDEX = 0, | |
| NUM_MSG_SEQUENCES, | |
| }; | |
| enum msg_id | |
| { | |
| PARENT_ID, | |
| EDIT_ID, | |
| }; | |
| static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; | |
| static void CALLBACK msg_winevent_proc(HWINEVENTHOOK hevent, | |
| DWORD event, | |
| HWND hwnd, | |
| LONG object_id, | |
| LONG child_id, | |
| DWORD thread_id, | |
| DWORD event_time) | |
| { | |
| struct message msg = {0}; | |
| char class_name[256]; | |
| /* ignore window and other system events */ | |
| if (object_id != OBJID_CLIENT) return; | |
| /* ignore events not from an edit control */ | |
| if (!GetClassNameA(hwnd, class_name, ARRAY_SIZE(class_name)) || | |
| strcmp(class_name, WC_EDITA) != 0) | |
| return; | |
| msg.message = event; | |
| msg.flags = winevent_hook|wparam|lparam; | |
| msg.wParam = object_id; | |
| msg.lParam = child_id; | |
| add_message(sequences, COMBINED_SEQ_INDEX, &msg); | |
| } | |
| static void init_winevent_hook(void) { | |
| hwineventhook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandleA(0), msg_winevent_proc, | |
| 0, GetCurrentThreadId(), WINEVENT_INCONTEXT); | |
| if (!hwineventhook) | |
| win_skip( "no win event hook support\n" ); | |
| } | |
| static void uninit_winevent_hook(void) { | |
| if (!hwineventhook) | |
| return; | |
| UnhookWinEvent(hwineventhook); | |
| hwineventhook = 0; | |
| } | |
| struct edit_notify { | |
| int en_change, en_maxtext, en_update; | |
| }; | |
| static struct edit_notify notifications; | |
| /* try to make sure pending X events have been processed before continuing */ | |
| static void flush_events(void) | |
| { | |
| MSG msg; | |
| int diff = 200; | |
| int min_timeout = 100; | |
| DWORD time = GetTickCount() + diff; | |
| while (diff > 0) | |
| { | |
| if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) | |
| break; | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) | |
| DispatchMessageA(&msg); | |
| diff = time - GetTickCount(); | |
| } | |
| } | |
| static BOOL open_clipboard(HWND hwnd) | |
| { | |
| DWORD start = GetTickCount(); | |
| while (1) | |
| { | |
| BOOL ret = OpenClipboard(hwnd); | |
| if (ret || GetLastError() != ERROR_ACCESS_DENIED) | |
| return ret; | |
| if (GetTickCount() - start > 100) | |
| { | |
| char classname[256]; | |
| DWORD le = GetLastError(); | |
| HWND clipwnd = GetOpenClipboardWindow(); | |
| /* Provide a hint as to the source of interference: | |
| * - The class name would typically be CLIPBRDWNDCLASS if the | |
| * clipboard was opened by a Windows application using the | |
| * ole32 API. | |
| * - And it would be __wine_clipboard_manager if it was opened in | |
| * response to a native application. | |
| */ | |
| GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); | |
| trace("%p (%s) opened the clipboard\n", clipwnd, classname); | |
| SetLastError(le); | |
| return ret; | |
| } | |
| Sleep(15); | |
| } | |
| } | |
| 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, WC_EDITA, "Text Text", style, 10, 10, 300, 300, | |
| NULL, NULL, hinst, NULL); | |
| ok (handle != NULL, "CreateWindow EDIT Control failed\n"); | |
| 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"); | |
| 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"); | |
| 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 %ld\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%lx\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 %lx\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%lx\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 %lx\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%lx\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 %lx\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%lx\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 %lx\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); | |
| ok(hwndMain != NULL, "Failed to create control parent.\n"); | |
| if (winetest_interactive) | |
| ShowWindow (hwndMain, SW_SHOW); | |
| hwndET2 = CreateWindowA(WC_EDITA, 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); | |
| ok(hwndET2 != NULL, "Failed to create Edit control.\n"); | |
| 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: %ld\n", 1, r); | |
| r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); | |
| ok(1 == r, "Expected: %d, got: %ld\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: %ld\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: %ld\n", r); | |
| r = GetCaretPos(&cpos); | |
| ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%ld,%ld)\n", cpos.x, cpos.y); | |
| r = SetCaretPos(-1, -1); | |
| ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| r = GetCaretPos(&cpos); | |
| ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%ld,%ld)\n", cpos.x, cpos.y); | |
| r = SetCaretPos(w << 1, h << 1); | |
| ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| r = GetCaretPos(&cpos); | |
| ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| ok(cpos.x == (w << 1) && cpos.y == (h << 1), "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w << 1, h << 1, cpos.x, cpos.y); | |
| r = SetCaretPos(w, h); | |
| ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| r = GetCaretPos(&cpos); | |
| ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w, h, cpos.x, cpos.y); | |
| r = SetCaretPos(w - 1, h - 1); | |
| ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| r = GetCaretPos(&cpos); | |
| ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); | |
| ok(cpos.x == (w - 1) && cpos.y == (h - 1), "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\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); | |
| } | |
| static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |
| { | |
| static LONG defwndproc_counter = 0; | |
| struct message msg = { 0 }; | |
| LRESULT ret; | |
| msg.message = message; | |
| msg.flags = sent|wparam|id; | |
| if (defwndproc_counter) msg.flags |= defwinproc; | |
| msg.wParam = wParam; | |
| msg.id = PARENT_ID; | |
| if (message != WM_IME_SETCONTEXT && | |
| message != WM_IME_NOTIFY && | |
| message != WM_GETICON && | |
| message != WM_DWMNCRENDERINGCHANGED && | |
| message != WM_GETMINMAXINFO && | |
| message != WM_PAINT && | |
| message != WM_CTLCOLOREDIT && | |
| message != WM_WINDOWPOSCHANGING && | |
| message != WM_WINDOWPOSCHANGED && | |
| message != WM_MOVE && | |
| message != WM_MOUSEACTIVATE && | |
| message < 0xc000) | |
| { | |
| add_message(sequences, COMBINED_SEQ_INDEX, &msg); | |
| } | |
| defwndproc_counter++; | |
| ret = DefWindowProcA(hwnd, message, wParam, lParam); | |
| defwndproc_counter--; | |
| return ret; | |
| } | |
| static LRESULT CALLBACK edit_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|id; | |
| if (defwndproc_counter) msg.flags |= defwinproc; | |
| msg.wParam = wParam; | |
| msg.id = EDIT_ID; | |
| if (message != WM_IME_SETCONTEXT && | |
| message != WM_IME_NOTIFY) | |
| { | |
| add_message(sequences, COMBINED_SEQ_INDEX, &msg); | |
| } | |
| defwndproc_counter++; | |
| if (IsWindowUnicode(hwnd)) | |
| ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam); | |
| else | |
| ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); | |
| defwndproc_counter--; | |
| return ret; | |
| } | |
| /* 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); | |
| ok(hParent != NULL, "Failed to create control parent.\n"); | |
| trace("EDIT: Single line, no ES_AUTOHSCROLL\n"); | |
| hWnd = CreateWindowExA(0, WC_EDITA, NULL, 0, 10, 10, 50, 50, hParent, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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, WC_EDITA, NULL, ES_AUTOHSCROLL, 10, 10, 50, 50, hParent, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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, WC_EDITA, NULL, ES_MULTILINE, | |
| 10, 10, (50 * dpi) / 96, (50 * dpi) / 96, | |
| hParent, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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, WC_EDITA, NULL, ES_MULTILINE | ES_AUTOHSCROLL, | |
| 10, 10, (50 * dpi) / 96, (50 * dpi) / 96, | |
| hParent, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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, WC_EDITA, NULL, ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, | |
| 10, 10, 50, 50, hParent, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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; | |
| HDC dc; | |
| SIZE size; | |
| 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 + 1) / 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 + 1) / 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 + 1) / 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 + 1) / 2; | |
| 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 + 1) / 2; | |
| 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 + 1) / 2; | |
| 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); | |
| /* Scrolled to the right with partially visible line, position on next line. */ | |
| hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); | |
| dc = GetDC(hwEdit); | |
| GetTextExtentPoint32A(dc, "w", 1, &size); | |
| ReleaseDC(hwEdit, dc); | |
| SetWindowPos(hwEdit, NULL, 0, 0, size.cx * 15, size.cy * 5, SWP_NOMOVE | SWP_NOZORDER); | |
| SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"wwwwwwwwwwwwwwwwwwww\r\n\r\n"); | |
| SendMessageA(hwEdit, EM_SETSEL, 40, 40); | |
| lo = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 22, 0); | |
| ret = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 20, 0); | |
| ret -= 20 * size.cx; /* Calculate expected position, 20 characters back. */ | |
| ok(ret == lo, "Unexpected position %d vs %d.\n", lo, 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, WC_EDITA, str, 0, 10, 10, 1, 1, NULL, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| /* size of non-child edit control is (much) bigger than requested */ | |
| GetWindowRect( hWnd, &rc); | |
| ok( rc.right - rc.left > 20, "size of the window (%ld) 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); | |
| ok(parentWnd != NULL, "Failed to create control parent.\n"); | |
| ShowWindow( parentWnd, SW_SHOW); | |
| /* single line */ | |
| hWnd = CreateWindowExA(0, WC_EDITA, str, WS_VISIBLE | WS_BORDER | WS_CHILD, | |
| rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, | |
| parentWnd, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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, WC_EDITA, str, WS_CHILD | ES_MULTILINE, | |
| rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, | |
| parentWnd, NULL, NULL, NULL); | |
| ok(hWnd != NULL, "Failed to create Edit control.\n"); | |
| 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 %ld\n", TRUE, ret); | |
| ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); | |
| ok(ret == strlen(str), "Expected %s, got len %ld\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 %ld\n", ret); | |
| ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); | |
| ok(ret == strlen(str), "Expected %s, got len %ld\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 %ld\n", ret); | |
| ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); | |
| todo_wine { | |
| ok(ret == strlen("Test"), "Unexpected text length %ld\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 %lu\n", r); | |
| SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); | |
| r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); | |
| ok( r == 2147483646, "got limit %lu (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 %lu\n", r); | |
| SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); | |
| r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); | |
| ok( r == 4294967295U, "got limit %lu (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(WC_EDITA, single_line_str, WS_VSCROLL | ES_MULTILINE, | |
| 1, 1, 100, 100, NULL, NULL, hinst, NULL); | |
| ok(hwEdit != NULL, "Failed to create Edit control.\n"); | |
| ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); | |
| ok(!ret, "Returned %lx, expected 0.\n", ret); | |
| ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEUP, 0); | |
| ok(!ret, "Returned %lx, expected 0.\n", ret); | |
| ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEUP, 0); | |
| ok(!ret, "Returned %lx, expected 0.\n", ret); | |
| ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEDOWN, 0); | |
| ok(!ret, "Returned %lx, 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(WC_EDITA, multiline_str, WS_VSCROLL | ES_MULTILINE, | |
| 0, 0, 100, 100, NULL, NULL, hinst, NULL); | |
| ok(hwEdit != NULL, "Failed to create Edit control.\n"); | |
| ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); | |
| ok(!ret, "Returned %lx, expected 0.\n", ret); | |
| DestroyWindow (hwEdit); | |
| } | |
| static BOOL is_cjk(HDC dc) | |
| { | |
| const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB; | |
| FONTSIGNATURE fs; | |
| switch (GdiGetCodePage(dc)) { | |
| case 932: case 936: case 949: case 950: case 1361: | |
| return TRUE; | |
| default: | |
| return (GetTextCharsetInfo(dc, &fs, 0) != DEFAULT_CHARSET && | |
| (fs.fsCsb[0] & FS_DBCS_MASK)); | |
| } | |
| } | |
| static void test_margins_usefontinfo(UINT charset) | |
| { | |
| HWND hwnd; | |
| HDC hdc; | |
| TEXTMETRICW tm; | |
| SIZE size; | |
| LOGFONTA lf; | |
| HFONT hfont; | |
| RECT rect; | |
| INT margins, threshold, expect, empty_expect; | |
| const UINT small_margins = MAKELONG(1, 5); | |
| 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, &tm, &size.cy ); | |
| if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) || | |
| !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { | |
| skip("%s for charset %d isn't available\n", lf.lfFaceName, charset); | |
| hfont = SelectObject(hdc, hfont); | |
| ReleaseDC(hwnd, hdc); | |
| DestroyWindow(hwnd); | |
| DeleteObject(hfont); | |
| return; | |
| } | |
| expect = MAKELONG(size.cx / 2, size.cx / 2); | |
| 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)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| expect = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| DestroyWindow(hwnd); | |
| threshold = HIWORD(expect) + LOWORD(expect) + size.cx * 2; | |
| empty_expect = threshold > 80 ? small_margins : expect; | |
| /* Size below the threshold, margins remain unchanged */ | |
| 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)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == small_margins, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); | |
| DestroyWindow(hwnd); | |
| /* Size at the threshold, 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)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| 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)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| 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 INT get_cjk_fontinfo_margin(INT width, INT side_bearing) | |
| { | |
| INT margin; | |
| if (side_bearing < 0) | |
| margin = min(-side_bearing, width/2); | |
| else | |
| margin = 0; | |
| return margin; | |
| } | |
| static DWORD get_cjk_font_margins(HDC hdc) | |
| { | |
| ABC abc[256]; | |
| SHORT left, right; | |
| UINT i; | |
| if (!GetCharABCWidthsW(hdc, 0, 255, abc)) | |
| return 0; | |
| left = right = 0; | |
| for (i = 0; i < ARRAY_SIZE(abc); i++) { | |
| if (-abc[i].abcA > right) right = -abc[i].abcA; | |
| if (-abc[i].abcC > left) left = -abc[i].abcC; | |
| } | |
| return MAKELONG(left, right); | |
| } | |
| static void test_margins_default(const char* facename, UINT charset) | |
| { | |
| HWND hwnd; | |
| HDC hdc; | |
| TEXTMETRICW tm; | |
| SIZE size; | |
| BOOL cjk; | |
| LOGFONTA lf; | |
| HFONT hfont; | |
| RECT rect; | |
| INT margins, expect, font_expect; | |
| const UINT small_margins = MAKELONG(1, 5); | |
| const WCHAR EditW[] = {'E','d','i','t',0}, strW[] = {'W',0}; | |
| struct char_width_info { | |
| INT lsb, rsb, unknown; | |
| } info; | |
| HMODULE hgdi32; | |
| BOOL (WINAPI *pGetCharWidthInfo)(HDC, struct char_width_info *); | |
| hgdi32 = GetModuleHandleA("gdi32.dll"); | |
| pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo"); | |
| memset(&lf, 0, sizeof(lf)); | |
| lf.lfHeight = -11; | |
| lf.lfWeight = FW_NORMAL; | |
| lf.lfCharSet = charset; | |
| strcpy(lf.lfFaceName, facename); | |
| hfont = CreateFontIndirectA(&lf); | |
| ok(hfont != NULL, "got %p\n", hfont); | |
| /* Unicode version */ | |
| hwnd = CreateWindowExW(0, EditW, strW, 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, &tm, &size.cy ); | |
| if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) || | |
| !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { | |
| skip("%s for charset %d isn't available\n", lf.lfFaceName, charset); | |
| hfont = SelectObject(hdc, hfont); | |
| ReleaseDC(hwnd, hdc); | |
| DestroyWindow(hwnd); | |
| DeleteObject(hfont); | |
| return; | |
| } | |
| cjk = is_cjk(hdc); | |
| if (cjk && pGetCharWidthInfo && pGetCharWidthInfo(hdc, &info)) { | |
| short left, right; | |
| left = get_cjk_fontinfo_margin(size.cx, info.lsb); | |
| right = get_cjk_fontinfo_margin(size.cx, info.rsb); | |
| expect = MAKELONG(left, right); | |
| font_expect = get_cjk_font_margins(hdc); | |
| if (!font_expect) | |
| /* In this case, margins aren't updated */ | |
| font_expect = small_margins; | |
| } | |
| else | |
| font_expect = expect = MAKELONG(size.cx / 2, size.cx / 2); | |
| hfont = SelectObject(hdc, hfont); | |
| ReleaseDC(hwnd, hdc); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == 0, "got %x\n", margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins)); | |
| DestroyWindow(hwnd); | |
| /* ANSI version */ | |
| 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)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == 0, "got %x\n", margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins)); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); | |
| SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); | |
| margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); | |
| ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins)); | |
| DestroyWindow(hwnd); | |
| DeleteObject(hfont); | |
| } | |
| static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) | |
| { | |
| return 0; | |
| } | |
| static BOOL is_font_installed(const char*name) | |
| { | |
| HDC hdc = GetDC(NULL); | |
| BOOL ret = FALSE; | |
| if (!EnumFontFamiliesA(hdc, name, find_font_proc, 0)) | |
| ret = TRUE; | |
| ReleaseDC(NULL, hdc); | |
| return ret; | |
| } | |
| static WNDPROC orig_class_proc; | |
| static LRESULT CALLBACK test_class_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |
| { | |
| RECT rect; | |
| LRESULT result, r; | |
| switch (message) | |
| { | |
| case WM_NCCREATE: | |
| result = CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam); | |
| memset(&rect, 0, sizeof(rect)); | |
| SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rect); | |
| ok(!rect.right && !rect.bottom, "Invalid size after NCCREATE: %ld x %ld\n", rect.right, rect.bottom); | |
| /* test that messages between WM_NCCREATE and WM_CREATE | |
| don't crash or cause unexpected behavior */ | |
| r = SendMessageA(hwnd, EM_SETSEL, 0, 0); | |
| ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010); | |
| todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1); | |
| ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| return result; | |
| case WM_CREATE: | |
| /* test that messages between WM_NCCREATE and WM_CREATE | |
| don't crash or cause unexpected behavior */ | |
| r = SendMessageA(hwnd, EM_SETSEL, 0, 0); | |
| ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010); | |
| todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1); | |
| ok(r == 1, "Returned %Id, expected 1.\n", r); | |
| break; | |
| } | |
| return CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam); | |
| } | |
| static void test_initialization(void) | |
| { | |
| BOOL ret; | |
| ATOM atom; | |
| HWND hwEdit; | |
| WNDCLASSA cls; | |
| ret = GetClassInfoA(NULL, "Edit", &cls); | |
| ok(ret, "Failed to get class info.\n"); | |
| orig_class_proc = cls.lpfnWndProc; | |
| cls.lpfnWndProc = test_class_proc; | |
| cls.lpszClassName = "TestClassName"; | |
| atom = RegisterClassA(&cls); | |
| ok(atom != 0, "Failed to register class.\n"); | |
| hwEdit = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atom), "Text Text", | |
| ES_MULTILINE | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, | |
| 10, 10, 300, 300, NULL, NULL, hinst, NULL); | |
| ok(hwEdit != NULL, "Failed to create a window.\n"); | |
| DestroyWindow(hwEdit); | |
| UnregisterClassA((LPCSTR)MAKEINTATOM(atom), hinst); | |
| } | |
| 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); | |
| test_margins_default("Tahoma", ANSI_CHARSET); | |
| test_margins_default("Tahoma", EASTEUROPE_CHARSET); | |
| test_margins_default("Tahoma", HANGUL_CHARSET); | |
| test_margins_default("Tahoma", CHINESEBIG5_CHARSET); | |
| if (is_font_installed("MS PGothic")) { | |
| test_margins_default("MS PGothic", SHIFTJIS_CHARSET); | |
| test_margins_default("MS PGothic", GREEK_CHARSET); | |
| } | |
| else | |
| skip("MS PGothic is not available, skipping some margin tests\n"); | |
| if (is_font_installed("Ume P Gothic")) { | |
| test_margins_default("Ume P Gothic", SHIFTJIS_CHARSET); | |
| test_margins_default("Ume P Gothic", GREEK_CHARSET); | |
| } | |
| else | |
| skip("Ume P Gothic is not available, skipping some margin tests\n"); | |
| if (is_font_installed("SimSun")) { | |
| test_margins_default("SimSun", GB2312_CHARSET); | |
| test_margins_default("SimSun", ANSI_CHARSET); | |
| } | |
| else | |
| skip("SimSun is not available, skipping some margin tests\n"); | |
| } | |
| static void test_margins_font_change(void) | |
| { | |
| DWORD margins, font_margins; | |
| HFONT hfont, hfont2; | |
| HWND hwEdit; | |
| LOGFONTA lf; | |
| if (!is_font_installed("Arial")) | |
| { | |
| skip("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 = GREEK_CHARSET; /* to avoid associated charset feature */ | |
| 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(expected, got, txt) edit_pos_ok_(__LINE__, expected, got, #txt) | |
| static inline void edit_pos_ok_(unsigned line, DWORD expected, DWORD got, const char* txt) | |
| { | |
| ok_(__FILE__, line)(expected == got, "wrong %s expected %ld got %ld\n", txt, expected, 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) | |
| /* Starting with Win10, multiline edit controls can have any value for height. | |
| * Before, they always have a height which is a multiple of the font height. | |
| * So detect which model we're running the tests on, and adjust the expected | |
| * height accordingly. | |
| */ | |
| static BOOL old_height_model; | |
| static DWORD compute_height(BOOL single_line, unsigned line_height, unsigned incr, unsigned limit) | |
| { | |
| if (single_line) return line_height; | |
| if (incr >= limit) incr -= limit; | |
| return old_height_model ? (line_height + incr) - ((line_height + incr) % line_height) : line_height + incr; | |
| } | |
| static void get_font_and_metrics(HFONT *font, TEXTMETRICA *metrics) | |
| { | |
| HDC dc; | |
| HFONT old_font; | |
| BOOL xb; | |
| /* 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"); | |
| old_font = SelectObject(dc, font); | |
| xb = GetTextMetricsA(dc, metrics); | |
| ok (xb, "GetTextMetrics failed\n"); | |
| SelectObject(dc, old_font); | |
| ReleaseDC(NULL, dc); | |
| } | |
| static BOOL determine_height_model(void) | |
| { | |
| HWND hedit; | |
| HFONT font; | |
| TEXTMETRICA metrics; | |
| RECT format_rect; | |
| BOOL ret = TRUE; | |
| get_font_and_metrics(&font, &metrics); | |
| hedit = create_child_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_VISIBLE, 0); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| set_client_height(hedit, metrics.tmHeight + 1); | |
| SendMessageA(hedit, EM_GETRECT, 0, (LPARAM) &format_rect); | |
| old_height_model = TRUE; | |
| if (format_rect.bottom - format_rect.top == metrics.tmHeight + 1) | |
| old_height_model = FALSE; | |
| else | |
| ret = format_rect.bottom - format_rect.top == metrics.tmHeight; | |
| destroy_child_editcontrol(hedit); | |
| return ret; | |
| } | |
| static void test_text_position_style(DWORD style) | |
| { | |
| HWND hedit; | |
| HFONT font; | |
| TEXTMETRICA metrics; | |
| INT b, b2, incr; | |
| BOOL single_line = !(style & ES_MULTILINE); | |
| get_font_and_metrics(&font, &metrics); | |
| b = GetSystemMetrics(SM_CYBORDER) + 1; | |
| b2 = 2 * b; | |
| /* 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 */ | |
| hedit = create_child_editcontrol(style | WS_VISIBLE, 0); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 0), 0); | |
| destroy_child_editcontrol(hedit); | |
| hedit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, 0); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= b2 ? b : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, b2), b); | |
| destroy_child_editcontrol(hedit); | |
| hedit = create_child_editcontrol(style | WS_VISIBLE, WS_EX_CLIENTEDGE); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= 2 ? 1 : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 2), 1); | |
| destroy_child_editcontrol(hedit); | |
| hedit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, WS_EX_CLIENTEDGE); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= 2 ? 1 : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 2), 1); | |
| destroy_child_editcontrol(hedit); | |
| /* Edit controls that are popup windows */ | |
| hedit = create_editcontrol(style | WS_POPUP, 0); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 0), 0); | |
| DestroyWindow(hedit); | |
| hedit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= b2 ? b : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, b2), b); | |
| DestroyWindow(hedit); | |
| hedit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= 2 ? 1 : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 2), 1); | |
| DestroyWindow(hedit); | |
| hedit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE); | |
| SendMessageA(hedit, WM_SETFONT, (WPARAM) font, FALSE); | |
| if (single_line) | |
| check_pos(hedit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1); | |
| for (incr = 0; incr < 4 * metrics.tmHeight; incr++) | |
| check_pos(hedit, metrics.tmHeight + incr, incr >= 2 ? 1 : 0, | |
| compute_height(single_line, metrics.tmHeight, incr, 2), 1); | |
| DestroyWindow(hedit); | |
| } | |
| static void test_text_position(void) | |
| { | |
| ok (determine_height_model(), "Unable to guess the height model, forcing old one\n"); | |
| trace("EDIT: Using %s model for height computation\n", old_height_model ? "old" : "new"); | |
| 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%lx\n", r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) password); | |
| ok(r == TRUE, "Expected: %d, got: %ld\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: %ld\n", 1, r); | |
| /* get text */ | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); | |
| ok(r == strlen(password), "Expected: %s, got len %ld\n", password, r); | |
| ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer); | |
| r = open_clipboard(hwEdit); | |
| ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); | |
| r = EmptyClipboard(); | |
| ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); | |
| r = CloseClipboard(); | |
| ok(r == TRUE, "expected %d, got %ld\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: %ld\n", 1, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, 22, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); | |
| ok(r == 0, "Expected: 0, got: %ld\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%lx\n", 0, r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) text); | |
| ok(TRUE == r, "Expected: %d, got: %ld\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 %ld\n", r); | |
| ok(0 == cpMin, "Expected: %d, got %ld\n", 0, cpMin); | |
| ok(9 == cpMax, "Expected: %d, got %ld\n", 9, cpMax); | |
| /* cut (ctrl-x) */ | |
| r = SendMessageA(hwEdit, WM_CHAR, 24, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); | |
| ok(0 == r, "Expected: %d, got len %ld\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: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); | |
| ok(strlen(text) == r, "Unexpected length %ld\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: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); | |
| ok(r == 0, "Expected: %d, got len %ld\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%lx\n", r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); | |
| ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); | |
| ok(2 == r, "Expected: %d, got len %ld\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%lx\n", 0, r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); | |
| ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); | |
| ok(0 == r, "Expected: %d, got len %ld\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%lx\n", r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); | |
| ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); | |
| ok(0 == r, "Expected: %d, got len %ld\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%lx\n", r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); | |
| ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); | |
| ok(1 == r, "Expected: %d, got len %ld\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%lx\n", 0, r); | |
| /* set text */ | |
| r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); | |
| ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| /* get text */ | |
| buffer[0] = 0; | |
| r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); | |
| ok(0 == r, "Expected: %d, got len %ld\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); | |
| ok(hwndMain != NULL, "Failed to create control parent.\n"); | |
| hwndEdit = CreateWindowA(WC_EDITA, 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); | |
| ok(hwndEdit != NULL, "Failed to create Edit control.\n"); | |
| 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; | |
| WNDCLASSA wc; | |
| 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; | |
| memset(&wc, 0, sizeof(wc)); | |
| wc.lpfnWndProc = parent_wnd_proc; | |
| wc.hInstance = GetModuleHandleA(NULL); | |
| wc.lpszClassName = "ParentWnd"; | |
| if (!RegisterClassA(&wc)) 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: %ld\n", 1, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, 'B', 1); | |
| ok(1 == r, "Expected: %d, got: %ld\n", 1, r); | |
| r = SendMessageA(hwEdit, WM_CHAR, 'C', 1); | |
| ok(1 == r, "Expected: %d, got: %ld\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 %ld\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); | |
| 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); | |
| 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); | |
| 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); | |
| 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); | |
| ok(len == lstrlenA(str2), "got %d (expected %d)\n", len, lstrlenA(str2)); | |
| lstrcpyA(current, str0); | |
| r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); | |
| 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); | |
| } | |
| /* In Windows 10+, the WM_PASTE message isn't always successful. | |
| * So retry in case of failure. | |
| */ | |
| #define check_paste(a, b) _check_paste(__LINE__, (a), (b)) | |
| static void _check_paste(unsigned int line, HWND hedit, const char *content) | |
| { | |
| /* only retry on windows platform */ | |
| int tries = strcmp(winetest_platform, "wine") ? 3 : 1; | |
| int len = 0; | |
| SendMessageA(hedit, WM_SETTEXT, 0, (LPARAM)""); | |
| do | |
| { | |
| SendMessageA(hedit, WM_PASTE, 0, 0); | |
| if ((len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0))) break; | |
| Sleep(1); | |
| } while (--tries > 0); | |
| ok_(__FILE__, line)(len == strlen(content), "Unexpected len %u in edit\n", len); | |
| } | |
| 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; | |
| 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 = open_clipboard(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 */ | |
| check_paste(hEdit, str); | |
| /* 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 = open_clipboard(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)""); | |
| check_paste(hEdit, "first line"); | |
| /* Paste multiline text in multiline edit */ | |
| check_paste(hMultilineEdit, str2); | |
| /* 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 < ARRAY_SIZE(hwnd); i++) | |
| { | |
| static const WCHAR strW[] = {'t','e','x','t',0}; | |
| static const char *str = "text"; | |
| WCHAR buffW[16]; | |
| char buff[16]; | |
| int r; | |
| 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 = ARRAY_SIZE(buffW); | |
| 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 = ARRAY_SIZE(buffW); | |
| 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]); | |
| } | |
| } | |
| static int CALLBACK test_wordbreak_procA(char *text, int current, int length, int code) | |
| { | |
| return -1; | |
| } | |
| static void test_wordbreak_proc(void) | |
| { | |
| EDITWORDBREAKPROCA proc; | |
| LRESULT ret; | |
| HWND hwnd; | |
| hwnd = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); | |
| proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0); | |
| ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc); | |
| ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)test_wordbreak_procA); | |
| ok(ret == 1, "Unexpected return value %Id.\n", ret); | |
| proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0); | |
| ok(proc == test_wordbreak_procA, "Unexpected wordbreak proc %p.\n", proc); | |
| ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, 0); | |
| ok(ret == 1, "Unexpected return value %Id.\n", ret); | |
| proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0); | |
| ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc); | |
| DestroyWindow(hwnd); | |
| } | |
| static const struct message setfocus_combined_seq[] = | |
| { | |
| { WM_KILLFOCUS, sent|id, 0, 0, PARENT_ID }, | |
| { EVENT_OBJECT_FOCUS, winevent_hook|lparam, 0, 0 }, | |
| { WM_SETFOCUS, sent|id, 0, 0, EDIT_ID }, | |
| { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_SETFOCUS), 0, PARENT_ID }, | |
| { WM_PAINT, sent|id, 0, 0, EDIT_ID }, | |
| { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, | |
| { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, | |
| { 0 } | |
| }; | |
| static const struct message killfocus_combined_seq[] = | |
| { | |
| { WM_KILLFOCUS, sent|id, 0, 0, EDIT_ID }, | |
| { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_KILLFOCUS), 0, PARENT_ID }, | |
| { WM_SETFOCUS, sent|id, 0, 0, PARENT_ID }, | |
| { WM_PAINT, sent|id, 0, 0, EDIT_ID }, | |
| { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, | |
| { 0 } | |
| }; | |
| static const struct message setfocus_sent_only_combined_seq[] = | |
| { | |
| { WM_KILLFOCUS, sent|id, 0, 0, PARENT_ID }, | |
| { EVENT_OBJECT_FOCUS, winevent_hook|lparam, 0, 0 }, | |
| { WM_SETFOCUS, sent|id, 0, 0, EDIT_ID }, | |
| { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_SETFOCUS), 0, PARENT_ID }, | |
| { 0 } | |
| }; | |
| static const struct message killfocus_sent_only_combined_seq[] = | |
| { | |
| { WM_KILLFOCUS, sent|id, 0, 0, EDIT_ID }, | |
| { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_KILLFOCUS), 0, PARENT_ID }, | |
| { WM_SETFOCUS, sent|id, 0, 0, PARENT_ID }, | |
| { 0 } | |
| }; | |
| static void test_cue_banner(void) | |
| { | |
| HWND hwnd_edit; | |
| BOOL ret; | |
| static WCHAR getcuetestW[5] = {'T',0}; | |
| static const WCHAR testcmp1W[] = {'T','e','s','t',0}; | |
| static const WCHAR testcmp2W[] = {'T','e','s',0}; | |
| hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); | |
| if (getcuetestW[0]) | |
| { | |
| win_skip("skipping for Win XP and 2003 Server.\n"); | |
| DestroyWindow(hwnd_edit); | |
| return; | |
| } | |
| ok(!getcuetestW[0], "First char is %c\n", getcuetestW[0]); | |
| ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); | |
| lstrcpyW(getcuetestW, testcmp1W); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 0); | |
| ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW)); | |
| ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0); | |
| ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, 0); | |
| ok(ret == FALSE, "EM_SETCUEBANNER should have returned FALSE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0); | |
| ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); | |
| lstrcpyW(getcuetestW, testcmp1W); | |
| ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW); | |
| ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 5); | |
| ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); | |
| ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); | |
| ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); | |
| ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)L""); | |
| ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); | |
| ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); | |
| ok(!getcuetestW[0], "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); | |
| /* EM_GETCUEBANNER's buffer size includes null char */ | |
| ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)testcmp1W); | |
| ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); | |
| memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR)); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)+1); | |
| ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); | |
| ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); | |
| memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR)); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)); | |
| ok(lstrcmpW(getcuetestW, testcmp2W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); | |
| DestroyWindow(hwnd_edit); | |
| /* setting cue banner fails for multi-line edit controls */ | |
| hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0); | |
| lstrcpyW(getcuetestW, testcmp1W); | |
| ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); | |
| ok(ret == FALSE, "EM_SETCUEBANNER.\n"); | |
| ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW)); | |
| ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW); | |
| ok(ret == FALSE, "EM_SETCUEBANNER.\n"); | |
| DestroyWindow(hwnd_edit); | |
| } | |
| static void test_change_focus(void) | |
| { | |
| HWND hwnd, parent_wnd; | |
| WNDPROC oldproc; | |
| MSG msg; | |
| POINT orig_pos; | |
| GetCursorPos(&orig_pos); | |
| parent_wnd = CreateWindowA("ParentWnd", "", WS_OVERLAPPEDWINDOW, | |
| 0, 0, 200, 200, NULL, NULL, GetModuleHandleA(NULL), NULL); | |
| ok(parent_wnd != NULL, "Failed to create control parent.\n"); | |
| SetWindowPos(parent_wnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); | |
| ShowWindow(parent_wnd, SW_SHOW); | |
| hwnd = CreateWindowExA(0, WC_EDITA, "Test", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, | |
| parent_wnd, (HMENU)1, GetModuleHandleA(NULL), NULL); | |
| ok(hwnd != NULL, "Failed to create Edit control.\n"); | |
| oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_subclass_proc); | |
| SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); | |
| SetCursorPos(400, 400); | |
| flush_events(); | |
| SetFocus(parent_wnd); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SetFocus(hwnd); | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, setfocus_combined_seq, "Set focus", FALSE); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SetFocus(parent_wnd); | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_combined_seq, "Kill focus", FALSE); | |
| /* Test message sequences without waiting for posted messages */ | |
| SetFocus(parent_wnd); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SetFocus(hwnd); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, setfocus_sent_only_combined_seq, | |
| "Set focus sent only", FALSE); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SetFocus(parent_wnd); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_sent_only_combined_seq, | |
| "Kill focus sent only", FALSE); | |
| SetCursorPos(orig_pos.x, orig_pos.y); | |
| DestroyWindow(hwnd); | |
| } | |
| static const struct message wm_ime_composition_seq[] = | |
| { | |
| {WM_IME_STARTCOMPOSITION, sent}, | |
| {WM_IME_COMPOSITION, sent | wparam, 'W'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'W'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'i'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'n'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'e'}, | |
| {WM_IME_ENDCOMPOSITION, sent}, | |
| {WM_CHAR, sent | wparam, 'W'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'i'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'n'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'e'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {0} | |
| }; | |
| static const struct message wm_ime_composition_korean_seq[] = | |
| { | |
| {WM_IME_ENDCOMPOSITION, sent}, | |
| {WM_IME_COMPOSITION, sent | wparam, 'W'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'W'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'i'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'n'}, | |
| {WM_IME_CHAR, sent | wparam | defwinproc, 'e'}, | |
| {WM_CHAR, sent | wparam, 'W'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'i'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'n'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_CHAR, sent | wparam, 'e'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {0} | |
| }; | |
| static const struct message wm_ime_char_seq[] = | |
| { | |
| {WM_IME_CHAR, sent | wparam, '0'}, | |
| {WM_CHAR, sent | wparam, '0'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {0} | |
| }; | |
| static const struct message eimes_getcompstratonce_seq[] = | |
| { | |
| {WM_IME_STARTCOMPOSITION, sent}, | |
| {WM_IME_COMPOSITION, sent | wparam, 'W'}, | |
| {EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam, 0, 0}, | |
| {WM_IME_ENDCOMPOSITION, sent}, | |
| {0} | |
| }; | |
| static LRESULT CALLBACK edit_ime_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; | |
| if (defwndproc_counter) | |
| msg.flags |= defwinproc; | |
| msg.wParam = wParam; | |
| if (message < 0xc000 && | |
| message != WM_GETTEXTLENGTH && | |
| message != WM_GETTEXT && | |
| message != WM_GETFONT && | |
| message != WM_GETICON && | |
| message != WM_IME_SETCONTEXT && | |
| message != WM_IME_NOTIFY && | |
| message != WM_CTLCOLOREDIT && | |
| message != WM_PAINT && | |
| message != WM_ERASEBKGND && | |
| message != WM_NCHITTEST && | |
| message != WM_SETCURSOR && | |
| message != WM_MOUSEMOVE && | |
| message != WM_MOUSEACTIVATE && | |
| message != WM_KEYUP && | |
| (message < EM_GETSEL || message > EM_GETIMESTATUS)) | |
| { | |
| add_message(sequences, COMBINED_SEQ_INDEX, &msg); | |
| } | |
| defwndproc_counter++; | |
| if (IsWindowUnicode(hwnd)) | |
| ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam); | |
| else | |
| ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); | |
| defwndproc_counter--; | |
| return ret; | |
| } | |
| static void test_ime(void) | |
| { | |
| static const HKL korean_hkl = (HKL)0x04120412; | |
| WNDPROC old_proc; | |
| LRESULT lr; | |
| HIMC himc; | |
| HWND hwnd; | |
| BOOL ret; | |
| HKL hkl; | |
| MSG msg; | |
| hkl = GetKeyboardLayout(0); | |
| hwnd = create_editcontrol(WS_POPUP | WS_VISIBLE, 0); | |
| /* Test EM_{GET|SET}IMESTATUS */ | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); | |
| /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about | |
| * returning the previous LPARAM value */ | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE | |
| | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS), | |
| "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); | |
| /* Invalid EM_{GET|SET}IMESTATUS status types and flags */ | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); | |
| /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */ | |
| old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc); | |
| SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc); | |
| flush_events(); | |
| himc = ImmGetContext(hwnd); | |
| ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); | |
| ok(ret, "ImmSetCompositionStringA failed.\n"); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); | |
| ok(ret, "ImmNotifyIME failed.\n"); | |
| /* Note that the following message loop is necessary to get the WM_CHAR messages because they | |
| * are posted. Same for the later message loops in this function. */ | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| if (hkl == korean_hkl) | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_composition_korean_seq, | |
| "korean WM_IME_COMPOSITION", TRUE); | |
| else | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE); | |
| /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */ | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SendMessageA(hwnd, WM_IME_CHAR, '0', 1); | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_char_seq, "WM_IME_CHAR", FALSE); | |
| /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */ | |
| lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE); | |
| ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); | |
| lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); | |
| ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr); | |
| ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); | |
| ok(ret, "ImmSetCompositionStringA failed.\n"); | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); | |
| ok(ret, "ImmNotifyIME failed.\n"); | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| if (hkl == korean_hkl) | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_composition_korean_seq, | |
| "Korean WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE); | |
| else | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, eimes_getcompstratonce_seq, | |
| "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE); | |
| /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */ | |
| flush_sequences(sequences, NUM_MSG_SEQUENCES); | |
| SendMessageA(hwnd, WM_IME_CHAR, '0', 1); | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); | |
| ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_char_seq, "WM_IME_CHAR", FALSE); | |
| ImmReleaseContext(hwnd, himc); | |
| DestroyWindow(hwnd); | |
| } | |
| static void test_format_rect(void) | |
| { | |
| HWND edit; | |
| RECT rect, old_rect; | |
| static const struct | |
| { | |
| int style_ex; | |
| RECT input; | |
| int expected_equal; | |
| } | |
| tests[] = | |
| { | |
| {0, {0, 0, 0, 0}, 1}, | |
| {0, {0, 0, 10, 10}, 1}, | |
| {0, {1, 1, 10, 10}, 1}, | |
| {0, {1, 1, 10, 250}, 1}, | |
| {0, {1, 1, 250, 10}, 1}, | |
| {0, {1, 1, 10, 1000}, 1}, | |
| {0, {1, 1, 1000, 10}, 1}, | |
| {0, {1, 1, 1000, 1000}, 0}, | |
| {WS_EX_CLIENTEDGE, {0, 0, 0, 0}, 1}, | |
| {WS_EX_CLIENTEDGE, {0, 0, 10, 10}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 10, 10}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 10, 250}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 250, 10}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 10, 1000}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 1000, 10}, 1}, | |
| {WS_EX_CLIENTEDGE, {1, 1, 1000, 1000}, 0} | |
| }; | |
| for (int i = 0; i < ARRAY_SIZE(tests); i++) | |
| { | |
| edit = create_editcontrol(ES_MULTILINE | WS_VISIBLE, tests[i].style_ex); | |
| SendMessageA(edit, EM_GETRECT, 0, (LPARAM)&old_rect); | |
| SetWindowTextA(edit, "Test Test Test\r\n\r\nTest Test Test Test Test Test Test Test Test Test Test Test\r\n\r\nTest Test Test"); | |
| SendMessageA(edit, EM_SETRECT, 0, (LPARAM)&tests[i].input); | |
| SendMessageA(edit, EM_GETRECT, 0, (LPARAM)&rect); | |
| if (tests[i].expected_equal) | |
| ok(EqualRect(&old_rect, &rect), "Expected format rectangle to be equal to client rectangle.\n"); | |
| else | |
| ok((rect.right - rect.left) > (old_rect.right - old_rect.left), "Expected format rect to be larger than client rectangle.\n"); | |
| DestroyWindow(edit); | |
| } | |
| } | |
| static void test_PASSWORDCHAR(void) | |
| { | |
| HWND hwEdit; | |
| LONG r; | |
| CHAR passwdChar = '#'; | |
| hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); | |
| r = SendMessageA(hwEdit, EM_SETPASSWORDCHAR, passwdChar, 0); | |
| ok(r == 1, "Expected: 1, got: %ld\n", r); | |
| r = get_edit_style(hwEdit); | |
| ok(r & ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%lx\n", r); | |
| r = SendMessageA(hwEdit, EM_GETPASSWORDCHAR, 0, 0); | |
| ok(r == passwdChar, "Expected: 0, got: %ld\n", r); | |
| DestroyWindow (hwEdit); | |
| hwEdit = create_editcontrol(ES_MULTILINE, 0); | |
| r = get_edit_style(hwEdit); | |
| ok(r == ES_MULTILINE, "Wrong style expected ES_PASSWORD got: 0x%lx\n", r); | |
| r = SendMessageA(hwEdit, EM_SETPASSWORDCHAR, passwdChar, 0); | |
| ok(r == 1, "Expected: 1, got: %ld\n", r); | |
| r = get_edit_style(hwEdit); | |
| ok(r == (ES_MULTILINE | ES_PASSWORD), "Wrong style expected ES_MULTILINE|ES_PASSWORD got: 0x%lx\n", r); | |
| r = SendMessageA(hwEdit, EM_GETPASSWORDCHAR, 0, 0); | |
| ok(r == passwdChar, "Expected: 0, got: %ld\n", r); | |
| r = SendMessageA(hwEdit, EM_SETPASSWORDCHAR, 0, 0); | |
| ok(r == 1, "Expected: 1, got: %ld\n", r); | |
| r = get_edit_style(hwEdit); | |
| ok(r == ES_MULTILINE, "Wrong style expected ES_PASSWORD got: 0x%lx\n", r); | |
| r = SendMessageA(hwEdit, EM_GETPASSWORDCHAR, 0, 0); | |
| ok(r == 0, "Expected: 0, got: %ld\n", r); | |
| DestroyWindow (hwEdit); | |
| } | |
| START_TEST(edit) | |
| { | |
| ULONG_PTR ctx_cookie; | |
| HANDLE hCtx; | |
| BOOL b; | |
| if (!load_v6_module(&ctx_cookie, &hCtx)) | |
| return; | |
| init_msg_sequences(sequences, NUM_MSG_SEQUENCES); | |
| init_winevent_hook(); | |
| 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_initialization(); | |
| 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(); | |
| test_wordbreak_proc(); | |
| test_change_focus(); | |
| test_cue_banner(); | |
| test_ime(); | |
| test_format_rect(); | |
| test_PASSWORDCHAR(); | |
| UnregisterWindowClasses(); | |
| uninit_winevent_hook(); | |
| unload_v6_module(ctx_cookie, hCtx); | |
| } |