push b7454c0be268e63e23db077ecd5238ed6dc9ec0b
[wine/hacks.git] / dlls / user32 / tests / edit.c
blob74092beee566bfe89511849c6d36e46e0f54d54f
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 <assert.h>
22 #include <windows.h>
23 #include <commctrl.h>
25 #include "wine/test.h"
27 #ifndef ES_COMBO
28 #define ES_COMBO 0x200
29 #endif
31 #define ID_EDITTEST2 99
32 #define MAXLEN 200
34 struct edit_notify {
35 int en_change, en_maxtext, en_update;
38 static struct edit_notify notifications;
40 static INT_PTR CALLBACK edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
42 switch (msg)
44 case WM_INITDIALOG:
46 HWND hedit = GetDlgItem(hdlg, 1000);
47 SetFocus(hedit);
48 switch (lparam)
50 /* from bug 11841 */
51 case 0:
52 PostMessage(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
53 break;
54 case 1:
55 PostMessage(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
56 break;
57 case 2:
58 PostMessage(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
59 PostMessage(hdlg, WM_USER, 0xdeadbeef, 1);
60 break;
62 /* more test cases for WM_CHAR */
63 case 3:
64 PostMessage(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
65 PostMessage(hdlg, WM_USER, 0xdeadbeef, 0);
66 break;
67 case 4:
68 PostMessage(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
69 PostMessage(hdlg, WM_USER, 0xdeadbeef, 0);
70 break;
71 case 5:
72 PostMessage(hedit, WM_CHAR, VK_TAB, 0xf0001);
73 PostMessage(hdlg, WM_USER, 0xdeadbeef, 0);
74 break;
76 /* more test cases for WM_KEYDOWN + WM_CHAR */
77 case 6:
78 PostMessage(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
79 PostMessage(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
80 PostMessage(hdlg, WM_USER, 0xdeadbeef, 0);
81 break;
82 case 7:
83 PostMessage(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
84 PostMessage(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
85 PostMessage(hdlg, WM_USER, 0xdeadbeef, 1);
86 break;
87 case 8:
88 PostMessage(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
89 PostMessage(hedit, WM_CHAR, VK_TAB, 0xf0001);
90 PostMessage(hdlg, WM_USER, 0xdeadbeef, 1);
91 break;
93 default:
94 break;
96 break;
99 case WM_COMMAND:
100 if (HIWORD(wparam) != BN_CLICKED)
101 break;
103 switch (LOWORD(wparam))
105 case IDOK:
106 EndDialog(hdlg, 111);
107 break;
109 case IDCANCEL:
110 EndDialog(hdlg, 222);
111 break;
113 default:
114 break;
116 break;
118 case WM_USER:
120 int len;
121 HWND hok = GetDlgItem(hdlg, IDOK);
122 HWND hedit = GetDlgItem(hdlg, 1000);
124 if (wparam != 0xdeadbeef)
125 break;
127 switch (lparam)
129 case 0:
130 len = SendMessage(hedit, WM_GETTEXTLENGTH, 0, 0);
131 if (len == 0)
132 EndDialog(hdlg, 444);
133 else
134 EndDialog(hdlg, 555);
135 break;
137 case 1:
138 len = SendMessage(hedit, WM_GETTEXTLENGTH, 0, 0);
139 if ((GetFocus() == hok) && len == 0)
140 EndDialog(hdlg, 444);
141 else
142 EndDialog(hdlg, 555);
143 break;
145 default:
146 EndDialog(hdlg, 555);
148 break;
151 case WM_CLOSE:
152 EndDialog(hdlg, 333);
153 break;
155 default:
156 break;
159 return FALSE;
162 static HINSTANCE hinst;
163 static HWND hwndET2;
164 static const char szEditTest2Class[] = "EditTest2Class";
165 static const char szEditTest3Class[] = "EditTest3Class";
166 static const char szEditTextPositionClass[] = "EditTextPositionWindowClass";
168 static HWND create_editcontrol (DWORD style, DWORD exstyle)
170 HWND handle;
172 handle = CreateWindowEx(exstyle,
173 "EDIT",
174 "Test Text",
175 style,
176 10, 10, 300, 300,
177 NULL, NULL, hinst, NULL);
178 assert (handle);
179 if (winetest_interactive)
180 ShowWindow (handle, SW_SHOW);
181 return handle;
184 static HWND create_child_editcontrol (DWORD style, DWORD exstyle)
186 HWND parentWnd;
187 HWND editWnd;
188 RECT rect;
190 rect.left = 0;
191 rect.top = 0;
192 rect.right = 300;
193 rect.bottom = 300;
194 assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
196 parentWnd = CreateWindowEx(0,
197 szEditTextPositionClass,
198 "Edit Test",
199 WS_OVERLAPPEDWINDOW,
200 CW_USEDEFAULT, CW_USEDEFAULT,
201 rect.right - rect.left, rect.bottom - rect.top,
202 NULL, NULL, hinst, NULL);
203 assert(parentWnd);
205 editWnd = CreateWindowEx(exstyle,
206 "EDIT",
207 "Test Text",
208 WS_CHILD | style,
209 0, 0, 300, 300,
210 parentWnd, NULL, hinst, NULL);
211 assert(editWnd);
212 if (winetest_interactive)
213 ShowWindow (parentWnd, SW_SHOW);
214 return editWnd;
217 static void destroy_child_editcontrol (HWND hwndEdit)
219 if (GetParent(hwndEdit))
220 DestroyWindow(GetParent(hwndEdit));
221 else {
222 trace("Edit control has no parent!\n");
223 DestroyWindow(hwndEdit);
227 static LONG get_edit_style (HWND hwnd)
229 return GetWindowLongA( hwnd, GWL_STYLE ) & (
230 ES_LEFT |
231 /* FIXME: not implemented
232 ES_CENTER |
233 ES_RIGHT |
234 ES_OEMCONVERT |
236 ES_MULTILINE |
237 ES_UPPERCASE |
238 ES_LOWERCASE |
239 ES_PASSWORD |
240 ES_AUTOVSCROLL |
241 ES_AUTOHSCROLL |
242 ES_NOHIDESEL |
243 ES_COMBO |
244 ES_READONLY |
245 ES_WANTRETURN |
246 ES_NUMBER
250 static void set_client_height(HWND Wnd, unsigned Height)
252 RECT ClientRect, WindowRect;
254 GetWindowRect(Wnd, &WindowRect);
255 GetClientRect(Wnd, &ClientRect);
256 SetWindowPos(Wnd, NULL, 0, 0,
257 WindowRect.right - WindowRect.left,
258 Height + (WindowRect.bottom - WindowRect.top) -
259 (ClientRect.bottom - ClientRect.top),
260 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
262 /* Workaround for a bug in Windows' edit control
263 (multi-line mode) */
264 GetWindowRect(Wnd, &WindowRect);
265 SetWindowPos(Wnd, NULL, 0, 0,
266 WindowRect.right - WindowRect.left + 1,
267 WindowRect.bottom - WindowRect.top + 1,
268 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
269 SetWindowPos(Wnd, NULL, 0, 0,
270 WindowRect.right - WindowRect.left,
271 WindowRect.bottom - WindowRect.top,
272 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
274 GetClientRect(Wnd, &ClientRect);
275 ok(ClientRect.bottom - ClientRect.top == Height,
276 "The client height should be %ld, but is %ld\n",
277 (long)Height, (long)(ClientRect.bottom - ClientRect.top));
280 static void test_edit_control_1(void)
282 HWND hwEdit;
283 MSG msMessage;
284 int i;
285 LONG r;
287 msMessage.message = WM_KEYDOWN;
289 trace("EDIT: Single line\n");
290 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
291 r = get_edit_style(hwEdit);
292 ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%x\n", r);
293 for (i=0;i<65535;i++)
295 msMessage.wParam = i;
296 r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
297 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
298 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r);
300 DestroyWindow (hwEdit);
302 trace("EDIT: Single line want returns\n");
303 hwEdit = create_editcontrol(ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
304 r = get_edit_style(hwEdit);
305 ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%x\n", r);
306 for (i=0;i<65535;i++)
308 msMessage.wParam = i;
309 r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
310 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
311 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r);
313 DestroyWindow (hwEdit);
315 trace("EDIT: Multiline line\n");
316 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
317 r = get_edit_style(hwEdit);
318 ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%x\n", r);
319 for (i=0;i<65535;i++)
321 msMessage.wParam = i;
322 r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
323 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
324 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r);
326 DestroyWindow (hwEdit);
328 trace("EDIT: Multi line want returns\n");
329 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
330 r = get_edit_style(hwEdit);
331 ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%x\n", r);
332 for (i=0;i<65535;i++)
334 msMessage.wParam = i;
335 r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
336 ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
337 "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r);
339 DestroyWindow (hwEdit);
342 /* WM_SETTEXT is implemented by selecting all text, and then replacing the
343 * selection. This test checks that the first 'select all' doesn't generate
344 * an UPDATE message which can escape and (via a handler) change the
345 * selection, which would cause WM_SETTEXT to break. This old bug
346 * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
348 static void test_edit_control_2(void)
350 HWND hwndMain;
351 char szLocalString[MAXLEN];
353 /* Create main and edit windows. */
354 hwndMain = CreateWindow(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW,
355 0, 0, 200, 200, NULL, NULL, hinst, NULL);
356 assert(hwndMain);
357 if (winetest_interactive)
358 ShowWindow (hwndMain, SW_SHOW);
360 hwndET2 = CreateWindow("EDIT", NULL,
361 WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
362 0, 0, 150, 50, /* important this not be 0 size. */
363 hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
364 assert(hwndET2);
365 if (winetest_interactive)
366 ShowWindow (hwndET2, SW_SHOW);
368 trace("EDIT: SETTEXT atomicity\n");
369 /* Send messages to "type" in the word 'foo'. */
370 SendMessage(hwndET2, WM_CHAR, 'f', 1);
371 SendMessage(hwndET2, WM_CHAR, 'o', 1);
372 SendMessage(hwndET2, WM_CHAR, 'o', 1);
373 /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
374 GetWindowText(hwndET2, szLocalString, MAXLEN);
375 ok(lstrcmp(szLocalString, "bar")==0,
376 "Wrong contents of edit: %s\n", szLocalString);
378 /* OK, done! */
379 DestroyWindow (hwndET2);
380 DestroyWindow (hwndMain);
383 static void ET2_check_change(void) {
384 char szLocalString[MAXLEN];
385 /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
386 GetWindowText(hwndET2, szLocalString, MAXLEN);
387 if (lstrcmp(szLocalString, "foo")==0) {
388 lstrcpy(szLocalString, "bar");
389 SendMessage(hwndET2, WM_SETTEXT, 0, (LPARAM) szLocalString);
391 /* always leave the cursor at the end. */
392 SendMessage(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
394 static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
396 if (id==ID_EDITTEST2 && codeNotify == EN_UPDATE)
397 ET2_check_change();
399 static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
401 switch (iMsg) {
402 case WM_COMMAND:
403 ET2_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
404 break;
406 return DefWindowProc(hwnd, iMsg, wParam, lParam);
409 static void zero_notify(void)
411 notifications.en_change = 0;
412 notifications.en_maxtext = 0;
413 notifications.en_update = 0;
416 #define test_notify(enchange, enmaxtext, enupdate) \
417 ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
418 "got %d\n", enchange, notifications.en_change); \
419 ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
420 "got %d\n", enmaxtext, notifications.en_maxtext); \
421 ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
422 "got %d\n", enupdate, notifications.en_update)
425 static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
427 switch (msg) {
428 case WM_COMMAND:
429 switch (HIWORD(wParam)) {
430 case EN_MAXTEXT:
431 notifications.en_maxtext++;
432 break;
433 case EN_UPDATE:
434 notifications.en_update++;
435 break;
436 case EN_CHANGE:
437 notifications.en_change++;
438 break;
440 break;
442 return DefWindowProcA(hWnd, msg, wParam, lParam);
445 /* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notificatisons sent in response
446 * to these messages.
448 static void test_edit_control_3(void)
450 HWND hWnd;
451 HWND hParent;
452 int len;
453 static const char *str = "this is a long string.";
454 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.";
456 trace("EDIT: Test notifications\n");
458 hParent = CreateWindowExA(0,
459 szEditTest3Class,
460 NULL,
462 CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
463 NULL, NULL, NULL, NULL);
464 assert(hParent);
466 trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
467 hWnd = CreateWindowExA(0,
468 "EDIT",
469 NULL,
471 10, 10, 50, 50,
472 hParent, NULL, NULL, NULL);
473 assert(hWnd);
475 zero_notify();
476 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
477 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
478 ok(lstrlenA(str) > len, "text should have been truncated\n");
479 test_notify(1, 1, 1);
481 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
482 zero_notify();
483 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
484 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
485 ok(1 == len, "wrong text length, expected 1, got %d\n", len);
486 test_notify(1, 0, 1);
488 zero_notify();
489 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
490 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
491 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
492 test_notify(1, 0, 1);
494 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
496 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
497 zero_notify();
498 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
499 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
500 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
501 test_notify(1, 1, 1);
503 zero_notify();
504 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
505 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
506 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
507 test_notify(1, 0, 1);
509 DestroyWindow(hWnd);
511 trace("EDIT: Single line, ES_AUTOHSCROLL\n");
512 hWnd = CreateWindowExA(0,
513 "EDIT",
514 NULL,
515 ES_AUTOHSCROLL,
516 10, 10, 50, 50,
517 hParent, NULL, NULL, NULL);
518 assert(hWnd);
520 zero_notify();
521 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
522 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
523 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
524 test_notify(1, 0, 1);
526 zero_notify();
527 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
528 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
529 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
530 test_notify(1, 0, 1);
532 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
534 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
535 zero_notify();
536 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
537 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
538 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
539 test_notify(1, 1, 1);
541 zero_notify();
542 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
543 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
544 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
545 test_notify(1, 0, 1);
547 DestroyWindow(hWnd);
549 trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
550 hWnd = CreateWindowExA(0,
551 "EDIT",
552 NULL,
553 ES_MULTILINE,
554 10, 10, 50, 50,
555 hParent, NULL, NULL, NULL);
556 assert(hWnd);
558 zero_notify();
559 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
560 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
561 ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
562 test_notify(1, 1, 1);
564 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
565 zero_notify();
566 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
567 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
568 ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
569 test_notify(1, 0, 1);
571 zero_notify();
572 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
573 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
574 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
575 test_notify(0, 0, 0);
577 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
579 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
580 zero_notify();
581 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
582 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
583 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
584 test_notify(1, 1, 1);
586 zero_notify();
587 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
588 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
589 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
590 test_notify(0, 0, 0);
592 DestroyWindow(hWnd);
594 trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
595 hWnd = CreateWindowExA(0,
596 "EDIT",
597 NULL,
598 ES_MULTILINE | ES_AUTOHSCROLL,
599 10, 10, 50, 50,
600 hParent, NULL, NULL, NULL);
601 assert(hWnd);
603 zero_notify();
604 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
605 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
606 ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
607 test_notify(1, 1, 1);
609 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
610 zero_notify();
611 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
612 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
613 ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
614 test_notify(1, 0, 1);
616 zero_notify();
617 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
618 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
619 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
620 test_notify(0, 0, 0);
622 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
624 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
625 zero_notify();
626 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
627 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
628 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
629 test_notify(1, 1, 1);
631 zero_notify();
632 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
633 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
634 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
635 test_notify(0, 0, 0);
637 DestroyWindow(hWnd);
639 trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
640 hWnd = CreateWindowExA(0,
641 "EDIT",
642 NULL,
643 ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
644 10, 10, 50, 50,
645 hParent, NULL, NULL, NULL);
646 assert(hWnd);
648 zero_notify();
649 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
650 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
651 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
652 test_notify(1, 0, 1);
654 zero_notify();
655 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
656 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
657 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
658 test_notify(0, 0, 0);
660 SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
662 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
663 zero_notify();
664 SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
665 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
666 ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
667 test_notify(1, 1, 1);
669 zero_notify();
670 SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
671 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
672 ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
673 test_notify(0, 0, 0);
675 DestroyWindow(hWnd);
678 /* Test EM_CHARFROMPOS and EM_POSFROMCHAR
680 static void test_edit_control_4(void)
682 HWND hwEdit;
683 int lo, hi, mid;
684 int ret;
685 int i;
687 trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n");
688 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
689 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
690 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
691 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
692 mid = lo + (hi - lo) / 2;
694 for (i = lo; i < mid; i++) {
695 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
696 ok(0 == ret, "expected 0 got %d\n", ret);
698 for (i = mid; i <= hi; i++) {
699 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
700 ok(1 == ret, "expected 1 got %d\n", ret);
702 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
703 ok(-1 == ret, "expected -1 got %d\n", ret);
704 DestroyWindow(hwEdit);
706 hwEdit = create_editcontrol(ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
707 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
708 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
709 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
710 mid = lo + (hi - lo) / 2;
712 for (i = lo; i < mid; i++) {
713 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
714 ok(0 == ret, "expected 0 got %d\n", ret);
716 for (i = mid; i <= hi; i++) {
717 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
718 ok(1 == ret, "expected 1 got %d\n", ret);
720 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
721 ok(-1 == ret, "expected -1 got %d\n", ret);
722 DestroyWindow(hwEdit);
724 hwEdit = create_editcontrol(ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
725 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
726 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
727 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
728 mid = lo + (hi - lo) / 2;
730 for (i = lo; i < mid; i++) {
731 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
732 ok(0 == ret, "expected 0 got %d\n", ret);
734 for (i = mid; i <= hi; i++) {
735 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
736 ok(1 == ret, "expected 1 got %d\n", ret);
738 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
739 ok(-1 == ret, "expected -1 got %d\n", ret);
740 DestroyWindow(hwEdit);
742 hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
743 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
744 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
745 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
746 mid = lo + (hi - lo) / 2 +1;
748 for (i = lo; i < mid; i++) {
749 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
750 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
752 for (i = mid; i <= hi; i++) {
753 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
754 ok(1 == ret, "expected 1 got %d\n", ret);
756 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
757 ok(-1 == ret, "expected -1 got %d\n", ret);
758 DestroyWindow(hwEdit);
760 hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
761 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
762 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
763 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
764 mid = lo + (hi - lo) / 2 +1;
766 for (i = lo; i < mid; i++) {
767 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
768 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
770 for (i = mid; i <= hi; i++) {
771 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
772 ok(1 == ret, "expected 1 got %d\n", ret);
774 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
775 ok(-1 == ret, "expected -1 got %d\n", ret);
776 DestroyWindow(hwEdit);
778 hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
779 SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
780 lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
781 hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
782 mid = lo + (hi - lo) / 2 +1;
784 for (i = lo; i < mid; i++) {
785 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
786 ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
788 for (i = mid; i <= hi; i++) {
789 ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
790 ok(1 == ret, "expected 1 got %d\n", ret);
792 ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
793 ok(-1 == ret, "expected -1 got %d\n", ret);
794 DestroyWindow(hwEdit);
797 /* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL
798 * truncates text that doesn't fit.
800 static void test_edit_control_5(void)
802 static const char *str = "test\r\ntest";
803 HWND hWnd;
804 int len;
806 hWnd = CreateWindowEx(0,
807 "EDIT",
808 str,
810 10, 10, 1, 1,
811 NULL, NULL, NULL, NULL);
812 assert(hWnd);
814 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
815 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
816 DestroyWindow(hWnd);
818 hWnd = CreateWindowEx(0,
819 "EDIT",
820 str,
821 ES_MULTILINE,
822 10, 10, 1, 1,
823 NULL, NULL, NULL, NULL);
824 assert(hWnd);
826 len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
827 ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
828 DestroyWindow(hWnd);
831 static void test_edit_control_limittext(void)
833 HWND hwEdit;
834 DWORD r;
836 /* Test default limit for single-line control */
837 trace("EDIT: buffer limit for single-line\n");
838 hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
839 r = SendMessage(hwEdit, EM_GETLIMITTEXT, 0, 0);
840 ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r);
841 SendMessage(hwEdit, EM_SETLIMITTEXT, 0, 0);
842 r = SendMessage(hwEdit, EM_GETLIMITTEXT, 0, 0);
843 /* Win9x+ME: 32766; WinNT: 2147483646UL */
844 ok( (r == 32766) || (r == 2147483646UL),
845 "got limit %u (expected 32766 or 2147483646)\n", r);
846 DestroyWindow(hwEdit);
848 /* Test default limit for multi-line control */
849 trace("EDIT: buffer limit for multi-line\n");
850 hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
851 r = SendMessage(hwEdit, EM_GETLIMITTEXT, 0, 0);
852 ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r);
853 SendMessage(hwEdit, EM_SETLIMITTEXT, 0, 0);
854 r = SendMessage(hwEdit, EM_GETLIMITTEXT, 0, 0);
855 /* Win9x+ME: 65535; WinNT: 4294967295UL */
856 ok( (r == 65535) || (r == 4294967295UL),
857 "got limit %u (expected 65535 or 4294967295)\n", r);
858 DestroyWindow(hwEdit);
861 static void test_margins(void)
863 HWND hwEdit;
864 RECT old_rect, new_rect;
865 INT old_left_margin, old_right_margin;
866 DWORD old_margins, new_margins;
868 hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
870 old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
871 old_left_margin = LOWORD(old_margins);
872 old_right_margin = HIWORD(old_margins);
874 /* Check if setting the margins works */
876 SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
877 new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
878 ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
879 ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
881 SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
882 new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
883 ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
884 ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
887 /* The size of the rectangle must decrease if we increase the margin */
889 SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
890 SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
891 SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
892 SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
893 ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
894 ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
895 ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
896 ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
899 /* If we set the margin to same value as the current margin,
900 the rectangle must not change */
902 SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
903 old_rect.left = 1;
904 old_rect.right = 99;
905 old_rect.top = 1;
906 old_rect.bottom = 99;
907 SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);
908 SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
909 SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
910 SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
911 ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
912 ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
913 ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
914 ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
916 DestroyWindow (hwEdit);
919 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
921 return 0;
924 static void test_margins_font_change(void)
926 HWND hwEdit;
927 DWORD margins, font_margins;
928 LOGFONT lf;
929 HFONT hfont, hfont2;
930 HDC hdc = GetDC(0);
932 if(EnumFontFamiliesA(hdc, "Arial", find_font_proc, 0))
934 trace("Arial not found - skipping font change margin tests\n");
935 ReleaseDC(0, hdc);
936 return;
938 ReleaseDC(0, hdc);
940 hwEdit = create_child_editcontrol(0, 0);
942 SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
944 memset(&lf, 0, sizeof(lf));
945 strcpy(lf.lfFaceName, "Arial");
946 lf.lfHeight = 16;
947 lf.lfCharSet = DEFAULT_CHARSET;
948 hfont = CreateFontIndirectA(&lf);
949 lf.lfHeight = 30;
950 hfont2 = CreateFontIndirectA(&lf);
952 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
953 font_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
954 ok(LOWORD(font_margins) != 0, "got %d\n", LOWORD(font_margins));
955 ok(HIWORD(font_margins) != 0, "got %d\n", HIWORD(font_margins));
957 /* With 'small' edit controls, test that the margin doesn't get set */
958 SetWindowPos(hwEdit, NULL, 10, 10, 16, 100, SWP_NOZORDER | SWP_NOACTIVATE);
959 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0));
960 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
961 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
962 ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins));
963 ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
965 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
966 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
967 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
968 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
969 ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
971 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
972 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
973 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
974 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
975 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
977 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
978 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
979 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
980 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
981 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
982 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
983 ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
984 ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
986 /* Above a certain size threshold then the margin is updated */
987 SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
988 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
989 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
990 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
991 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
992 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
994 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
995 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
996 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
997 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
998 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
1000 SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
1001 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
1002 ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
1003 ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
1004 SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
1005 margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
1006 ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins));
1007 ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins));
1009 SendMessageA(hwEdit, WM_SETFONT, 0, 0);
1011 DeleteObject(hfont2);
1012 DeleteObject(hfont);
1013 destroy_child_editcontrol(hwEdit);
1017 #define edit_pos_ok(exp, got, txt) \
1018 ok(exp == got, "wrong " #txt " expected %d got %d\n", exp, got);
1020 #define check_pos(hwEdit, set_height, test_top, test_height, test_left) \
1021 do { \
1022 RECT format_rect; \
1023 int left_margin; \
1024 set_client_height(hwEdit, set_height); \
1025 SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
1026 left_margin = LOWORD(SendMessage(hwEdit, EM_GETMARGINS, 0, 0)); \
1027 edit_pos_ok(test_top, format_rect.top, vertical position); \
1028 edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \
1029 edit_pos_ok(test_left, format_rect.left - left_margin, left); \
1030 } while(0)
1032 static void test_text_position_style(DWORD style)
1034 HWND hwEdit;
1035 HFONT font, oldFont;
1036 HDC dc;
1037 TEXTMETRIC metrics;
1038 INT b, bm, b2, b3;
1039 BOOL single_line = !(style & ES_MULTILINE);
1041 b = GetSystemMetrics(SM_CYBORDER) + 1;
1042 b2 = 2 * b;
1043 b3 = 3 * b;
1044 bm = b2 - 1;
1046 /* Get a stock font for which we can determine the metrics */
1047 assert(font = GetStockObject(SYSTEM_FONT));
1048 assert(dc = GetDC(NULL));
1049 oldFont = SelectObject(dc, font);
1050 assert(GetTextMetrics(dc, &metrics));
1051 SelectObject(dc, oldFont);
1052 ReleaseDC(NULL, dc);
1054 /* Windows' edit control has some bugs in multi-line mode:
1055 * - Sometimes the format rectangle doesn't get updated
1056 * (see workaround in set_client_height())
1057 * - If the height of the control is smaller than the height of a text
1058 * line, the format rectangle is still as high as a text line
1059 * (higher than the client rectangle) and the caret is not shown
1062 /* Edit controls that are in a parent window */
1064 hwEdit = create_child_editcontrol(style | WS_VISIBLE, 0);
1065 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1066 if (single_line)
1067 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
1068 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
1069 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
1070 check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
1071 check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
1072 destroy_child_editcontrol(hwEdit);
1074 hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, 0);
1075 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1076 if (single_line)
1077 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
1078 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
1079 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
1080 check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
1081 check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
1082 check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
1083 destroy_child_editcontrol(hwEdit);
1085 hwEdit = create_child_editcontrol(style | WS_VISIBLE, WS_EX_CLIENTEDGE);
1086 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1087 if (single_line)
1088 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
1089 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
1090 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
1091 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
1092 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
1093 destroy_child_editcontrol(hwEdit);
1095 hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, WS_EX_CLIENTEDGE);
1096 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1097 if (single_line)
1098 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
1099 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
1100 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
1101 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
1102 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
1103 destroy_child_editcontrol(hwEdit);
1106 /* Edit controls that are popup windows */
1108 hwEdit = create_editcontrol(style | WS_POPUP, 0);
1109 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1110 if (single_line)
1111 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
1112 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
1113 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
1114 check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
1115 check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
1116 DestroyWindow(hwEdit);
1118 hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0);
1119 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1120 if (single_line)
1121 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
1122 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
1123 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
1124 check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
1125 check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
1126 check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
1127 DestroyWindow(hwEdit);
1129 hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE);
1130 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1131 if (single_line)
1132 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
1133 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
1134 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
1135 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
1136 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
1137 DestroyWindow(hwEdit);
1139 hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
1140 SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
1141 if (single_line)
1142 check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
1143 check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
1144 check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
1145 check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
1146 check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
1147 DestroyWindow(hwEdit);
1150 static void test_text_position(void)
1152 trace("EDIT: Text position (Single line)\n");
1153 test_text_position_style(ES_AUTOHSCROLL | ES_AUTOVSCROLL);
1154 trace("EDIT: Text position (Multi line)\n");
1155 test_text_position_style(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL);
1158 static void test_espassword(void)
1160 HWND hwEdit;
1161 LONG r;
1162 char buffer[1024];
1163 const char* password = "secret";
1165 hwEdit = create_editcontrol(ES_PASSWORD, 0);
1166 r = get_edit_style(hwEdit);
1167 ok(r == ES_PASSWORD, "Wrong style expected 0x%x got: 0x%x\n", ES_PASSWORD, r);
1168 /* set text */
1169 r = SendMessage(hwEdit , WM_SETTEXT, 0, (LPARAM) password);
1170 ok(r == TRUE, "Expected: %d, got: %d\n", TRUE, r);
1172 /* select all, cut (ctrl-x) */
1173 SendMessage(hwEdit, EM_SETSEL, 0, -1);
1174 SendMessage(hwEdit, WM_CHAR, 24, 0);
1176 /* get text */
1177 r = SendMessage(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1178 ok(r == strlen(password), "Expected: %s, got len %d\n", password, r);
1179 ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer);
1181 r = OpenClipboard(hwEdit);
1182 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
1183 r = EmptyClipboard();
1184 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
1185 r = CloseClipboard();
1186 ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
1188 /* select all, copy (ctrl-c) and paste (ctrl-v) */
1189 SendMessage(hwEdit, EM_SETSEL, 0, -1);
1190 SendMessage(hwEdit, WM_CHAR, 3, 0);
1191 SendMessage(hwEdit, WM_CHAR, 22, 0);
1193 /* get text */
1194 buffer[0] = 0;
1195 r = SendMessage(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1196 ok(r == 0, "Expected: 0, got: %d\n", r);
1197 ok(strcmp(buffer, "") == 0, "expected empty string, got %s\n", buffer);
1199 DestroyWindow (hwEdit);
1202 static void test_undo(void)
1204 HWND hwEdit;
1205 LONG r;
1206 DWORD cpMin, cpMax;
1207 char buffer[1024];
1208 const char* text = "undo this";
1210 hwEdit = create_editcontrol(0, 0);
1211 r = get_edit_style(hwEdit);
1212 ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r);
1214 /* set text */
1215 r = SendMessage(hwEdit , WM_SETTEXT, 0, (LPARAM) text);
1216 ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
1218 /* select all, */
1219 cpMin = cpMax = 0xdeadbeef;
1220 SendMessage(hwEdit, EM_SETSEL, 0, -1);
1221 r = SendMessage(hwEdit, EM_GETSEL, (WPARAM) &cpMin, (LPARAM) &cpMax);
1222 ok((strlen(text) << 16) == r, "Unexpected length %d\n", r);
1223 ok(0 == cpMin, "Expected: %d, got %d\n", 0, cpMin);
1224 ok(9 == cpMax, "Expected: %d, got %d\n", 9, cpMax);
1226 /* cut (ctrl-x) */
1227 r = SendMessage(hwEdit, WM_CHAR, 24, 0);
1228 todo_wine { ok(1 == r, "Expected: %d, got: %d\n", 1, r); }
1230 /* get text */
1231 buffer[0] = 0;
1232 r = SendMessage(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1233 ok(0 == r, "Expected: %d, got len %d\n", 0, r);
1234 ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
1236 /* undo (ctrl-z) */
1237 r = SendMessage(hwEdit, WM_CHAR, 26, 0);
1238 todo_wine { ok(1 == r, "Expected: %d, got: %d\n", 1, r); }
1240 /* get text */
1241 buffer[0] = 0;
1242 r = SendMessage(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1243 ok(strlen(text) == r, "Unexpected length %d\n", r);
1244 ok(0 == strcmp(buffer, text), "expected %s, got %s\n", text, buffer);
1246 /* undo again (ctrl-z) */
1247 r = SendMessage(hwEdit, WM_CHAR, 26, 0);
1248 todo_wine { ok(1 == r, "Expected: %d, got: %d\n", 1, r); }
1250 /* get text */
1251 buffer[0] = 0;
1252 r = SendMessage(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1253 ok(r == 0, "Expected: %d, got len %d\n", 0, r);
1254 ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
1256 DestroyWindow (hwEdit);
1259 static void test_edit_dialog(void)
1261 int r;
1263 /* from bug 11841 */
1264 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 0);
1265 ok(333 == r, "Expected %d, got %d\n", 333, r);
1266 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 1);
1267 ok(111 == r, "Expected %d, got %d\n", 111, r);
1268 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 2);
1269 ok(444 == r, "Expected %d, got %d\n", 444, r);
1271 /* more tests for WM_CHAR */
1272 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 3);
1273 ok(444 == r, "Expected %d, got %d\n", 444, r);
1274 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 4);
1275 ok(444 == r, "Expected %d, got %d\n", 444, r);
1276 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 5);
1277 ok(444 == r, "Expected %d, got %d\n", 444, r);
1279 /* more tests for WM_KEYDOWN + WM_CHAR */
1280 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 6);
1281 todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r);
1282 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 7);
1283 todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r);
1284 r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 8);
1285 ok(444 == r, "Expected %d, got %d\n", 444, r);
1287 /* tests with an editable edit control */
1288 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 0);
1289 ok(333 == r, "Expected %d, got %d\n", 333, r);
1290 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 1);
1291 ok(111 == r, "Expected %d, got %d\n", 111, r);
1292 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 2);
1293 ok(444 == r, "Expected %d, got %d\n", 444, r);
1295 /* tests for WM_CHAR */
1296 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 3);
1297 ok(444 == r, "Expected %d, got %d\n", 444, r);
1298 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 4);
1299 ok(444 == r, "Expected %d, got %d\n", 444, r);
1300 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 5);
1301 ok(444 == r, "Expected %d, got %d\n", 444, r);
1303 /* tests for WM_KEYDOWN + WM_CHAR */
1304 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 6);
1305 todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r);
1306 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 7);
1307 todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r);
1308 r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 8);
1309 ok(444 == r, "Expected %d, got %d\n", 444, r);
1312 static BOOL RegisterWindowClasses (void)
1314 WNDCLASSA test2;
1315 WNDCLASSA test3;
1316 WNDCLASSA text_position;
1318 test2.style = 0;
1319 test2.lpfnWndProc = ET2_WndProc;
1320 test2.cbClsExtra = 0;
1321 test2.cbWndExtra = 0;
1322 test2.hInstance = hinst;
1323 test2.hIcon = NULL;
1324 test2.hCursor = LoadCursorA (NULL, IDC_ARROW);
1325 test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1326 test2.lpszMenuName = NULL;
1327 test2.lpszClassName = szEditTest2Class;
1328 if (!RegisterClassA(&test2)) return FALSE;
1330 test3.style = 0;
1331 test3.lpfnWndProc = edit3_wnd_procA;
1332 test3.cbClsExtra = 0;
1333 test3.cbWndExtra = 0;
1334 test3.hInstance = hinst;
1335 test3.hIcon = 0;
1336 test3.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1337 test3.hbrBackground = GetStockObject(WHITE_BRUSH);
1338 test3.lpszMenuName = NULL;
1339 test3.lpszClassName = szEditTest3Class;
1340 if (!RegisterClassA(&test3)) return FALSE;
1342 text_position.style = CS_HREDRAW | CS_VREDRAW;
1343 text_position.cbClsExtra = 0;
1344 text_position.cbWndExtra = 0;
1345 text_position.hInstance = hinst;
1346 text_position.hIcon = NULL;
1347 text_position.hCursor = LoadCursorA(NULL, IDC_ARROW);
1348 text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1349 text_position.lpszMenuName = NULL;
1350 text_position.lpszClassName = szEditTextPositionClass;
1351 text_position.lpfnWndProc = DefWindowProc;
1352 if (!RegisterClassA(&text_position)) return FALSE;
1354 return TRUE;
1357 static void UnregisterWindowClasses (void)
1359 UnregisterClassA(szEditTest2Class, hinst);
1360 UnregisterClassA(szEditTest3Class, hinst);
1361 UnregisterClassA(szEditTextPositionClass, hinst);
1364 START_TEST(edit)
1366 hinst = GetModuleHandleA(NULL);
1367 assert(RegisterWindowClasses());
1369 test_edit_control_1();
1370 test_edit_control_2();
1371 test_edit_control_3();
1372 test_edit_control_4();
1373 test_edit_control_5();
1374 test_edit_control_limittext();
1375 test_margins();
1376 test_margins_font_change();
1377 test_text_position();
1378 test_espassword();
1379 test_undo();
1380 test_edit_dialog();
1382 UnregisterWindowClasses();