comctl32/tests: Flush events before testing edit control SetFocus() messages.
[wine.git] / dlls / comctl32 / tests / edit.c
blobccdeed95d92f77d467dca22c7a5e3f3f2f634aa5
1 /* Unit test suite for edit control.
3 * Copyright 2004 Vitaliy Margolen
4 * Copyright 2005 C. Scott Ananian
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <windows.h>
22 #include <commctrl.h>
23 #include <imm.h>
25 #include "wine/test.h"
26 #include "v6util.h"
27 #include "msg.h"
29 #ifndef ES_COMBO
30 #define ES_COMBO 0x200
31 #endif
33 #define ID_EDITTESTDBUTTON 0x123
34 #define ID_EDITTEST2 99
35 #define MAXLEN 200
37 enum seq_index
39 COMBINED_SEQ_INDEX = 0,
40 NUM_MSG_SEQUENCES,
43 enum msg_id
45 PARENT_ID,
46 EDIT_ID,
49 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
51 struct edit_notify {
52 int en_change, en_maxtext, en_update;
55 static struct edit_notify notifications;
57 /* try to make sure pending X events have been processed before continuing */
58 static void flush_events(void)
60 MSG msg;
61 int diff = 200;
62 int min_timeout = 100;
63 DWORD time = GetTickCount() + diff;
65 while (diff > 0)
67 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT)
68 break;
69 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
70 DispatchMessageA(&msg);
71 diff = time - GetTickCount();
75 static INT_PTR CALLBACK multi_edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
77 static int num_ok_commands = 0;
78 switch (msg)
80 case WM_INITDIALOG:
82 HWND hedit = GetDlgItem(hdlg, 1000);
83 SetFocus(hedit);
84 switch (lparam)
86 /* test cases related to bug 12319 */
87 case 0:
88 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
89 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
90 break;
91 case 1:
92 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
93 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
94 break;
95 case 2:
96 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
97 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
98 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
99 break;
101 /* test cases for pressing enter */
102 case 3:
103 num_ok_commands = 0;
104 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
105 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
106 break;
108 default:
109 break;
111 break;
114 case WM_COMMAND:
115 if (HIWORD(wparam) != BN_CLICKED)
116 break;
118 switch (LOWORD(wparam))
120 case IDOK:
121 num_ok_commands++;
122 break;
124 default:
125 break;
127 break;
129 case WM_USER:
131 HWND hfocus = GetFocus();
132 HWND hedit = GetDlgItem(hdlg, 1000);
133 HWND hedit2 = GetDlgItem(hdlg, 1001);
134 HWND hedit3 = GetDlgItem(hdlg, 1002);
136 if (wparam != 0xdeadbeef)
137 break;
139 switch (lparam)
141 case 0:
142 if (hfocus == hedit)
143 EndDialog(hdlg, 1111);
144 else if (hfocus == hedit2)
145 EndDialog(hdlg, 2222);
146 else if (hfocus == hedit3)
147 EndDialog(hdlg, 3333);
148 else
149 EndDialog(hdlg, 4444);
150 break;
151 case 1:
152 if ((hfocus == hedit) && (num_ok_commands == 0))
153 EndDialog(hdlg, 11);
154 else
155 EndDialog(hdlg, 22);
156 break;
157 default:
158 EndDialog(hdlg, 5555);
160 break;
163 case WM_CLOSE:
164 EndDialog(hdlg, 333);
165 break;
167 default:
168 break;
171 return FALSE;
174 static INT_PTR CALLBACK edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
176 switch (msg)
178 case WM_INITDIALOG:
180 HWND hedit = GetDlgItem(hdlg, 1000);
181 SetFocus(hedit);
182 switch (lparam)
184 /* from bug 11841 */
185 case 0:
186 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
187 break;
188 case 1:
189 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
190 break;
191 case 2:
192 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
193 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
194 break;
196 /* more test cases for WM_CHAR */
197 case 3:
198 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
199 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
200 break;
201 case 4:
202 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
203 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
204 break;
205 case 5:
206 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
207 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
208 break;
210 /* more test cases for WM_KEYDOWN + WM_CHAR */
211 case 6:
212 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
213 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
214 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
215 break;
216 case 7:
217 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
218 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
219 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
220 break;
221 case 8:
222 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
223 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
224 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
225 break;
227 /* multiple tab tests */
228 case 9:
229 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
230 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
231 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
232 break;
233 case 10:
234 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
235 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
236 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
237 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
238 break;
240 default:
241 break;
243 break;
246 case WM_COMMAND:
247 if (HIWORD(wparam) != BN_CLICKED)
248 break;
250 switch (LOWORD(wparam))
252 case IDOK:
253 EndDialog(hdlg, 111);
254 break;
256 case IDCANCEL:
257 EndDialog(hdlg, 222);
258 break;
260 default:
261 break;
263 break;
265 case WM_USER:
267 int len;
268 HWND hok = GetDlgItem(hdlg, IDOK);
269 HWND hcancel = GetDlgItem(hdlg, IDCANCEL);
270 HWND hedit = GetDlgItem(hdlg, 1000);
271 HWND hfocus = GetFocus();
273 if (wparam != 0xdeadbeef)
274 break;
276 switch (lparam)
278 case 0:
279 len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
280 if (len == 0)
281 EndDialog(hdlg, 444);
282 else
283 EndDialog(hdlg, 555);
284 break;
286 case 1:
287 len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
288 if ((hfocus == hok) && len == 0)
289 EndDialog(hdlg, 444);
290 else
291 EndDialog(hdlg, 555);
292 break;
294 case 2:
295 if (hfocus == hok)
296 EndDialog(hdlg, 11);
297 else if (hfocus == hcancel)
298 EndDialog(hdlg, 22);
299 else if (hfocus == hedit)
300 EndDialog(hdlg, 33);
301 else
302 EndDialog(hdlg, 44);
303 break;
305 default:
306 EndDialog(hdlg, 555);
308 break;
311 case WM_CLOSE:
312 EndDialog(hdlg, 333);
313 break;
315 default:
316 break;
319 return FALSE;
322 static INT_PTR CALLBACK edit_singleline_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
324 switch (msg)
326 case WM_INITDIALOG:
328 HWND hedit = GetDlgItem(hdlg, 1000);
329 SetFocus(hedit);
330 switch (lparam)
332 /* test cases for WM_KEYDOWN */
333 case 0:
334 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
335 break;
336 case 1:
337 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
338 break;
339 case 2:
340 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
341 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
342 break;
344 /* test cases for WM_CHAR */
345 case 3:
346 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
347 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
348 break;
349 case 4:
350 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
351 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
352 break;
353 case 5:
354 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
355 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
356 break;
358 /* test cases for WM_KEYDOWN + WM_CHAR */
359 case 6:
360 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
361 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
362 break;
363 case 7:
364 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
365 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
366 break;
367 case 8:
368 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
369 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
370 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
371 break;
373 default:
374 break;
376 break;
379 case WM_COMMAND:
380 if (HIWORD(wparam) != BN_CLICKED)
381 break;
383 switch (LOWORD(wparam))
385 case IDOK:
386 EndDialog(hdlg, 111);
387 break;
389 case IDCANCEL:
390 EndDialog(hdlg, 222);
391 break;
393 default:
394 break;
396 break;
398 case WM_USER:
400 HWND hok = GetDlgItem(hdlg, IDOK);
401 HWND hedit = GetDlgItem(hdlg, 1000);
402 HWND hfocus = GetFocus();
403 int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
405 if (wparam != 0xdeadbeef)
406 break;
408 switch (lparam)
410 case 0:
411 if ((hfocus == hedit) && len == 0)
412 EndDialog(hdlg, 444);
413 else
414 EndDialog(hdlg, 555);
415 break;
417 case 1:
418 if ((hfocus == hok) && len == 0)
419 EndDialog(hdlg, 444);
420 else
421 EndDialog(hdlg, 555);
422 break;
424 default:
425 EndDialog(hdlg, 55);
427 break;
430 case WM_CLOSE:
431 EndDialog(hdlg, 333);
432 break;
434 default:
435 break;
438 return FALSE;
441 static INT_PTR CALLBACK edit_wantreturn_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
443 switch (msg)
445 case WM_INITDIALOG:
447 HWND hedit = GetDlgItem(hdlg, 1000);
448 SetFocus(hedit);
449 switch (lparam)
451 /* test cases for WM_KEYDOWN */
452 case 0:
453 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
454 break;
455 case 1:
456 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
457 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
458 break;
459 case 2:
460 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
461 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
462 break;
464 /* test cases for WM_CHAR */
465 case 3:
466 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
467 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
468 break;
469 case 4:
470 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
471 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
472 break;
473 case 5:
474 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
475 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
476 break;
478 /* test cases for WM_KEYDOWN + WM_CHAR */
479 case 6:
480 PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
481 PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
482 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
483 break;
484 case 7:
485 PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
486 PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
487 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
488 break;
489 case 8:
490 PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
491 PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
492 PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
493 break;
495 default:
496 break;
498 break;
501 case WM_COMMAND:
502 if (HIWORD(wparam) != BN_CLICKED)
503 break;
505 switch (LOWORD(wparam))
507 case IDOK:
508 EndDialog(hdlg, 111);
509 break;
511 case IDCANCEL:
512 EndDialog(hdlg, 222);
513 break;
515 default:
516 break;
518 break;
520 case WM_USER:
522 HWND hok = GetDlgItem(hdlg, IDOK);
523 HWND hedit = GetDlgItem(hdlg, 1000);
524 HWND hfocus = GetFocus();
525 int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
527 if (wparam != 0xdeadbeef)
528 break;
530 switch (lparam)
532 case 0:
533 if ((hfocus == hedit) && len == 0)
534 EndDialog(hdlg, 444);
535 else
536 EndDialog(hdlg, 555);
537 break;
539 case 1:
540 if ((hfocus == hok) && len == 0)
541 EndDialog(hdlg, 444);
542 else
543 EndDialog(hdlg, 555);
544 break;
546 case 2:
547 if ((hfocus == hedit) && len == 2)
548 EndDialog(hdlg, 444);
549 else
550 EndDialog(hdlg, 555);
551 break;
553 default:
554 EndDialog(hdlg, 55);
556 break;
559 case WM_CLOSE:
560 EndDialog(hdlg, 333);
561 break;
563 default:
564 break;
567 return FALSE;
570 static HINSTANCE hinst;
571 static HWND hwndET2;
572 static const char szEditTest2Class[] = "EditTest2Class";
573 static const char szEditTest3Class[] = "EditTest3Class";
574 static const char szEditTest4Class[] = "EditTest4Class";
575 static const char szEditTextPositionClass[] = "EditTextPositionWindowClass";
577 static HWND create_editcontrol (DWORD style, DWORD exstyle)
579 HWND handle;
581 handle = CreateWindowExA(exstyle, WC_EDITA, "Text Text", style, 10, 10, 300, 300,
582 NULL, NULL, hinst, NULL);
583 ok (handle != NULL, "CreateWindow EDIT Control failed\n");
585 if (winetest_interactive)
586 ShowWindow (handle, SW_SHOW);
587 return handle;
590 static HWND create_editcontrolW(DWORD style, DWORD exstyle)
592 static const WCHAR testtextW[] = {'T','e','s','t',' ','t','e','x','t',0};
593 HWND handle;
595 handle = CreateWindowExW(exstyle, WC_EDITW, testtextW, style, 10, 10, 300, 300,
596 NULL, NULL, hinst, NULL);
597 ok(handle != NULL, "Failed to create Edit control.\n");
598 return handle;
601 static HWND create_child_editcontrol (DWORD style, DWORD exstyle)
603 HWND parentWnd;
604 HWND editWnd;
605 RECT rect;
606 BOOL b;
607 SetRect(&rect, 0, 0, 300, 300);
608 b = AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
609 ok(b, "AdjustWindowRect failed\n");
611 parentWnd = CreateWindowExA(0,
612 szEditTextPositionClass,
613 "Edit Test",
614 WS_OVERLAPPEDWINDOW,
615 CW_USEDEFAULT, CW_USEDEFAULT,
616 rect.right - rect.left, rect.bottom - rect.top,
617 NULL, NULL, hinst, NULL);
618 ok (parentWnd != NULL, "CreateWindow EDIT Test failed\n");
620 editWnd = CreateWindowExA(exstyle,
621 "EDIT",
622 "Test Text",
623 WS_CHILD | style,
624 0, 0, 300, 300,
625 parentWnd, NULL, hinst, NULL);
626 ok (editWnd != NULL, "CreateWindow EDIT Test Text failed\n");
627 if (winetest_interactive)
628 ShowWindow (parentWnd, SW_SHOW);
629 return editWnd;
632 static void destroy_child_editcontrol (HWND hwndEdit)
634 if (GetParent(hwndEdit))
635 DestroyWindow(GetParent(hwndEdit));
636 else {
637 trace("Edit control has no parent!\n");
638 DestroyWindow(hwndEdit);
642 static LONG get_edit_style (HWND hwnd)
644 return GetWindowLongA( hwnd, GWL_STYLE ) & (
645 ES_LEFT |
646 /* FIXME: not implemented
647 ES_CENTER |
648 ES_RIGHT |
649 ES_OEMCONVERT |
651 ES_MULTILINE |
652 ES_UPPERCASE |
653 ES_LOWERCASE |
654 ES_PASSWORD |
655 ES_AUTOVSCROLL |
656 ES_AUTOHSCROLL |
657 ES_NOHIDESEL |
658 ES_COMBO |
659 ES_READONLY |
660 ES_WANTRETURN |
661 ES_NUMBER
665 static void set_client_height(HWND Wnd, unsigned Height)
667 RECT ClientRect, WindowRect;
669 GetWindowRect(Wnd, &WindowRect);
670 GetClientRect(Wnd, &ClientRect);
671 SetWindowPos(Wnd, NULL, 0, 0,
672 WindowRect.right - WindowRect.left,
673 Height + (WindowRect.bottom - WindowRect.top) -
674 (ClientRect.bottom - ClientRect.top),
675 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
677 /* Workaround for a bug in Windows' edit control
678 (multi-line mode) */
679 GetWindowRect(Wnd, &WindowRect);
680 SetWindowPos(Wnd, NULL, 0, 0,
681 WindowRect.right - WindowRect.left + 1,
682 WindowRect.bottom - WindowRect.top + 1,
683 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
684 SetWindowPos(Wnd, NULL, 0, 0,
685 WindowRect.right - WindowRect.left,
686 WindowRect.bottom - WindowRect.top,
687 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
689 GetClientRect(Wnd, &ClientRect);
690 ok(ClientRect.bottom - ClientRect.top == Height,
691 "The client height should be %d, but is %ld\n",
692 Height, ClientRect.bottom - ClientRect.top);
695 static void test_edit_control_1(void)
697 HWND hwEdit;
698 MSG msMessage;
699 int i;
700 LONG r;
702 msMessage.message = WM_KEYDOWN;
704 trace("EDIT: Single line\n");
705 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
706 r = get_edit_style(hwEdit);
707 ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r);
708 for (i = 0; i < 65535; i++)
710 msMessage.wParam = i;
711 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
712 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
713 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
715 DestroyWindow(hwEdit);
717 trace("EDIT: Single line want returns\n");
718 hwEdit = create_editcontrol(ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
719 r = get_edit_style(hwEdit);
720 ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r);
721 for (i = 0; i < 65535; i++)
723 msMessage.wParam = i;
724 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
725 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
726 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
728 DestroyWindow(hwEdit);
730 trace("EDIT: Multiline line\n");
731 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
732 r = get_edit_style(hwEdit);
733 ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r);
734 for (i = 0; i < 65535; i++)
736 msMessage.wParam = i;
737 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
738 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
739 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
741 DestroyWindow(hwEdit);
743 trace("EDIT: Multi line want returns\n");
744 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
745 r = get_edit_style(hwEdit);
746 ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r);
747 for (i = 0; i < 65535; i++)
749 msMessage.wParam = i;
750 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
751 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
752 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
754 DestroyWindow(hwEdit);
757 /* WM_SETTEXT is implemented by selecting all text, and then replacing the
758 * selection. This test checks that the first 'select all' doesn't generate
759 * an UPDATE message which can escape and (via a handler) change the
760 * selection, which would cause WM_SETTEXT to break. This old bug
761 * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
763 static void test_edit_control_2(void)
765 HWND hwndMain, phwnd;
766 char szLocalString[MAXLEN];
767 LONG r, w = 150, h = 50;
768 POINT cpos;
770 /* Create main and edit windows. */
771 hwndMain = CreateWindowA(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW,
772 0, 0, 200, 200, NULL, NULL, hinst, NULL);
773 ok(hwndMain != NULL, "Failed to create control parent.\n");
774 if (winetest_interactive)
775 ShowWindow (hwndMain, SW_SHOW);
777 hwndET2 = CreateWindowA(WC_EDITA, NULL, WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
778 0, 0, w, h, /* important this not be 0 size. */
779 hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
780 ok(hwndET2 != NULL, "Failed to create Edit control.\n");
781 if (winetest_interactive)
782 ShowWindow (hwndET2, SW_SHOW);
784 trace("EDIT: SETTEXT atomicity\n");
785 /* Send messages to "type" in the word 'foo'. */
786 r = SendMessageA(hwndET2, WM_CHAR, 'f', 1);
787 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
788 r = SendMessageA(hwndET2, WM_CHAR, 'o', 1);
789 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
790 r = SendMessageA(hwndET2, WM_CHAR, 'o', 1);
791 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
792 /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
793 GetWindowTextA(hwndET2, szLocalString, MAXLEN);
794 ok(strcmp(szLocalString, "bar")==0,
795 "Wrong contents of edit: %s\n", szLocalString);
797 /* try setting the caret before it's visible */
798 r = SetCaretPos(0, 0);
799 todo_wine ok(0 == r, "SetCaretPos succeeded unexpectedly, expected: 0, got: %ld\n", r);
800 phwnd = SetFocus(hwndET2);
801 ok(phwnd != NULL, "SetFocus failed unexpectedly, expected non-zero, got NULL\n");
802 r = SetCaretPos(0, 0);
803 ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
804 r = GetCaretPos(&cpos);
805 ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
806 ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%ld,%ld)\n", cpos.x, cpos.y);
807 r = SetCaretPos(-1, -1);
808 ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
809 r = GetCaretPos(&cpos);
810 ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
811 ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%ld,%ld)\n", cpos.x, cpos.y);
812 r = SetCaretPos(w << 1, h << 1);
813 ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
814 r = GetCaretPos(&cpos);
815 ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
816 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);
817 r = SetCaretPos(w, h);
818 ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
819 r = GetCaretPos(&cpos);
820 ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
821 ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w, h, cpos.x, cpos.y);
822 r = SetCaretPos(w - 1, h - 1);
823 ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
824 r = GetCaretPos(&cpos);
825 ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r);
826 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);
828 DestroyWindow(hwndET2);
829 DestroyWindow(hwndMain);
832 static void ET2_check_change(void)
834 char szLocalString[MAXLEN];
835 /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
836 GetWindowTextA(hwndET2, szLocalString, MAXLEN);
837 if (!strcmp(szLocalString, "foo"))
839 strcpy(szLocalString, "bar");
840 SendMessageA(hwndET2, WM_SETTEXT, 0, (LPARAM)szLocalString);
842 /* always leave the cursor at the end. */
843 SendMessageA(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
846 static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
848 if (id == ID_EDITTEST2 && codeNotify == EN_UPDATE)
849 ET2_check_change();
852 static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
854 switch (iMsg)
856 case WM_COMMAND:
857 ET2_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
858 break;
860 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
863 static void zero_notify(void)
865 notifications.en_change = 0;
866 notifications.en_maxtext = 0;
867 notifications.en_update = 0;
870 #define test_notify(enchange, enmaxtext, enupdate) \
871 do { \
872 ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
873 "got %d\n", enchange, notifications.en_change); \
874 ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
875 "got %d\n", enmaxtext, notifications.en_maxtext); \
876 ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
877 "got %d\n", enupdate, notifications.en_update); \
878 } while(0)
880 static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
882 switch (msg)
884 case WM_COMMAND:
885 switch (HIWORD(wParam))
887 case EN_MAXTEXT:
888 notifications.en_maxtext++;
889 break;
890 case EN_UPDATE:
891 notifications.en_update++;
892 break;
893 case EN_CHANGE:
894 notifications.en_change++;
895 break;
897 break;
899 return DefWindowProcA(hWnd, msg, wParam, lParam);
902 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
904 static LONG defwndproc_counter = 0;
905 struct message msg = { 0 };
906 LRESULT ret;
908 msg.message = message;
909 msg.flags = sent|wparam|id;
910 if (defwndproc_counter) msg.flags |= defwinproc;
911 msg.wParam = wParam;
912 msg.id = PARENT_ID;
914 if (message != WM_IME_SETCONTEXT &&
915 message != WM_IME_NOTIFY &&
916 message != WM_GETICON &&
917 message != WM_DWMNCRENDERINGCHANGED &&
918 message != WM_GETMINMAXINFO &&
919 message != WM_PAINT &&
920 message != WM_CTLCOLOREDIT &&
921 message != WM_WINDOWPOSCHANGING &&
922 message != WM_WINDOWPOSCHANGED &&
923 message != WM_MOVE &&
924 message != WM_MOUSEACTIVATE &&
925 message < 0xc000)
927 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
930 defwndproc_counter++;
931 ret = DefWindowProcA(hwnd, message, wParam, lParam);
932 defwndproc_counter--;
934 return ret;
937 static LRESULT CALLBACK edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
939 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
940 static LONG defwndproc_counter = 0;
941 struct message msg = { 0 };
942 LRESULT ret;
944 msg.message = message;
945 msg.flags = sent|wparam|id;
946 if (defwndproc_counter) msg.flags |= defwinproc;
947 msg.wParam = wParam;
948 msg.id = EDIT_ID;
950 if (message != WM_IME_SETCONTEXT &&
951 message != WM_IME_NOTIFY)
953 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
956 defwndproc_counter++;
957 if (IsWindowUnicode(hwnd))
958 ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam);
959 else
960 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
961 defwndproc_counter--;
963 return ret;
966 /* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notifications sent in response
967 * to these messages.
969 static void test_edit_control_3(void)
971 static const char *str = "this is a long string.";
972 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.";
973 HWND hWnd, hParent;
974 int len, dpi;
975 HDC hDC;
977 hDC = GetDC(NULL);
978 dpi = GetDeviceCaps(hDC, LOGPIXELSY);
979 ReleaseDC(NULL, hDC);
981 trace("EDIT: Test notifications\n");
983 hParent = CreateWindowExA(0,
984 szEditTest3Class,
985 NULL,
987 CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
988 NULL, NULL, NULL, NULL);
989 ok(hParent != NULL, "Failed to create control parent.\n");
991 trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
992 hWnd = CreateWindowExA(0, WC_EDITA, NULL, 0, 10, 10, 50, 50, hParent, NULL, NULL, NULL);
993 ok(hWnd != NULL, "Failed to create Edit control.\n");
995 zero_notify();
996 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
997 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
998 if (len == lstrlenA(str)) /* Win 8 */
999 test_notify(1, 0, 1);
1000 else
1001 test_notify(1, 1, 1);
1003 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1004 zero_notify();
1005 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
1006 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1007 ok(1 == len, "wrong text length, expected 1, got %d\n", len);
1008 test_notify(1, 0, 1);
1010 zero_notify();
1011 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1012 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1013 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1014 test_notify(1, 0, 1);
1016 len = SendMessageA(hWnd, EM_GETSEL, 0, 0);
1017 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
1018 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
1019 SendMessageA(hParent, WM_SETFOCUS, 0, (LPARAM)hWnd);
1020 len = SendMessageA(hWnd, EM_GETSEL, 0, 0);
1021 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
1022 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
1024 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
1026 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1027 zero_notify();
1028 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
1029 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1030 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
1031 test_notify(1, 1, 1);
1033 zero_notify();
1034 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1035 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1036 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1037 test_notify(1, 0, 1);
1039 DestroyWindow(hWnd);
1041 trace("EDIT: Single line, ES_AUTOHSCROLL\n");
1042 hWnd = CreateWindowExA(0, WC_EDITA, NULL, ES_AUTOHSCROLL, 10, 10, 50, 50, hParent, NULL, NULL, NULL);
1043 ok(hWnd != NULL, "Failed to create Edit control.\n");
1045 zero_notify();
1046 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
1047 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1048 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1049 test_notify(1, 0, 1);
1051 zero_notify();
1052 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1053 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1054 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1055 test_notify(1, 0, 1);
1057 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1058 zero_notify();
1059 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
1060 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1061 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1062 test_notify(1, 0, 1);
1064 zero_notify();
1065 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
1066 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1067 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1068 test_notify(1, 0, 1);
1070 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
1072 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1073 zero_notify();
1074 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
1075 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1076 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
1077 test_notify(1, 1, 1);
1079 zero_notify();
1080 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1081 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1082 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1083 test_notify(1, 0, 1);
1085 DestroyWindow(hWnd);
1087 trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
1088 hWnd = CreateWindowExA(0, WC_EDITA, NULL, ES_MULTILINE,
1089 10, 10, (50 * dpi) / 96, (50 * dpi) / 96,
1090 hParent, NULL, NULL, NULL);
1091 ok(hWnd != NULL, "Failed to create Edit control.\n");
1093 zero_notify();
1094 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
1095 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1096 if (len == lstrlenA(str)) /* Win 8 */
1097 test_notify(1, 0, 1);
1098 else
1100 ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
1101 test_notify(1, 1, 1);
1104 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1105 zero_notify();
1106 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
1107 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1108 ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
1109 test_notify(1, 0, 1);
1111 zero_notify();
1112 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1113 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1114 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1115 test_notify(0, 0, 0);
1117 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
1119 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1120 zero_notify();
1121 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
1122 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1123 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
1124 test_notify(1, 1, 1);
1126 zero_notify();
1127 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1128 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1129 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1130 test_notify(0, 0, 0);
1132 DestroyWindow(hWnd);
1134 trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
1135 hWnd = CreateWindowExA(0, WC_EDITA, NULL, ES_MULTILINE | ES_AUTOHSCROLL,
1136 10, 10, (50 * dpi) / 96, (50 * dpi) / 96,
1137 hParent, NULL, NULL, NULL);
1138 ok(hWnd != NULL, "Failed to create Edit control.\n");
1140 zero_notify();
1141 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
1142 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1143 ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
1144 test_notify(1, 1, 1);
1146 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1147 zero_notify();
1148 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
1149 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1150 ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
1151 test_notify(1, 0, 1);
1153 zero_notify();
1154 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
1155 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1156 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1157 test_notify(0, 0, 0);
1159 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
1161 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1162 zero_notify();
1163 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
1164 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1165 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
1166 test_notify(1, 1, 1);
1168 zero_notify();
1169 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
1170 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1171 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1172 test_notify(0, 0, 0);
1174 DestroyWindow(hWnd);
1176 trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
1177 hWnd = CreateWindowExA(0, WC_EDITA, NULL, ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
1178 10, 10, 50, 50, hParent, NULL, NULL, NULL);
1179 ok(hWnd != NULL, "Failed to create Edit control.\n");
1181 zero_notify();
1182 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
1183 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1184 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1185 test_notify(1, 0, 1);
1187 zero_notify();
1188 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
1189 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1190 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1191 test_notify(0, 0, 0);
1193 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
1195 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
1196 zero_notify();
1197 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
1198 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1199 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
1200 test_notify(1, 1, 1);
1202 zero_notify();
1203 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
1204 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1205 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
1206 test_notify(0, 0, 0);
1208 DestroyWindow(hWnd);
1211 static void test_char_from_pos(void)
1213 int lo, hi, mid, ret, i;
1214 HWND hwEdit;
1215 HDC dc;
1216 SIZE size;
1218 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1219 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1220 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1221 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1222 mid = lo + (hi - lo) / 2;
1224 for (i = lo; i < mid; i++)
1226 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1227 ok(0 == ret, "expected 0 got %d\n", ret);
1230 for (i = mid; i <= hi; i++)
1232 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1233 ok(1 == ret, "expected 1 got %d\n", ret);
1236 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1237 ok(-1 == ret, "expected -1 got %d\n", ret);
1238 DestroyWindow(hwEdit);
1240 hwEdit = create_editcontrol(ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1241 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1242 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1243 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1244 mid = lo + (hi - lo) / 2;
1246 for (i = lo; i < mid; i++)
1248 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1249 ok(0 == ret, "expected 0 got %d\n", ret);
1252 for (i = mid; i <= hi; i++)
1254 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1255 ok(1 == ret, "expected 1 got %d\n", ret);
1258 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1259 ok(-1 == ret, "expected -1 got %d\n", ret);
1260 DestroyWindow(hwEdit);
1262 hwEdit = create_editcontrol(ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1263 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1264 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1265 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1266 mid = lo + (hi - lo) / 2;
1268 for (i = lo; i < mid; i++)
1270 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1271 ok(0 == ret, "expected 0 got %d\n", ret);
1274 for (i = mid; i <= hi; i++)
1276 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1277 ok(1 == ret, "expected 1 got %d\n", ret);
1280 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1281 ok(-1 == ret, "expected -1 got %d\n", ret);
1282 DestroyWindow(hwEdit);
1284 hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1285 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1286 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1287 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1288 mid = lo + (hi - lo) / 2 + 1;
1290 for (i = lo; i < mid; i++)
1292 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1293 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
1296 for (i = mid; i <= hi; i++)
1298 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1299 ok(1 == ret, "expected 1 got %d\n", ret);
1302 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1303 ok(-1 == ret, "expected -1 got %d\n", ret);
1304 DestroyWindow(hwEdit);
1306 hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1307 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1308 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1309 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1310 mid = lo + (hi - lo) / 2 + 1;
1312 for (i = lo; i < mid; i++)
1314 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1315 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
1318 for (i = mid; i <= hi; i++)
1320 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1321 ok(1 == ret, "expected 1 got %d\n", ret);
1324 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1325 ok(-1 == ret, "expected -1 got %d\n", ret);
1326 DestroyWindow(hwEdit);
1328 hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1329 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
1330 lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
1331 hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
1332 mid = lo + (hi - lo) / 2 + 1;
1334 for (i = lo; i < mid; i++)
1336 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1337 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
1340 for (i = mid; i <= hi; i++)
1342 ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
1343 ok(1 == ret, "expected 1 got %d\n", ret);
1346 ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
1347 ok(-1 == ret, "expected -1 got %d\n", ret);
1348 DestroyWindow(hwEdit);
1350 /* Scrolled to the right with partially visible line, position on next line. */
1351 hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1353 dc = GetDC(hwEdit);
1354 GetTextExtentPoint32A(dc, "w", 1, &size);
1355 ReleaseDC(hwEdit, dc);
1357 SetWindowPos(hwEdit, NULL, 0, 0, size.cx * 15, size.cy * 5, SWP_NOMOVE | SWP_NOZORDER);
1358 SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"wwwwwwwwwwwwwwwwwwww\r\n\r\n");
1359 SendMessageA(hwEdit, EM_SETSEL, 40, 40);
1361 lo = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 22, 0);
1362 ret = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 20, 0);
1363 ret -= 20 * size.cx; /* Calculate expected position, 20 characters back. */
1364 ok(ret == lo, "Unexpected position %d vs %d.\n", lo, ret);
1366 DestroyWindow(hwEdit);
1369 /* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL
1370 * truncates text that doesn't fit.
1372 static void test_edit_control_5(void)
1374 static const char *str = "test\r\ntest";
1375 HWND parentWnd;
1376 HWND hWnd;
1377 int len;
1378 RECT rc1 = { 10, 10, 11, 11};
1379 RECT rc;
1381 /* first show that a non-child won't do for this test */
1382 hWnd = CreateWindowExA(0, WC_EDITA, str, 0, 10, 10, 1, 1, NULL, NULL, NULL, NULL);
1383 ok(hWnd != NULL, "Failed to create Edit control.\n");
1385 /* size of non-child edit control is (much) bigger than requested */
1386 GetWindowRect( hWnd, &rc);
1387 ok( rc.right - rc.left > 20, "size of the window (%ld) is smaller than expected\n",
1388 rc.right - rc.left);
1389 DestroyWindow(hWnd);
1390 /* so create a parent, and give it edit controls children to test with */
1391 parentWnd = CreateWindowExA(0,
1392 szEditTextPositionClass,
1393 "Edit Test", WS_VISIBLE |
1394 WS_OVERLAPPEDWINDOW,
1395 CW_USEDEFAULT, CW_USEDEFAULT,
1396 250, 250,
1397 NULL, NULL, hinst, NULL);
1398 ok(parentWnd != NULL, "Failed to create control parent.\n");
1399 ShowWindow( parentWnd, SW_SHOW);
1400 /* single line */
1401 hWnd = CreateWindowExA(0, WC_EDITA, str, WS_VISIBLE | WS_BORDER | WS_CHILD,
1402 rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
1403 parentWnd, NULL, NULL, NULL);
1404 ok(hWnd != NULL, "Failed to create Edit control.\n");
1405 GetClientRect( hWnd, &rc);
1406 ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top,
1407 "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc ));
1408 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1409 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1410 DestroyWindow(hWnd);
1411 /* multi line */
1412 hWnd = CreateWindowExA(0, WC_EDITA, str, WS_CHILD | ES_MULTILINE,
1413 rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
1414 parentWnd, NULL, NULL, NULL);
1415 ok(hWnd != NULL, "Failed to create Edit control.\n");
1416 GetClientRect( hWnd, &rc);
1417 ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top,
1418 "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc ));
1419 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
1420 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
1421 DestroyWindow(hWnd);
1422 DestroyWindow(parentWnd);
1425 /* Test WM_GETTEXT processing
1426 * after destroy messages
1428 static void test_edit_control_6(void)
1430 static const char *str = "test\r\ntest";
1431 char buf[MAXLEN];
1432 HWND hWnd;
1433 LONG ret;
1435 hWnd = CreateWindowExA(0, "EDIT", "Test", 0, 10, 10, 1, 1, NULL, NULL, hinst, NULL);
1436 ok(hWnd != NULL, "Failed to create edit control.\n");
1438 ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
1439 ok(ret == TRUE, "Expected %d, got %ld\n", TRUE, ret);
1440 ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
1441 ok(ret == strlen(str), "Expected %s, got len %ld\n", str, ret);
1442 ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf);
1444 buf[0] = 0;
1445 ret = SendMessageA(hWnd, WM_DESTROY, 0, 0);
1446 todo_wine
1447 ok(ret == 1, "Unexpected return value %ld\n", ret);
1448 ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
1449 ok(ret == strlen(str), "Expected %s, got len %ld\n", str, ret);
1450 ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf);
1452 buf[0] = 0;
1453 ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0);
1454 ok(ret == 0, "Expected 0, got %ld\n", ret);
1455 ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
1456 todo_wine {
1457 ok(ret == strlen("Test"), "Unexpected text length %ld\n", ret);
1458 ok(!strcmp(buf, "Test"), "Unexpected text %s\n", buf);
1460 DestroyWindow(hWnd);
1463 static void test_edit_control_limittext(void)
1465 HWND hwEdit;
1466 DWORD r;
1468 /* Test default limit for single-line control */
1469 trace("EDIT: buffer limit for single-line\n");
1470 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1471 r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
1472 ok(r == 30000, "Incorrect default text limit, expected 30000 got %lu\n", r);
1473 SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0);
1474 r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
1475 ok( r == 2147483646, "got limit %lu (expected 2147483646)\n", r);
1476 DestroyWindow(hwEdit);
1478 /* Test default limit for multi-line control */
1479 trace("EDIT: buffer limit for multi-line\n");
1480 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1481 r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
1482 ok(r == 30000, "Incorrect default text limit, expected 30000 got %lu\n", r);
1483 SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0);
1484 r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
1485 ok( r == 4294967295U, "got limit %lu (expected 4294967295)\n", r);
1486 DestroyWindow(hwEdit);
1489 /* Test EM_SCROLL */
1490 static void test_edit_control_scroll(void)
1492 static const char *single_line_str = "a";
1493 static const char *multiline_str = "Test\r\nText";
1494 HWND hwEdit;
1495 LONG ret;
1497 /* Check the return value when EM_SCROLL doesn't scroll
1498 * anything. Should not return true unless any lines were actually
1499 * scrolled. */
1500 hwEdit = CreateWindowA(WC_EDITA, single_line_str, WS_VSCROLL | ES_MULTILINE,
1501 1, 1, 100, 100, NULL, NULL, hinst, NULL);
1502 ok(hwEdit != NULL, "Failed to create Edit control.\n");
1504 ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0);
1505 ok(!ret, "Returned %lx, expected 0.\n", ret);
1507 ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEUP, 0);
1508 ok(!ret, "Returned %lx, expected 0.\n", ret);
1510 ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEUP, 0);
1511 ok(!ret, "Returned %lx, expected 0.\n", ret);
1513 ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEDOWN, 0);
1514 ok(!ret, "Returned %lx, expected 0.\n", ret);
1516 DestroyWindow (hwEdit);
1518 /* SB_PAGEDOWN while at the beginning of a buffer with few lines
1519 should not cause EM_SCROLL to return a negative value of
1520 scrolled lines that would put us "before" the beginning. */
1521 hwEdit = CreateWindowA(WC_EDITA, multiline_str, WS_VSCROLL | ES_MULTILINE,
1522 0, 0, 100, 100, NULL, NULL, hinst, NULL);
1523 ok(hwEdit != NULL, "Failed to create Edit control.\n");
1525 ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0);
1526 ok(!ret, "Returned %lx, expected 0.\n", ret);
1528 DestroyWindow (hwEdit);
1531 static BOOL is_cjk(HDC dc)
1533 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
1534 FONTSIGNATURE fs;
1536 switch (GdiGetCodePage(dc)) {
1537 case 932: case 936: case 949: case 950: case 1361:
1538 return TRUE;
1539 default:
1540 return (GetTextCharsetInfo(dc, &fs, 0) != DEFAULT_CHARSET &&
1541 (fs.fsCsb[0] & FS_DBCS_MASK));
1545 static void test_margins_usefontinfo(UINT charset)
1547 HWND hwnd;
1548 HDC hdc;
1549 TEXTMETRICW tm;
1550 SIZE size;
1551 LOGFONTA lf;
1552 HFONT hfont;
1553 RECT rect;
1554 INT margins, threshold, expect, empty_expect;
1555 const UINT small_margins = MAKELONG(1, 5);
1557 memset(&lf, 0, sizeof(lf));
1558 lf.lfHeight = -11;
1559 lf.lfWeight = FW_NORMAL;
1560 lf.lfCharSet = charset;
1561 strcpy(lf.lfFaceName, "Tahoma");
1563 hfont = CreateFontIndirectA(&lf);
1564 ok(hfont != NULL, "got %p\n", hfont);
1566 /* Big window rectangle */
1567 hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
1568 ok(hwnd != NULL, "got %p\n", hwnd);
1569 GetClientRect(hwnd, &rect);
1570 ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1572 hdc = GetDC(hwnd);
1573 hfont = SelectObject(hdc, hfont);
1574 size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy );
1575 if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) ||
1576 !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) {
1577 skip("%s for charset %d isn't available\n", lf.lfFaceName, charset);
1578 hfont = SelectObject(hdc, hfont);
1579 ReleaseDC(hwnd, hdc);
1580 DestroyWindow(hwnd);
1581 DeleteObject(hfont);
1582 return;
1584 expect = MAKELONG(size.cx / 2, size.cx / 2);
1585 hfont = SelectObject(hdc, hfont);
1586 ReleaseDC(hwnd, hdc);
1588 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1589 ok(margins == 0, "got %x\n", margins);
1590 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1591 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1592 expect = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1593 DestroyWindow(hwnd);
1595 threshold = HIWORD(expect) + LOWORD(expect) + size.cx * 2;
1596 empty_expect = threshold > 80 ? small_margins : expect;
1598 /* Size below the threshold, margins remain unchanged */
1599 hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL);
1600 ok(hwnd != NULL, "got %p\n", hwnd);
1601 GetClientRect(hwnd, &rect);
1602 ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1604 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1605 ok(margins == 0, "got %x\n", margins);
1607 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1608 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1609 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1610 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1611 ok(margins == small_margins, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
1612 DestroyWindow(hwnd);
1614 /* Size at the threshold, margins become non-zero */
1615 hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL);
1616 ok(hwnd != NULL, "got %p\n", hwnd);
1617 GetClientRect(hwnd, &rect);
1618 ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1620 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1621 ok(margins == 0, "got %x\n", margins);
1623 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1624 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1625 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1626 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1627 ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
1628 DestroyWindow(hwnd);
1630 /* Empty rect */
1631 hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1632 ok(hwnd != NULL, "got %p\n", hwnd);
1633 GetClientRect(hwnd, &rect);
1634 ok(IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1636 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1637 ok(margins == 0, "got %x\n", margins);
1639 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1640 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1641 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1642 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1643 ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
1644 DestroyWindow(hwnd);
1646 DeleteObject(hfont);
1649 static INT get_cjk_fontinfo_margin(INT width, INT side_bearing)
1651 INT margin;
1652 if (side_bearing < 0)
1653 margin = min(-side_bearing, width/2);
1654 else
1655 margin = 0;
1656 return margin;
1659 static DWORD get_cjk_font_margins(HDC hdc)
1661 ABC abc[256];
1662 SHORT left, right;
1663 UINT i;
1665 if (!GetCharABCWidthsW(hdc, 0, 255, abc))
1666 return 0;
1668 left = right = 0;
1669 for (i = 0; i < ARRAY_SIZE(abc); i++) {
1670 if (-abc[i].abcA > right) right = -abc[i].abcA;
1671 if (-abc[i].abcC > left) left = -abc[i].abcC;
1673 return MAKELONG(left, right);
1676 static void test_margins_default(const char* facename, UINT charset)
1678 HWND hwnd;
1679 HDC hdc;
1680 TEXTMETRICW tm;
1681 SIZE size;
1682 BOOL cjk;
1683 LOGFONTA lf;
1684 HFONT hfont;
1685 RECT rect;
1686 INT margins, expect, font_expect;
1687 const UINT small_margins = MAKELONG(1, 5);
1688 const WCHAR EditW[] = {'E','d','i','t',0}, strW[] = {'W',0};
1689 struct char_width_info {
1690 INT lsb, rsb, unknown;
1691 } info;
1692 HMODULE hgdi32;
1693 BOOL (WINAPI *pGetCharWidthInfo)(HDC, struct char_width_info *);
1695 hgdi32 = GetModuleHandleA("gdi32.dll");
1696 pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo");
1698 memset(&lf, 0, sizeof(lf));
1699 lf.lfHeight = -11;
1700 lf.lfWeight = FW_NORMAL;
1701 lf.lfCharSet = charset;
1702 strcpy(lf.lfFaceName, facename);
1704 hfont = CreateFontIndirectA(&lf);
1705 ok(hfont != NULL, "got %p\n", hfont);
1707 /* Unicode version */
1708 hwnd = CreateWindowExW(0, EditW, strW, WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
1709 ok(hwnd != NULL, "got %p\n", hwnd);
1710 GetClientRect(hwnd, &rect);
1711 ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1713 hdc = GetDC(hwnd);
1714 hfont = SelectObject(hdc, hfont);
1715 size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy );
1716 if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) ||
1717 !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) {
1718 skip("%s for charset %d isn't available\n", lf.lfFaceName, charset);
1719 hfont = SelectObject(hdc, hfont);
1720 ReleaseDC(hwnd, hdc);
1721 DestroyWindow(hwnd);
1722 DeleteObject(hfont);
1723 return;
1725 cjk = is_cjk(hdc);
1726 if (cjk && pGetCharWidthInfo && pGetCharWidthInfo(hdc, &info)) {
1727 short left, right;
1729 left = get_cjk_fontinfo_margin(size.cx, info.lsb);
1730 right = get_cjk_fontinfo_margin(size.cx, info.rsb);
1731 expect = MAKELONG(left, right);
1733 font_expect = get_cjk_font_margins(hdc);
1734 if (!font_expect)
1735 /* In this case, margins aren't updated */
1736 font_expect = small_margins;
1738 else
1739 font_expect = expect = MAKELONG(size.cx / 2, size.cx / 2);
1741 hfont = SelectObject(hdc, hfont);
1742 ReleaseDC(hwnd, hdc);
1744 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1745 ok(margins == 0, "got %x\n", margins);
1746 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1747 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1748 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1749 ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins));
1750 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1751 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1752 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1753 ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins));
1754 DestroyWindow(hwnd);
1756 /* ANSI version */
1757 hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
1758 ok(hwnd != NULL, "got %p\n", hwnd);
1759 GetClientRect(hwnd, &rect);
1760 ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
1762 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1763 ok(margins == 0, "got %x\n", margins);
1764 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1765 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
1766 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1767 ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins));
1768 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
1769 SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
1770 margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
1771 ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins));
1772 DestroyWindow(hwnd);
1774 DeleteObject(hfont);
1777 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
1779 return 0;
1782 static BOOL is_font_installed(const char*name)
1784 HDC hdc = GetDC(NULL);
1785 BOOL ret = FALSE;
1787 if (!EnumFontFamiliesA(hdc, name, find_font_proc, 0))
1788 ret = TRUE;
1790 ReleaseDC(NULL, hdc);
1791 return ret;
1794 static WNDPROC orig_class_proc;
1796 static LRESULT CALLBACK test_class_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1798 RECT rect;
1799 LRESULT result, r;
1801 switch (message)
1803 case WM_NCCREATE:
1804 result = CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam);
1806 memset(&rect, 0, sizeof(rect));
1807 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rect);
1808 ok(!rect.right && !rect.bottom, "Invalid size after NCCREATE: %ld x %ld\n", rect.right, rect.bottom);
1810 /* test that messages between WM_NCCREATE and WM_CREATE
1811 don't crash or cause unexpected behavior */
1812 r = SendMessageA(hwnd, EM_SETSEL, 0, 0);
1813 ok(r == 1, "Returned %Id, expected 1.\n", r);
1814 r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010);
1815 todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r);
1816 r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1);
1817 ok(r == 1, "Returned %Id, expected 1.\n", r);
1819 return result;
1821 case WM_CREATE:
1822 /* test that messages between WM_NCCREATE and WM_CREATE
1823 don't crash or cause unexpected behavior */
1824 r = SendMessageA(hwnd, EM_SETSEL, 0, 0);
1825 ok(r == 1, "Returned %Id, expected 1.\n", r);
1826 r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010);
1827 todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r);
1828 r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1);
1829 ok(r == 1, "Returned %Id, expected 1.\n", r);
1831 break;
1834 return CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam);
1837 static void test_initialization(void)
1839 BOOL ret;
1840 ATOM atom;
1841 HWND hwEdit;
1842 WNDCLASSA cls;
1844 ret = GetClassInfoA(NULL, "Edit", &cls);
1845 ok(ret, "Failed to get class info.\n");
1847 orig_class_proc = cls.lpfnWndProc;
1848 cls.lpfnWndProc = test_class_proc;
1849 cls.lpszClassName = "TestClassName";
1851 atom = RegisterClassA(&cls);
1852 ok(atom != 0, "Failed to register class.\n");
1854 hwEdit = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atom), "Text Text",
1855 ES_MULTILINE | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_VSCROLL,
1856 10, 10, 300, 300, NULL, NULL, hinst, NULL);
1857 ok(hwEdit != NULL, "Failed to create a window.\n");
1859 DestroyWindow(hwEdit);
1860 UnregisterClassA((LPCSTR)MAKEINTATOM(atom), hinst);
1863 static void test_margins(void)
1865 DWORD old_margins, new_margins;
1866 RECT old_rect, new_rect;
1867 INT old_right_margin;
1868 HWND hwEdit;
1870 hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
1872 old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
1873 old_right_margin = HIWORD(old_margins);
1875 /* Check if setting the margins works */
1877 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
1878 new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
1879 ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
1880 ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
1882 SendMessageA(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
1883 new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
1884 ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
1885 ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
1887 /* The size of the rectangle must decrease if we increase the margin */
1889 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
1890 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
1891 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
1892 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1893 ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
1894 ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
1895 ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
1896 ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
1898 /* If we set the margin to same value as the current margin,
1899 the rectangle must not change */
1901 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
1902 SetRect(&old_rect, 1, 1, 99, 99);
1903 SendMessageA(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);
1904 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
1905 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
1906 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1907 ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
1909 /* The lParam argument of the WM_SIZE message should be ignored. */
1911 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
1912 SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, 0);
1913 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1914 ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
1915 SendMessageA(hwEdit, WM_SIZE, SIZE_MINIMIZED, 0);
1916 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1917 ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
1918 SendMessageA(hwEdit, WM_SIZE, SIZE_MAXIMIZED, 0);
1919 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1920 ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
1921 SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, MAKELONG(10, 10));
1922 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
1923 ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
1925 DestroyWindow (hwEdit);
1927 test_margins_usefontinfo(ANSI_CHARSET);
1928 test_margins_usefontinfo(EASTEUROPE_CHARSET);
1930 test_margins_usefontinfo(SHIFTJIS_CHARSET);
1931 test_margins_usefontinfo(HANGUL_CHARSET);
1932 test_margins_usefontinfo(CHINESEBIG5_CHARSET);
1933 /* Don't test JOHAB_CHARSET. Treated as CJK by Win 8,
1934 but not by < Win 8 and Win 10. */
1936 test_margins_usefontinfo(DEFAULT_CHARSET);
1938 test_margins_default("Tahoma", ANSI_CHARSET);
1939 test_margins_default("Tahoma", EASTEUROPE_CHARSET);
1941 test_margins_default("Tahoma", HANGUL_CHARSET);
1942 test_margins_default("Tahoma", CHINESEBIG5_CHARSET);
1944 if (is_font_installed("MS PGothic")) {
1945 test_margins_default("MS PGothic", SHIFTJIS_CHARSET);
1946 test_margins_default("MS PGothic", GREEK_CHARSET);
1948 else
1949 skip("MS PGothic is not available, skipping some margin tests\n");
1951 if (is_font_installed("Ume P Gothic")) {
1952 test_margins_default("Ume P Gothic", SHIFTJIS_CHARSET);
1953 test_margins_default("Ume P Gothic", GREEK_CHARSET);
1955 else
1956 skip("Ume P Gothic is not available, skipping some margin tests\n");
1958 if (is_font_installed("SimSun")) {
1959 test_margins_default("SimSun", GB2312_CHARSET);
1960 test_margins_default("SimSun", ANSI_CHARSET);
1962 else
1963 skip("SimSun is not available, skipping some margin tests\n");
1966 static void test_margins_font_change(void)
1968 DWORD margins, font_margins;
1969 HFONT hfont, hfont2;
1970 HWND hwEdit;
1971 LOGFONTA lf;
1973 if (!is_font_installed("Arial"))
1975 skip("Arial not found - skipping font change margin tests\n");
1976 return;
1979 hwEdit = create_child_editcontrol(0, 0);
1981 SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
1983 memset(&lf, 0, sizeof(lf));
1984 strcpy(lf.lfFaceName, "Arial");
1985 lf.lfHeight = 16;
1986 lf.lfCharSet = GREEK_CHARSET; /* to avoid associated charset feature */
1987 hfont = CreateFontIndirectA(&lf);
1988 lf.lfHeight = 30;
1989 hfont2 = CreateFontIndirectA(&lf);
1991 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
1992 font_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
1993 ok(LOWORD(font_margins) != 0, "got %d\n", LOWORD(font_margins));
1994 ok(HIWORD(font_margins) != 0, "got %d\n", HIWORD(font_margins));
1996 /* With 'small' edit controls, test that the margin doesn't get set */
1997 SetWindowPos(hwEdit, NULL, 10, 10, 16, 100, SWP_NOZORDER | SWP_NOACTIVATE);
1998 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0));
1999 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2000 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2001 ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins));
2002 ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
2004 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
2005 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2006 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2007 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
2008 ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
2010 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
2011 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2012 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2013 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
2014 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
2016 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
2017 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2018 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
2019 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
2021 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
2022 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2023 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
2024 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
2026 /* Above a certain size threshold then the margin is updated */
2027 SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
2028 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
2029 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2030 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2031 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
2032 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
2034 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
2035 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2036 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2037 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
2038 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
2040 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
2041 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
2042 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2043 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
2044 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
2045 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
2046 margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
2047 ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins));
2048 ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins));
2050 SendMessageA(hwEdit, WM_SETFONT, 0, 0);
2052 DeleteObject(hfont2);
2053 DeleteObject(hfont);
2054 destroy_child_editcontrol(hwEdit);
2058 #define edit_pos_ok(expected, got, txt) edit_pos_ok_(__LINE__, expected, got, #txt)
2059 static inline void edit_pos_ok_(unsigned line, DWORD expected, DWORD got, const char* txt)
2061 ok_(__FILE__, line)(expected == got, "wrong %s expected %ld got %ld\n", txt, expected, got);
2064 #define check_pos(hwEdit, set_height, test_top, test_height, test_left) \
2065 do { \
2066 RECT format_rect; \
2067 int left_margin; \
2068 set_client_height(hwEdit, set_height); \
2069 SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
2070 left_margin = LOWORD(SendMessageA(hwEdit, EM_GETMARGINS, 0, 0)); \
2071 edit_pos_ok(test_top, format_rect.top, vertical position); \
2072 edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \
2073 edit_pos_ok(test_left, format_rect.left - left_margin, left); \
2074 } while(0)
2076 static void test_text_position_style(DWORD style)
2078 HWND hwEdit;
2079 HFONT font, oldFont;
2080 HDC dc;
2081 TEXTMETRICA metrics;
2082 INT b, bm, b2, b3;
2083 BOOL xb, single_line = !(style & ES_MULTILINE);
2085 b = GetSystemMetrics(SM_CYBORDER) + 1;
2086 b2 = 2 * b;
2087 b3 = 3 * b;
2088 bm = b2 - 1;
2090 /* Get a stock font for which we can determine the metrics */
2091 font = GetStockObject(SYSTEM_FONT);
2092 ok (font != NULL, "GetStockObject SYSTEM_FONT failed\n");
2093 dc = GetDC(NULL);
2094 ok (dc != NULL, "GetDC() failed\n");
2095 oldFont = SelectObject(dc, font);
2096 xb = GetTextMetricsA(dc, &metrics);
2097 ok (xb, "GetTextMetrics failed\n");
2098 SelectObject(dc, oldFont);
2099 ReleaseDC(NULL, dc);
2101 /* Windows' edit control has some bugs in multi-line mode:
2102 * - Sometimes the format rectangle doesn't get updated
2103 * (see workaround in set_client_height())
2104 * - If the height of the control is smaller than the height of a text
2105 * line, the format rectangle is still as high as a text line
2106 * (higher than the client rectangle) and the caret is not shown
2109 /* Edit controls that are in a parent window */
2111 hwEdit = create_child_editcontrol(style | WS_VISIBLE, 0);
2112 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2113 if (single_line)
2114 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
2115 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
2116 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
2117 check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
2118 check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
2119 destroy_child_editcontrol(hwEdit);
2121 hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, 0);
2122 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2123 if (single_line)
2124 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
2125 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
2126 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
2127 check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
2128 check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
2129 check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
2130 destroy_child_editcontrol(hwEdit);
2132 hwEdit = create_child_editcontrol(style | WS_VISIBLE, WS_EX_CLIENTEDGE);
2133 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2134 if (single_line)
2135 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
2136 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
2137 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
2138 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
2139 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
2140 destroy_child_editcontrol(hwEdit);
2142 hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, WS_EX_CLIENTEDGE);
2143 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2144 if (single_line)
2145 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
2146 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
2147 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
2148 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
2149 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
2150 destroy_child_editcontrol(hwEdit);
2153 /* Edit controls that are popup windows */
2155 hwEdit = create_editcontrol(style | WS_POPUP, 0);
2156 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2157 if (single_line)
2158 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
2159 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
2160 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
2161 check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
2162 check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
2163 DestroyWindow(hwEdit);
2165 hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0);
2166 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2167 if (single_line)
2168 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
2169 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
2170 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
2171 check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
2172 check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
2173 check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
2174 DestroyWindow(hwEdit);
2176 hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE);
2177 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2178 if (single_line)
2179 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
2180 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
2181 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
2182 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
2183 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
2184 DestroyWindow(hwEdit);
2186 hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
2187 SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
2188 if (single_line)
2189 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
2190 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
2191 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
2192 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
2193 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
2194 DestroyWindow(hwEdit);
2197 static void test_text_position(void)
2199 trace("EDIT: Text position (Single line)\n");
2200 test_text_position_style(ES_AUTOHSCROLL | ES_AUTOVSCROLL);
2201 trace("EDIT: Text position (Multi line)\n");
2202 test_text_position_style(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL);
2205 static void test_espassword(void)
2207 HWND hwEdit;
2208 LONG r;
2209 char buffer[1024];
2210 const char* password = "secret";
2212 hwEdit = create_editcontrol(ES_PASSWORD, 0);
2213 r = get_edit_style(hwEdit);
2214 ok(r == ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%lx\n", r);
2215 /* set text */
2216 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) password);
2217 ok(r == TRUE, "Expected: %d, got: %ld\n", TRUE, r);
2219 /* select all, cut (ctrl-x) */
2220 SendMessageA(hwEdit, EM_SETSEL, 0, -1);
2221 r = SendMessageA(hwEdit, WM_CHAR, 24, 0);
2222 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2224 /* get text */
2225 r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2226 ok(r == strlen(password), "Expected: %s, got len %ld\n", password, r);
2227 ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer);
2229 r = OpenClipboard(hwEdit);
2230 ok(r == TRUE, "expected %d, got %ld\n", TRUE, r);
2231 r = EmptyClipboard();
2232 ok(r == TRUE, "expected %d, got %ld\n", TRUE, r);
2233 r = CloseClipboard();
2234 ok(r == TRUE, "expected %d, got %ld\n", TRUE, r);
2236 /* select all, copy (ctrl-c) and paste (ctrl-v) */
2237 SendMessageA(hwEdit, EM_SETSEL, 0, -1);
2238 r = SendMessageA(hwEdit, WM_CHAR, 3, 0);
2239 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2240 r = SendMessageA(hwEdit, WM_CHAR, 22, 0);
2241 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2243 /* get text */
2244 buffer[0] = 0;
2245 r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2246 ok(r == 0, "Expected: 0, got: %ld\n", r);
2247 ok(strcmp(buffer, "") == 0, "expected empty string, got %s\n", buffer);
2249 DestroyWindow(hwEdit);
2252 static void test_undo(void)
2254 HWND hwEdit;
2255 LONG r;
2256 DWORD cpMin, cpMax;
2257 char buffer[1024];
2258 const char* text = "undo this";
2260 hwEdit = create_editcontrol(0, 0);
2261 r = get_edit_style(hwEdit);
2262 ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r);
2264 /* set text */
2265 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) text);
2266 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2268 /* select all, */
2269 cpMin = cpMax = 0xdeadbeef;
2270 SendMessageA(hwEdit, EM_SETSEL, 0, -1);
2271 r = SendMessageA(hwEdit, EM_GETSEL, (WPARAM) &cpMin, (LPARAM) &cpMax);
2272 ok((strlen(text) << 16) == r, "Unexpected length %ld\n", r);
2273 ok(0 == cpMin, "Expected: %d, got %ld\n", 0, cpMin);
2274 ok(9 == cpMax, "Expected: %d, got %ld\n", 9, cpMax);
2276 /* cut (ctrl-x) */
2277 r = SendMessageA(hwEdit, WM_CHAR, 24, 0);
2278 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2280 /* get text */
2281 buffer[0] = 0;
2282 r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2283 ok(0 == r, "Expected: %d, got len %ld\n", 0, r);
2284 ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
2286 /* undo (ctrl-z) */
2287 r = SendMessageA(hwEdit, WM_CHAR, 26, 0);
2288 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2290 /* get text */
2291 buffer[0] = 0;
2292 r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2293 ok(strlen(text) == r, "Unexpected length %ld\n", r);
2294 ok(0 == strcmp(buffer, text), "expected %s, got %s\n", text, buffer);
2296 /* undo again (ctrl-z) */
2297 r = SendMessageA(hwEdit, WM_CHAR, 26, 0);
2298 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2300 /* get text */
2301 buffer[0] = 0;
2302 r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2303 ok(r == 0, "Expected: %d, got len %ld\n", 0, r);
2304 ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
2306 DestroyWindow(hwEdit);
2309 static void test_enter(void)
2311 char buffer[16];
2312 HWND hwEdit;
2313 LONG r;
2315 /* multiline */
2316 hwEdit = create_editcontrol(ES_MULTILINE, 0);
2317 r = get_edit_style(hwEdit);
2318 ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%lx\n", r);
2320 /* set text */
2321 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
2322 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2324 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
2325 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2327 /* get text */
2328 buffer[0] = 0;
2329 r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
2330 ok(2 == r, "Expected: %d, got len %ld\n", 2, r);
2331 ok(0 == strcmp(buffer, "\r\n"), "expected \"\\r\\n\", got \"%s\"\n", buffer);
2333 DestroyWindow (hwEdit);
2335 /* single line */
2336 hwEdit = create_editcontrol(0, 0);
2337 r = get_edit_style(hwEdit);
2338 ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r);
2340 /* set text */
2341 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
2342 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2344 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
2345 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2347 /* get text */
2348 buffer[0] = 0;
2349 r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
2350 ok(0 == r, "Expected: %d, got len %ld\n", 0, r);
2351 ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
2353 DestroyWindow(hwEdit);
2355 /* single line with ES_WANTRETURN */
2356 hwEdit = create_editcontrol(ES_WANTRETURN, 0);
2357 r = get_edit_style(hwEdit);
2358 ok(ES_WANTRETURN == r, "Wrong style expected ES_WANTRETURN got: 0x%lx\n", r);
2360 /* set text */
2361 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
2362 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2364 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
2365 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2367 /* get text */
2368 buffer[0] = 0;
2369 r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
2370 ok(0 == r, "Expected: %d, got len %ld\n", 0, r);
2371 ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
2373 DestroyWindow(hwEdit);
2376 static void test_tab(void)
2378 char buffer[16];
2379 HWND hwEdit;
2380 LONG r;
2382 /* multiline */
2383 hwEdit = create_editcontrol(ES_MULTILINE, 0);
2384 r = get_edit_style(hwEdit);
2385 ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%lx\n", r);
2387 /* set text */
2388 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
2389 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2391 r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0);
2392 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2394 /* get text */
2395 buffer[0] = 0;
2396 r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
2397 ok(1 == r, "Expected: %d, got len %ld\n", 1, r);
2398 ok(0 == strcmp(buffer, "\t"), "expected \"\\t\", got \"%s\"\n", buffer);
2400 DestroyWindow(hwEdit);
2402 /* single line */
2403 hwEdit = create_editcontrol(0, 0);
2404 r = get_edit_style(hwEdit);
2405 ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r);
2407 /* set text */
2408 r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
2409 ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r);
2411 r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0);
2412 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2414 /* get text */
2415 buffer[0] = 0;
2416 r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
2417 ok(0 == r, "Expected: %d, got len %ld\n", 0, r);
2418 ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
2420 DestroyWindow(hwEdit);
2423 static void test_edit_dialog(void)
2425 int r;
2427 /* from bug 11841 */
2428 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 0);
2429 ok(333 == r, "Expected %d, got %d\n", 333, r);
2430 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 1);
2431 ok(111 == r, "Expected %d, got %d\n", 111, r);
2432 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 2);
2433 ok(444 == r, "Expected %d, got %d\n", 444, r);
2435 /* more tests for WM_CHAR */
2436 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 3);
2437 ok(444 == r, "Expected %d, got %d\n", 444, r);
2438 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 4);
2439 ok(444 == r, "Expected %d, got %d\n", 444, r);
2440 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 5);
2441 ok(444 == r, "Expected %d, got %d\n", 444, r);
2443 /* more tests for WM_KEYDOWN + WM_CHAR */
2444 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 6);
2445 ok(444 == r, "Expected %d, got %d\n", 444, r);
2446 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 7);
2447 ok(444 == r, "Expected %d, got %d\n", 444, r);
2448 r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 8);
2449 ok(444 == r, "Expected %d, got %d\n", 444, r);
2451 /* tests with an editable edit control */
2452 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 0);
2453 ok(333 == r, "Expected %d, got %d\n", 333, r);
2454 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 1);
2455 ok(111 == r, "Expected %d, got %d\n", 111, r);
2456 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 2);
2457 ok(444 == r, "Expected %d, got %d\n", 444, r);
2459 /* tests for WM_CHAR */
2460 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 3);
2461 ok(444 == r, "Expected %d, got %d\n", 444, r);
2462 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 4);
2463 ok(444 == r, "Expected %d, got %d\n", 444, r);
2464 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 5);
2465 ok(444 == r, "Expected %d, got %d\n", 444, r);
2467 /* tests for WM_KEYDOWN + WM_CHAR */
2468 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 6);
2469 ok(444 == r, "Expected %d, got %d\n", 444, r);
2470 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 7);
2471 ok(444 == r, "Expected %d, got %d\n", 444, r);
2472 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 8);
2473 ok(444 == r, "Expected %d, got %d\n", 444, r);
2475 /* multiple tab tests */
2476 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 9);
2477 ok(22 == r, "Expected %d, got %d\n", 22, r);
2478 r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 10);
2479 ok(33 == r, "Expected %d, got %d\n", 33, r);
2482 static void test_multi_edit_dialog(void)
2484 int r;
2486 /* test for multiple edit dialogs (bug 12319) */
2487 r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 0);
2488 ok(2222 == r, "Expected %d, got %d\n", 2222, r);
2489 r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 1);
2490 ok(1111 == r, "Expected %d, got %d\n", 1111, r);
2491 r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 2);
2492 ok(2222 == r, "Expected %d, got %d\n", 2222, r);
2493 r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 3);
2494 ok(11 == r, "Expected %d, got %d\n", 11, r);
2497 static void test_wantreturn_edit_dialog(void)
2499 int r;
2501 /* tests for WM_KEYDOWN */
2502 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 0);
2503 ok(333 == r, "Expected %d, got %d\n", 333, r);
2504 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 1);
2505 ok(444 == r, "Expected %d, got %d\n", 444, r);
2506 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 2);
2507 ok(444 == r, "Expected %d, got %d\n", 444, r);
2509 /* tests for WM_CHAR */
2510 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 3);
2511 ok(444 == r, "Expected %d, got %d\n", 444, r);
2512 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 4);
2513 ok(444 == r, "Expected %d, got %d\n", 444, r);
2514 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 5);
2515 ok(444 == r, "Expected %d, got %d\n", 444, r);
2517 /* tests for WM_KEYDOWN + WM_CHAR */
2518 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 6);
2519 ok(444 == r, "Expected %d, got %d\n", 444, r);
2520 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 7);
2521 ok(444 == r, "Expected %d, got %d\n", 444, r);
2522 r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 8);
2523 ok(444 == r, "Expected %d, got %d\n", 444, r);
2526 static void test_singleline_wantreturn_edit_dialog(void)
2528 int r;
2530 /* tests for WM_KEYDOWN */
2531 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 0);
2532 ok(222 == r, "Expected %d, got %d\n", 222, r);
2533 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 1);
2534 ok(111 == r, "Expected %d, got %d\n", 111, r);
2535 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 2);
2536 ok(444 == r, "Expected %d, got %d\n", 444, r);
2538 /* tests for WM_CHAR */
2539 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 3);
2540 ok(444 == r, "Expected %d, got %d\n", 444, r);
2541 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 4);
2542 ok(444 == r, "Expected %d, got %d\n", 444, r);
2543 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 5);
2544 ok(444 == r, "Expected %d, got %d\n", 444, r);
2546 /* tests for WM_KEYDOWN + WM_CHAR */
2547 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 6);
2548 ok(222 == r, "Expected %d, got %d\n", 222, r);
2549 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 7);
2550 ok(111 == r, "Expected %d, got %d\n", 111, r);
2551 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 8);
2552 ok(444 == r, "Expected %d, got %d\n", 444, r);
2554 /* tests for WM_KEYDOWN */
2555 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 0);
2556 ok(222 == r, "Expected %d, got %d\n", 222, r);
2557 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 1);
2558 ok(111 == r, "Expected %d, got %d\n", 111, r);
2559 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 2);
2560 ok(444 == r, "Expected %d, got %d\n", 444, r);
2562 /* tests for WM_CHAR */
2563 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 3);
2564 ok(444 == r, "Expected %d, got %d\n", 444, r);
2565 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 4);
2566 ok(444 == r, "Expected %d, got %d\n", 444, r);
2567 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 5);
2568 ok(444 == r, "Expected %d, got %d\n", 444, r);
2570 /* tests for WM_KEYDOWN + WM_CHAR */
2571 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 6);
2572 ok(222 == r, "Expected %d, got %d\n", 222, r);
2573 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 7);
2574 ok(111 == r, "Expected %d, got %d\n", 111, r);
2575 r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 8);
2576 ok(444 == r, "Expected %d, got %d\n", 444, r);
2579 static int child_edit_wmkeydown_num_messages = 0;
2580 static INT_PTR CALLBACK child_edit_wmkeydown_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
2582 switch (msg)
2584 case WM_DESTROY:
2585 case WM_NCDESTROY:
2586 break;
2588 default:
2589 child_edit_wmkeydown_num_messages++;
2590 break;
2593 return FALSE;
2596 static void test_child_edit_wmkeydown(void)
2598 HWND hwEdit, hwParent;
2599 int r;
2601 hwEdit = create_child_editcontrol(0, 0);
2602 hwParent = GetParent(hwEdit);
2603 SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)child_edit_wmkeydown_proc);
2604 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
2605 ok(1 == r, "expected 1, got %d\n", r);
2606 ok(0 == child_edit_wmkeydown_num_messages, "expected 0, got %d\n", child_edit_wmkeydown_num_messages);
2607 destroy_child_editcontrol(hwEdit);
2610 static BOOL got_en_setfocus = FALSE;
2611 static BOOL got_wm_capturechanged = FALSE;
2612 static LRESULT (CALLBACK *p_edit_proc)(HWND, UINT, WPARAM, LPARAM);
2614 static LRESULT CALLBACK edit4_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2616 switch (msg) {
2617 case WM_COMMAND:
2618 switch (HIWORD(wParam))
2620 case EN_SETFOCUS:
2621 got_en_setfocus = TRUE;
2622 break;
2624 break;
2625 case WM_CAPTURECHANGED:
2626 if (hWnd != (HWND)lParam)
2628 got_wm_capturechanged = TRUE;
2629 EndMenu();
2631 break;
2633 return DefWindowProcA(hWnd, msg, wParam, lParam);
2636 struct context_menu_messages
2638 unsigned int wm_command, em_setsel;
2641 static struct context_menu_messages menu_messages;
2643 static LRESULT CALLBACK child_edit_menu_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2645 switch (msg)
2647 case WM_ENTERIDLE:
2648 if (wParam == MSGF_MENU)
2650 HWND hwndMenu = (HWND)lParam;
2651 MENUBARINFO mbi = { sizeof(mbi) };
2652 if (GetMenuBarInfo(hwndMenu, OBJID_CLIENT, 0, &mbi))
2654 MENUITEMINFOA mii = { sizeof(MENUITEMINFOA), MIIM_STATE };
2655 if (GetMenuItemInfoA(mbi.hMenu, EM_SETSEL, FALSE, &mii))
2657 if (mii.fState & MFS_HILITE)
2659 PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0x1c0001);
2660 PostMessageA(hwnd, WM_KEYUP, VK_RETURN, 0x1c0001);
2662 else
2664 PostMessageA(hwnd, WM_KEYDOWN, VK_DOWN, 0x500001);
2665 PostMessageA(hwnd, WM_KEYUP, VK_DOWN, 0x500001);
2670 break;
2671 case WM_COMMAND:
2672 menu_messages.wm_command++;
2673 break;
2674 case EM_SETSEL:
2675 menu_messages.em_setsel++;
2676 break;
2678 return CallWindowProcA(p_edit_proc, hwnd, msg, wParam, lParam);
2681 static void test_contextmenu(void)
2683 HWND hwndMain, hwndEdit;
2684 MSG msg;
2686 hwndMain = CreateWindowA(szEditTest4Class, "ET4", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
2687 0, 0, 200, 200, NULL, NULL, hinst, NULL);
2688 ok(hwndMain != NULL, "Failed to create control parent.\n");
2690 hwndEdit = CreateWindowA(WC_EDITA, NULL, WS_CHILD|WS_BORDER|WS_VISIBLE|ES_LEFT|ES_AUTOHSCROLL,
2691 0, 0, 150, 50, /* important this not be 0 size. */
2692 hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
2693 ok(hwndEdit != NULL, "Failed to create Edit control.\n");
2695 SetFocus(NULL);
2696 SetCapture(hwndMain);
2697 SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(10, 10));
2698 ok(got_en_setfocus, "edit box didn't get focused\n");
2699 ok(got_wm_capturechanged, "main window capture did not change\n");
2701 DestroyWindow(hwndEdit);
2703 hwndEdit = CreateWindowA("EDIT", "Test Text",
2704 WS_CHILD | WS_BORDER | WS_VISIBLE,
2705 0, 0, 100, 100,
2706 hwndMain, NULL, hinst, NULL);
2707 memset(&menu_messages, 0, sizeof(menu_messages));
2708 p_edit_proc = (void*)SetWindowLongPtrA(hwndEdit, GWLP_WNDPROC,
2709 (ULONG_PTR)child_edit_menu_proc);
2711 SetFocus(hwndEdit);
2712 SendMessageA(hwndEdit, WM_SETTEXT, 0, (LPARAM)"foo");
2713 SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(-1, -1));
2714 while (PeekMessageA(&msg, hwndEdit, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2715 ok(menu_messages.wm_command == 0,
2716 "Expected no WM_COMMAND messages, got %d\n", menu_messages.wm_command);
2717 ok(menu_messages.em_setsel == 1,
2718 "Expected 1 EM_SETSEL message, got %d\n", menu_messages.em_setsel);
2720 DestroyWindow(hwndEdit);
2721 DestroyWindow(hwndMain);
2724 static BOOL register_classes(void)
2726 WNDCLASSA test2;
2727 WNDCLASSA test3;
2728 WNDCLASSA test4;
2729 WNDCLASSA text_position;
2730 WNDCLASSA wc;
2732 test2.style = 0;
2733 test2.lpfnWndProc = ET2_WndProc;
2734 test2.cbClsExtra = 0;
2735 test2.cbWndExtra = 0;
2736 test2.hInstance = hinst;
2737 test2.hIcon = NULL;
2738 test2.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
2739 test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2740 test2.lpszMenuName = NULL;
2741 test2.lpszClassName = szEditTest2Class;
2742 if (!RegisterClassA(&test2)) return FALSE;
2744 test3.style = 0;
2745 test3.lpfnWndProc = edit3_wnd_procA;
2746 test3.cbClsExtra = 0;
2747 test3.cbWndExtra = 0;
2748 test3.hInstance = hinst;
2749 test3.hIcon = 0;
2750 test3.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
2751 test3.hbrBackground = GetStockObject(WHITE_BRUSH);
2752 test3.lpszMenuName = NULL;
2753 test3.lpszClassName = szEditTest3Class;
2754 if (!RegisterClassA(&test3)) return FALSE;
2756 test4.style = 0;
2757 test4.lpfnWndProc = edit4_wnd_procA;
2758 test4.cbClsExtra = 0;
2759 test4.cbWndExtra = 0;
2760 test4.hInstance = hinst;
2761 test4.hIcon = NULL;
2762 test4.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
2763 test4.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2764 test4.lpszMenuName = NULL;
2765 test4.lpszClassName = szEditTest4Class;
2766 if (!RegisterClassA(&test4)) return FALSE;
2768 text_position.style = CS_HREDRAW | CS_VREDRAW;
2769 text_position.cbClsExtra = 0;
2770 text_position.cbWndExtra = 0;
2771 text_position.hInstance = hinst;
2772 text_position.hIcon = NULL;
2773 text_position.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2774 text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2775 text_position.lpszMenuName = NULL;
2776 text_position.lpszClassName = szEditTextPositionClass;
2777 text_position.lpfnWndProc = DefWindowProcA;
2778 if (!RegisterClassA(&text_position)) return FALSE;
2780 memset(&wc, 0, sizeof(wc));
2781 wc.lpfnWndProc = parent_wnd_proc;
2782 wc.hInstance = GetModuleHandleA(NULL);
2783 wc.lpszClassName = "ParentWnd";
2784 if (!RegisterClassA(&wc)) return FALSE;
2786 return TRUE;
2789 static void UnregisterWindowClasses (void)
2791 UnregisterClassA(szEditTest2Class, hinst);
2792 UnregisterClassA(szEditTest3Class, hinst);
2793 UnregisterClassA(szEditTest4Class, hinst);
2794 UnregisterClassA(szEditTextPositionClass, hinst);
2797 static void test_fontsize(void)
2799 HWND hwEdit;
2800 HFONT hfont;
2801 HDC hDC;
2802 LOGFONTA lf;
2803 LONG r;
2804 char szLocalString[MAXLEN];
2805 int dpi;
2807 hDC = GetDC(NULL);
2808 dpi = GetDeviceCaps(hDC, LOGPIXELSY);
2809 ReleaseDC(NULL, hDC);
2811 memset(&lf,0,sizeof(LOGFONTA));
2812 strcpy(lf.lfFaceName,"Arial");
2813 lf.lfHeight = -300; /* taller than the edit box */
2814 lf.lfWeight = 500;
2815 hfont = CreateFontIndirectA(&lf);
2817 trace("EDIT: Oversized font (Multi line)\n");
2818 hwEdit= CreateWindowA("EDIT", NULL, ES_MULTILINE|ES_AUTOHSCROLL,
2819 0, 0, (150 * dpi) / 96, (50 * dpi) / 96, NULL, NULL,
2820 hinst, NULL);
2822 SendMessageA(hwEdit,WM_SETFONT,(WPARAM)hfont,0);
2824 if (winetest_interactive)
2825 ShowWindow (hwEdit, SW_SHOW);
2827 r = SendMessageA(hwEdit, WM_CHAR, 'A', 1);
2828 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2829 r = SendMessageA(hwEdit, WM_CHAR, 'B', 1);
2830 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2831 r = SendMessageA(hwEdit, WM_CHAR, 'C', 1);
2832 ok(1 == r, "Expected: %d, got: %ld\n", 1, r);
2834 GetWindowTextA(hwEdit, szLocalString, MAXLEN);
2835 ok(strcmp(szLocalString, "ABC")==0,
2836 "Wrong contents of edit: %s\n", szLocalString);
2838 r = SendMessageA(hwEdit, EM_POSFROMCHAR,0,0);
2839 ok(r != -1,"EM_POSFROMCHAR failed index 0\n");
2840 r = SendMessageA(hwEdit, EM_POSFROMCHAR,1,0);
2841 ok(r != -1,"EM_POSFROMCHAR failed index 1\n");
2842 r = SendMessageA(hwEdit, EM_POSFROMCHAR,2,0);
2843 ok(r != -1,"EM_POSFROMCHAR failed index 2\n");
2844 r = SendMessageA(hwEdit, EM_POSFROMCHAR,3,0);
2845 ok(r == -1,"EM_POSFROMCHAR succeeded index 3\n");
2847 DestroyWindow (hwEdit);
2848 DeleteObject(hfont);
2851 struct dialog_mode_messages
2853 int wm_getdefid, wm_close, wm_command, wm_nextdlgctl;
2856 static struct dialog_mode_messages dm_messages;
2858 static void zero_dm_messages(void)
2860 dm_messages.wm_command = 0;
2861 dm_messages.wm_close = 0;
2862 dm_messages.wm_getdefid = 0;
2863 dm_messages.wm_nextdlgctl = 0;
2866 #define test_dm_messages(wmcommand, wmclose, wmgetdefid, wmnextdlgctl) \
2867 ok(dm_messages.wm_command == wmcommand, "expected %d WM_COMMAND messages, " \
2868 "got %d\n", wmcommand, dm_messages.wm_command); \
2869 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE messages, " \
2870 "got %d\n", wmclose, dm_messages.wm_close); \
2871 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID messages, " \
2872 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
2873 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL messages, " \
2874 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
2876 static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
2878 switch (iMsg)
2880 case WM_COMMAND:
2881 dm_messages.wm_command++;
2882 break;
2883 case DM_GETDEFID:
2884 dm_messages.wm_getdefid++;
2885 return MAKELONG(ID_EDITTESTDBUTTON, DC_HASDEFID);
2886 case WM_NEXTDLGCTL:
2887 dm_messages.wm_nextdlgctl++;
2888 break;
2889 case WM_CLOSE:
2890 dm_messages.wm_close++;
2891 break;
2894 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
2897 static void test_dialogmode(void)
2899 HWND hwEdit, hwParent, hwButton;
2900 MSG msg= {0};
2901 int len, r;
2902 hwEdit = create_child_editcontrol(ES_MULTILINE, 0);
2904 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2905 ok(1 == r, "expected 1, got %d\n", r);
2906 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2907 ok(11 == len, "expected 11, got %d\n", len);
2909 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, 0);
2910 ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
2912 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2913 ok(1 == r, "expected 1, got %d\n", r);
2914 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2915 ok(13 == len, "expected 13, got %d\n", len);
2917 r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
2918 ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
2919 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2920 ok(1 == r, "expected 1, got %d\n", r);
2921 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2922 ok(13 == len, "expected 13, got %d\n", len);
2924 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2925 ok(1 == r, "expected 1, got %d\n", r);
2926 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2927 ok(13 == len, "expected 13, got %d\n", len);
2929 destroy_child_editcontrol(hwEdit);
2931 hwEdit = create_editcontrol(ES_MULTILINE, 0);
2933 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2934 ok(1 == r, "expected 1, got %d\n", r);
2935 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2936 ok(11 == len, "expected 11, got %d\n", len);
2938 msg.hwnd = hwEdit;
2939 msg.message = WM_KEYDOWN;
2940 msg.wParam = VK_BACK;
2941 msg.lParam = 0xe0001;
2942 r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_BACK, (LPARAM)&msg);
2943 ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
2945 r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
2946 ok(1 == r, "expected 1, got %d\n", r);
2947 len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
2948 ok(11 == len, "expected 11, got %d\n", len);
2950 DestroyWindow(hwEdit);
2952 hwEdit = create_child_editcontrol(0, 0);
2953 hwParent = GetParent(hwEdit);
2954 SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc);
2956 zero_dm_messages();
2957 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
2958 ok(1 == r, "expected 1, got %d\n", r);
2959 test_dm_messages(0, 0, 0, 0);
2960 zero_dm_messages();
2962 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
2963 ok(1 == r, "expected 1, got %d\n", r);
2964 test_dm_messages(0, 0, 0, 0);
2965 zero_dm_messages();
2967 msg.hwnd = hwEdit;
2968 msg.message = WM_KEYDOWN;
2969 msg.wParam = VK_TAB;
2970 msg.lParam = 0xf0001;
2971 r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_TAB, (LPARAM)&msg);
2972 ok(0x89 == r, "expected 0x89, got 0x%x\n", r);
2973 test_dm_messages(0, 0, 0, 0);
2974 zero_dm_messages();
2976 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
2977 ok(1 == r, "expected 1, got %d\n", r);
2978 test_dm_messages(0, 0, 0, 0);
2979 zero_dm_messages();
2981 destroy_child_editcontrol(hwEdit);
2983 hwEdit = create_child_editcontrol(ES_MULTILINE, 0);
2984 hwParent = GetParent(hwEdit);
2985 SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc);
2987 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
2988 ok(1 == r, "expected 1, got %d\n", r);
2989 test_dm_messages(0, 0, 0, 0);
2990 zero_dm_messages();
2992 msg.hwnd = hwEdit;
2993 msg.message = WM_KEYDOWN;
2994 msg.wParam = VK_ESCAPE;
2995 msg.lParam = 0x10001;
2996 r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_ESCAPE, (LPARAM)&msg);
2997 ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
2998 test_dm_messages(0, 0, 0, 0);
2999 zero_dm_messages();
3001 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
3002 ok(1 == r, "expected 1, got %d\n", r);
3003 test_dm_messages(0, 0, 0, 0);
3004 zero_dm_messages();
3006 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
3007 ok(1 == r, "expected 1, got %d\n", r);
3008 test_dm_messages(0, 0, 0, 1);
3009 zero_dm_messages();
3011 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
3012 ok(1 == r, "expected 1, got %d\n", r);
3013 test_dm_messages(0, 0, 1, 0);
3014 zero_dm_messages();
3016 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
3017 100, 100, 50, 20, hwParent, (HMENU)ID_EDITTESTDBUTTON, hinst, NULL);
3018 ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError());
3020 r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
3021 ok(1 == r, "expected 1, got %d\n", r);
3022 test_dm_messages(0, 0, 1, 1);
3023 zero_dm_messages();
3025 DestroyWindow(hwButton);
3026 destroy_child_editcontrol(hwEdit);
3029 static void test_EM_GETHANDLE(void)
3031 static const WCHAR str1W[] = {'1','1','1','1','+','1','1','1','1','+','1','1','1','1','#',0};
3032 static const WCHAR str2W[] = {'2','2','2','2','-','2','2','2','2','-','2','2','2','2','-','2','2','2','2','#',0};
3033 static const char str0[] = "untouched";
3034 static const char str1[] = "1111+1111+1111#";
3035 static const char str1_1[] = "2111+1111+1111#";
3036 static const char str2[] = "2222-2222-2222-2222#";
3037 static const char str3[] = "3333*3333*3333*3333*3333#";
3038 CHAR current[42];
3039 HWND hEdit;
3040 HLOCAL hmem;
3041 HLOCAL hmem2;
3042 HLOCAL halloc;
3043 WCHAR *buffer;
3044 int len;
3045 int r;
3047 trace("EDIT: EM_GETHANDLE\n");
3049 /* EM_GETHANDLE is not supported for a single line edit control */
3050 hEdit = create_editcontrol(WS_BORDER, 0);
3051 ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit);
3053 hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0);
3054 ok(hmem == NULL, "got %p (expected NULL)\n", hmem);
3055 DestroyWindow(hEdit);
3057 /* EM_GETHANDLE needs a multiline edit control */
3058 hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0);
3059 ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit);
3061 /* set some text */
3062 r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1);
3063 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3064 ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1));
3066 lstrcpyA(current, str0);
3067 r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
3068 ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1),
3069 "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1), str1);
3071 hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0);
3072 ok(hmem != NULL, "got %p (expected != NULL)\n", hmem);
3073 /* The buffer belongs to the app now. According to MSDN, the app has to LocalFree the
3074 buffer, LocalAlloc a new buffer and pass it to the edit control with EM_SETHANDLE. */
3076 buffer = LocalLock(hmem);
3077 ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
3078 len = lstrlenW(buffer);
3079 ok(len == lstrlenW(str1W) && !lstrcmpW(buffer, str1W), "Unexpected buffer contents %s, length %d.\n",
3080 wine_dbgstr_w(buffer), len);
3081 LocalUnlock(hmem);
3083 /* See if WM_GETTEXTLENGTH/WM_GETTEXT still work. */
3084 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3085 ok(len == lstrlenA(str1), "Unexpected text length %d.\n", len);
3087 lstrcpyA(current, str0);
3088 r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
3089 ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1),
3090 "Unexpected retval %d and text \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1), str1);
3092 /* Application altered buffer contents, see if WM_GETTEXTLENGTH/WM_GETTEXT pick that up. */
3093 buffer = LocalLock(hmem);
3094 ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
3095 buffer[0] = '2';
3096 LocalUnlock(hmem);
3098 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3099 ok(len == lstrlenA(str1_1), "Unexpected text length %d.\n", len);
3101 lstrcpyA(current, str0);
3102 r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
3103 ok(r == lstrlenA(str1_1) && !lstrcmpA(current, str1_1),
3104 "Unexpected retval %d and text \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1_1), str1_1);
3106 /* See if WM_SETTEXT/EM_REPLACESEL work. */
3107 r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1);
3108 ok(r, "Failed to set text.\n");
3110 buffer = LocalLock(hmem);
3111 ok(buffer != NULL && buffer[0] == '1', "Unexpected buffer contents\n");
3112 LocalUnlock(hmem);
3114 r = SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)str1_1);
3115 ok(r, "Failed to replace selection.\n");
3117 buffer = LocalLock(hmem);
3118 ok(buffer != NULL && buffer[0] == '2', "Unexpected buffer contents\n");
3119 LocalUnlock(hmem);
3121 /* use LocalAlloc first to get a different handle */
3122 halloc = LocalAlloc(LMEM_MOVEABLE, 42);
3123 ok(halloc != NULL, "got %p (expected != NULL)\n", halloc);
3124 /* prepare our new memory */
3125 buffer = LocalLock(halloc);
3126 ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
3127 lstrcpyW(buffer, str2W);
3128 LocalUnlock(halloc);
3130 /* LocalFree the old memory handle before EM_SETHANDLE the new handle */
3131 LocalFree(hmem);
3132 /* use LocalAlloc after the LocalFree to likely consume the handle */
3133 hmem2 = LocalAlloc(LMEM_MOVEABLE, 42);
3134 ok(hmem2 != NULL, "got %p (expected != NULL)\n", hmem2);
3136 SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)halloc, 0);
3138 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3139 ok(len == lstrlenA(str2), "got %d (expected %d)\n", len, lstrlenA(str2));
3141 lstrcpyA(current, str0);
3142 r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
3143 ok(r == lstrlenA(str2) && !lstrcmpA(current, str2),
3144 "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str2), str2);
3146 /* set a different text */
3147 r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str3);
3148 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3149 ok((r == 1) && (len == lstrlenA(str3)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str3));
3151 lstrcpyA(current, str0);
3152 r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
3153 ok((r == lstrlenA(str3)) && !lstrcmpA(current, str3),
3154 "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str3), str3);
3156 LocalFree(hmem2);
3157 DestroyWindow(hEdit);
3159 /* Some apps have bugs ... */
3160 hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0);
3162 /* set some text */
3163 r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1);
3164 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3165 ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1));
3167 /* everything is normal up to EM_GETHANDLE */
3168 hmem = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0);
3169 /* Some messages still work while other messages fail.
3170 After LocalFree the memory handle, messages can crash the app */
3172 /* A buggy editor used EM_GETHANDLE twice */
3173 hmem2 = (HGLOBAL) SendMessageA(hEdit, EM_GETHANDLE, 0, 0);
3174 ok(hmem2 == hmem, "got %p (expected %p)\n", hmem2, hmem);
3176 /* Let the edit control free the memory handle */
3177 SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)hmem2, 0);
3179 DestroyWindow(hEdit);
3182 static void test_paste(void)
3184 static const char *str = "this is a simple text";
3185 static const char *str2 = "first line\r\nsecond line";
3186 HWND hEdit, hMultilineEdit;
3187 HANDLE hmem, hmem_ret;
3188 char *buffer;
3189 int r, len;
3191 hEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
3192 hMultilineEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0);
3194 /* Prepare clipboard data with simple text */
3195 hmem = GlobalAlloc(GMEM_MOVEABLE, 255);
3196 ok(hmem != NULL, "got %p (expected != NULL)\n", hmem);
3197 buffer = GlobalLock(hmem);
3198 ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
3199 strcpy(buffer, str);
3200 GlobalUnlock(hmem);
3202 r = OpenClipboard(hEdit);
3203 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3204 r = EmptyClipboard();
3205 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3206 hmem_ret = SetClipboardData(CF_TEXT, hmem);
3207 ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret);
3208 r = CloseClipboard();
3209 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3211 /* Paste single line */
3212 SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)"");
3213 r = SendMessageA(hEdit, WM_PASTE, 0, 0);
3214 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3215 ok(strlen(str) == len, "got %d\n", len);
3217 /* Prepare clipboard data with multiline text */
3218 hmem = GlobalAlloc(GMEM_MOVEABLE, 255);
3219 ok(hmem != NULL, "got %p (expected != NULL)\n", hmem);
3220 buffer = GlobalLock(hmem);
3221 ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
3222 strcpy(buffer, str2);
3223 GlobalUnlock(hmem);
3225 r = OpenClipboard(hEdit);
3226 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3227 r = EmptyClipboard();
3228 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3229 hmem_ret = SetClipboardData(CF_TEXT, hmem);
3230 ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret);
3231 r = CloseClipboard();
3232 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
3234 /* Paste multiline text in singleline edit - should be cut */
3235 SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)"");
3236 r = SendMessageA(hEdit, WM_PASTE, 0, 0);
3237 len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
3238 ok(strlen("first line") == len, "got %d\n", len);
3240 /* Paste multiline text in multiline edit */
3241 SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)"");
3242 r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0);
3243 len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0);
3244 ok(strlen(str2) == len, "got %d\n", len);
3246 /* Cleanup */
3247 DestroyWindow(hEdit);
3248 DestroyWindow(hMultilineEdit);
3251 static void test_EM_GETLINE(void)
3253 HWND hwnd[2];
3254 int i;
3256 hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
3257 hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
3259 for (i = 0; i < ARRAY_SIZE(hwnd); i++)
3261 static const WCHAR strW[] = {'t','e','x','t',0};
3262 static const char *str = "text";
3263 WCHAR buffW[16];
3264 char buff[16];
3265 int r;
3267 ok(IsWindowUnicode(hwnd[i]), "Expected unicode window.\n");
3269 SendMessageA(hwnd[i], WM_SETTEXT, 0, (LPARAM)str);
3271 memset(buff, 0, sizeof(buff));
3272 *(WORD *)buff = sizeof(buff);
3273 r = SendMessageA(hwnd[i], EM_GETLINE, 0, (LPARAM)buff);
3274 ok(r == strlen(str), "Failed to get a line %d.\n", r);
3275 ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff);
3277 memset(buff, 0, sizeof(buff));
3278 *(WORD *)buff = sizeof(buff);
3279 r = SendMessageA(hwnd[i], EM_GETLINE, 1, (LPARAM)buff);
3280 ok(r == strlen(str), "Failed to get a line %d.\n", r);
3281 ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff);
3283 memset(buffW, 0, sizeof(buffW));
3284 *(WORD *)buffW = ARRAY_SIZE(buffW);
3285 r = SendMessageW(hwnd[i], EM_GETLINE, 0, (LPARAM)buffW);
3286 ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r);
3287 ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW));
3289 memset(buffW, 0, sizeof(buffW));
3290 *(WORD *)buffW = ARRAY_SIZE(buffW);
3291 r = SendMessageW(hwnd[i], EM_GETLINE, 1, (LPARAM)buffW);
3292 ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r);
3293 ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW));
3295 DestroyWindow(hwnd[i]);
3299 static int CALLBACK test_wordbreak_procA(char *text, int current, int length, int code)
3301 return -1;
3304 static void test_wordbreak_proc(void)
3306 EDITWORDBREAKPROCA proc;
3307 LRESULT ret;
3308 HWND hwnd;
3310 hwnd = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
3312 proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0);
3313 ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc);
3315 ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)test_wordbreak_procA);
3316 ok(ret == 1, "Unexpected return value %Id.\n", ret);
3318 proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0);
3319 ok(proc == test_wordbreak_procA, "Unexpected wordbreak proc %p.\n", proc);
3321 ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, 0);
3322 ok(ret == 1, "Unexpected return value %Id.\n", ret);
3324 proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0);
3325 ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc);
3327 DestroyWindow(hwnd);
3330 static const struct message setfocus_combined_seq[] =
3332 { WM_KILLFOCUS, sent|id, 0, 0, PARENT_ID },
3333 { WM_SETFOCUS, sent|id, 0, 0, EDIT_ID },
3334 { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_SETFOCUS), 0, PARENT_ID },
3335 { WM_PAINT, sent|id, 0, 0, EDIT_ID },
3336 { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID },
3337 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, EDIT_ID },
3338 { 0 }
3341 static const struct message killfocus_combined_seq[] =
3343 { WM_KILLFOCUS, sent|id, 0, 0, EDIT_ID },
3344 { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_KILLFOCUS), 0, PARENT_ID },
3345 { WM_SETFOCUS, sent|id, 0, 0, PARENT_ID },
3346 { WM_PAINT, sent|id, 0, 0, EDIT_ID },
3347 { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID },
3348 { 0 }
3351 static const struct message setfocus_sent_only_combined_seq[] =
3353 { WM_KILLFOCUS, sent|id, 0, 0, PARENT_ID },
3354 { WM_SETFOCUS, sent|id, 0, 0, EDIT_ID },
3355 { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_SETFOCUS), 0, PARENT_ID },
3356 { 0 }
3359 static const struct message killfocus_sent_only_combined_seq[] =
3361 { WM_KILLFOCUS, sent|id, 0, 0, EDIT_ID },
3362 { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_KILLFOCUS), 0, PARENT_ID },
3363 { WM_SETFOCUS, sent|id, 0, 0, PARENT_ID },
3364 { 0 }
3367 static void test_cue_banner(void)
3369 HWND hwnd_edit;
3370 BOOL ret;
3371 static WCHAR getcuetestW[5] = {'T',0};
3372 static const WCHAR testcmp1W[] = {'T','e','s','t',0};
3373 static const WCHAR testcmp2W[] = {'T','e','s',0};
3375 hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
3377 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
3378 if (getcuetestW[0])
3380 win_skip("skipping for Win XP and 2003 Server.\n");
3381 DestroyWindow(hwnd_edit);
3382 return;
3384 ok(!getcuetestW[0], "First char is %c\n", getcuetestW[0]);
3385 ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
3387 lstrcpyW(getcuetestW, testcmp1W);
3388 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 0);
3389 ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW));
3390 ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
3392 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0);
3393 ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
3395 ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, 0);
3396 ok(ret == FALSE, "EM_SETCUEBANNER should have returned FALSE.\n");
3398 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0);
3399 ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
3401 lstrcpyW(getcuetestW, testcmp1W);
3402 ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW);
3403 ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
3405 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 5);
3406 ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
3408 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
3409 ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
3410 ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
3412 ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)L"");
3413 ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
3415 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
3416 ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
3417 ok(!getcuetestW[0], "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
3419 /* EM_GETCUEBANNER's buffer size includes null char */
3420 ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)testcmp1W);
3421 ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
3422 memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR));
3423 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)+1);
3424 ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
3425 ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
3426 memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR));
3427 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W));
3428 ok(lstrcmpW(getcuetestW, testcmp2W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
3429 DestroyWindow(hwnd_edit);
3431 /* setting cue banner fails for multi-line edit controls */
3432 hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0);
3433 lstrcpyW(getcuetestW, testcmp1W);
3434 ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
3435 ok(ret == FALSE, "EM_SETCUEBANNER.\n");
3436 ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW));
3437 ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW);
3438 ok(ret == FALSE, "EM_SETCUEBANNER.\n");
3440 DestroyWindow(hwnd_edit);
3443 static void test_change_focus(void)
3445 HWND hwnd, parent_wnd;
3446 WNDPROC oldproc;
3447 MSG msg;
3448 POINT orig_pos;
3450 GetCursorPos(&orig_pos);
3452 parent_wnd = CreateWindowA("ParentWnd", "", WS_OVERLAPPEDWINDOW,
3453 0, 0, 200, 200, NULL, NULL, GetModuleHandleA(NULL), NULL);
3454 ok(parent_wnd != NULL, "Failed to create control parent.\n");
3455 SetWindowPos(parent_wnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
3456 ShowWindow(parent_wnd, SW_SHOW);
3458 hwnd = CreateWindowExA(0, WC_EDITA, "Test", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100,
3459 parent_wnd, (HMENU)1, GetModuleHandleA(NULL), NULL);
3460 ok(hwnd != NULL, "Failed to create Edit control.\n");
3462 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_subclass_proc);
3463 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
3465 SetCursorPos(400, 400);
3466 flush_events();
3468 SetFocus(parent_wnd);
3469 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3470 SetFocus(hwnd);
3471 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3472 ok_sequence(sequences, COMBINED_SEQ_INDEX, setfocus_combined_seq, "Set focus", TRUE);
3474 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3475 SetFocus(parent_wnd);
3476 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3477 ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_combined_seq, "Kill focus", FALSE);
3479 /* Test message sequences without waiting for posted messages */
3480 SetFocus(parent_wnd);
3481 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3482 SetFocus(hwnd);
3483 ok_sequence(sequences, COMBINED_SEQ_INDEX, setfocus_sent_only_combined_seq,
3484 "Set focus sent only", FALSE);
3486 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3487 SetFocus(parent_wnd);
3488 ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_sent_only_combined_seq,
3489 "Kill focus sent only", FALSE);
3491 SetCursorPos(orig_pos.x, orig_pos.y);
3493 DestroyWindow(hwnd);
3496 static const struct message wm_ime_composition_seq[] =
3498 {WM_IME_STARTCOMPOSITION, sent},
3499 {WM_IME_COMPOSITION, sent | wparam, 'W'},
3500 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
3501 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
3502 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
3503 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
3504 {WM_IME_ENDCOMPOSITION, sent},
3505 {WM_CHAR, sent | wparam, 'W'},
3506 {WM_CHAR, sent | wparam, 'i'},
3507 {WM_CHAR, sent | wparam, 'n'},
3508 {WM_CHAR, sent | wparam, 'e'},
3512 static const struct message wm_ime_char_seq[] =
3514 {WM_IME_CHAR, sent | wparam, '0'},
3515 {WM_CHAR, sent | wparam, '0'},
3519 static const struct message eimes_getcompstratonce_seq[] =
3521 {WM_IME_STARTCOMPOSITION, sent},
3522 {WM_IME_COMPOSITION, sent | wparam, 'W'},
3523 {WM_IME_ENDCOMPOSITION, sent},
3527 static LRESULT CALLBACK edit_ime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3529 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
3530 static LONG defwndproc_counter = 0;
3531 struct message msg = {0};
3532 LRESULT ret;
3534 msg.message = message;
3535 msg.flags = sent | wparam;
3536 if (defwndproc_counter)
3537 msg.flags |= defwinproc;
3538 msg.wParam = wParam;
3540 if (message < 0xc000 &&
3541 message != WM_GETTEXTLENGTH &&
3542 message != WM_GETTEXT &&
3543 message != WM_GETFONT &&
3544 message != WM_GETICON &&
3545 message != WM_IME_SETCONTEXT &&
3546 message != WM_IME_NOTIFY &&
3547 message != WM_CTLCOLOREDIT &&
3548 message != WM_PAINT &&
3549 message != WM_ERASEBKGND &&
3550 message != WM_NCHITTEST &&
3551 message != WM_SETCURSOR &&
3552 message != WM_MOUSEMOVE &&
3553 message != WM_MOUSEACTIVATE &&
3554 message != WM_KEYUP &&
3555 (message < EM_GETSEL || message > EM_GETIMESTATUS))
3557 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
3560 defwndproc_counter++;
3561 if (IsWindowUnicode(hwnd))
3562 ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam);
3563 else
3564 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
3565 defwndproc_counter--;
3567 return ret;
3570 static void test_ime(void)
3572 WNDPROC old_proc;
3573 LRESULT lr;
3574 HIMC himc;
3575 HWND hwnd;
3576 BOOL ret;
3577 MSG msg;
3579 hwnd = create_editcontrol(WS_POPUP | WS_VISIBLE, 0);
3581 /* Test EM_{GET|SET}IMESTATUS */
3582 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3583 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
3585 /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about
3586 * returning the previous LPARAM value */
3587 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
3588 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3589 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3590 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
3592 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS);
3593 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3594 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3595 ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr);
3597 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS);
3598 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3599 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3600 ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr);
3602 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE
3603 | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS);
3604 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3605 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3606 ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS),
3607 "Got unexpected lr %#Ix.\n", lr);
3609 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3610 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3611 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3612 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
3614 /* Invalid EM_{GET|SET}IMESTATUS status types and flags */
3615 lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0);
3616 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3618 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0);
3619 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3621 lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE);
3622 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3623 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3624 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
3626 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE);
3627 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3628 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3629 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
3631 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF);
3632 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3633 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3634 ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr);
3636 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3637 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3638 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3639 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
3641 /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */
3642 old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc);
3643 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc);
3645 himc = ImmGetContext(hwnd);
3646 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
3647 ok(ret, "ImmSetCompositionStringA failed.\n");
3648 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3649 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
3650 ok(ret, "ImmNotifyIME failed.\n");
3651 /* Note that the following message loop is necessary to get the WM_CHAR messages because they
3652 * are posted. Same for the later message loops in this function. */
3653 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3654 ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE);
3656 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */
3657 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3658 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
3659 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3660 ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_char_seq, "WM_IME_CHAR", FALSE);
3662 /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */
3663 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
3664 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
3665 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
3666 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
3668 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
3669 ok(ret, "ImmSetCompositionStringA failed.\n");
3670 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3671 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
3672 ok(ret, "ImmNotifyIME failed.\n");
3673 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3674 ok_sequence(sequences, COMBINED_SEQ_INDEX, eimes_getcompstratonce_seq,
3675 "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
3677 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */
3678 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3679 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
3680 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
3681 ok_sequence(sequences, COMBINED_SEQ_INDEX, wm_ime_char_seq, "WM_IME_CHAR", FALSE);
3683 ImmReleaseContext(hwnd, himc);
3684 DestroyWindow(hwnd);
3687 START_TEST(edit)
3689 ULONG_PTR ctx_cookie;
3690 HANDLE hCtx;
3691 BOOL b;
3693 if (!load_v6_module(&ctx_cookie, &hCtx))
3694 return;
3696 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
3698 hinst = GetModuleHandleA(NULL);
3699 b = register_classes();
3700 ok(b, "Failed to register test classes.\n");
3701 if (!b) return;
3703 test_edit_control_1();
3704 test_edit_control_2();
3705 test_edit_control_3();
3706 test_char_from_pos();
3707 test_edit_control_5();
3708 test_edit_control_6();
3709 test_edit_control_limittext();
3710 test_edit_control_scroll();
3711 test_initialization();
3712 test_margins();
3713 test_margins_font_change();
3714 test_text_position();
3715 test_espassword();
3716 test_undo();
3717 test_enter();
3718 test_tab();
3719 test_edit_dialog();
3720 test_multi_edit_dialog();
3721 test_wantreturn_edit_dialog();
3722 test_singleline_wantreturn_edit_dialog();
3723 test_child_edit_wmkeydown();
3724 test_fontsize();
3725 test_dialogmode();
3726 test_contextmenu();
3727 test_EM_GETHANDLE();
3728 test_paste();
3729 test_EM_GETLINE();
3730 test_wordbreak_proc();
3731 test_change_focus();
3732 test_cue_banner();
3733 test_ime();
3735 UnregisterWindowClasses();
3737 unload_v6_module(ctx_cookie, hCtx);