2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include <wine/test.h>
35 static HMODULE hmoduleRichEdit;
37 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
39 hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
40 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
41 hmoduleRichEdit, NULL);
42 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
46 static HWND new_richedit(HWND parent) {
47 return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
50 static const char haystack[] = "WINEWine wineWine wine WineWine";
63 struct find_s find_tests[] = {
64 /* Find in empty text */
65 {0, -1, "foo", FR_DOWN, -1, 0},
66 {0, -1, "foo", 0, -1, 0},
67 {0, -1, "", FR_DOWN, -1, 0},
68 {20, 5, "foo", FR_DOWN, -1, 0},
69 {5, 20, "foo", FR_DOWN, -1, 0}
72 struct find_s find_tests2[] = {
74 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
75 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
77 /* Subsequent finds */
78 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
79 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
80 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
81 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
84 {19, 20, "Wine", FR_MATCHCASE, 13, 0},
85 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
86 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
88 /* Case-insensitive */
89 {1, 31, "wInE", FR_DOWN, 4, 0},
90 {1, 31, "Wine", FR_DOWN, 4, 0},
92 /* High-to-low ranges */
93 {20, 5, "Wine", FR_DOWN, -1, 0},
94 {2, 1, "Wine", FR_DOWN, -1, 0},
95 {30, 29, "Wine", FR_DOWN, -1, 0},
96 {20, 5, "Wine", 0, 13, 0},
99 {5, 10, "", FR_DOWN, -1, 0},
100 {10, 5, "", FR_DOWN, -1, 0},
101 {0, -1, "", FR_DOWN, -1, 0},
102 {10, 5, "", 0, -1, 0},
104 /* Whole-word search */
105 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
106 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
107 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
108 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
109 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
110 {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
111 {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
114 {5, 200, "XXX", FR_DOWN, -1, 0},
115 {-20, 20, "Wine", FR_DOWN, -1, 0},
116 {-20, 20, "Wine", FR_DOWN, -1, 0},
117 {-15, -20, "Wine", FR_DOWN, -1, 0},
118 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
120 /* Check the case noted in bug 4479 where matches at end aren't recognized */
121 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
122 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
123 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
124 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
125 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
127 /* The backwards case of bug 4479; bounds look right
128 * Fails because backward find is wrong */
129 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
130 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
133 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
136 memset(&ft, 0, sizeof(ft));
137 ft.chrg.cpMin = f->start;
138 ft.chrg.cpMax = f->end;
139 ft.lpstrText = f->needle;
140 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
141 ok(findloc == f->expected_loc,
142 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
143 name, id, f->needle, f->start, f->end, f->flags, findloc);
146 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
150 memset(&ft, 0, sizeof(ft));
151 ft.chrg.cpMin = f->start;
152 ft.chrg.cpMax = f->end;
153 ft.lpstrText = f->needle;
154 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
155 ok(findloc == f->expected_loc,
156 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
157 name, id, f->needle, f->start, f->end, f->flags, findloc);
158 ok(ft.chrgText.cpMin == f->expected_loc,
159 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
160 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
161 ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
162 : f->expected_loc + strlen(f->needle)),
163 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d\n",
164 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
167 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
172 for (i = 0; i < num_tests; i++) {
173 if (find[i]._todo_wine) {
175 check_EM_FINDTEXT(hwnd, name, &find[i], i);
176 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
179 check_EM_FINDTEXT(hwnd, name, &find[i], i);
180 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
185 static void test_EM_FINDTEXT(void)
187 HWND hwndRichEdit = new_richedit(NULL);
189 /* Empty rich edit control */
190 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
191 sizeof(find_tests)/sizeof(struct find_s));
193 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
196 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
197 sizeof(find_tests2)/sizeof(struct find_s));
199 DestroyWindow(hwndRichEdit);
202 static const struct getline_s {
207 {0, 10, "foo bar\r"},
212 /* Buffer smaller than line length */
218 static void test_EM_GETLINE(void)
221 HWND hwndRichEdit = new_richedit(NULL);
222 static const int nBuf = 1024;
223 char dest[1024], origdest[1024];
224 const char text[] = "foo bar\n"
228 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
230 memset(origdest, 0xBB, nBuf);
231 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
234 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
235 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
236 memset(dest, 0xBB, nBuf);
237 *(WORD *) dest = gl[i].buffer_len;
239 /* EM_GETLINE appends a "\r\0" to the end of the line
240 * nCopied counts up to and including the '\r' */
241 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
242 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
244 /* two special cases since a parameter is passed via dest */
245 if (gl[i].buffer_len == 0)
246 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
248 else if (gl[i].buffer_len == 1)
249 ok(dest[0] == gl[i].text[0] && !dest[1] &&
250 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
253 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
254 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
255 ok(!strncmp(dest + expected_bytes_written, origdest
256 + expected_bytes_written, nBuf - expected_bytes_written),
257 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
261 DestroyWindow(hwndRichEdit);
264 static void test_EM_LINELENGTH(void)
266 HWND hwndRichEdit = new_richedit(NULL);
272 int offset_test[10][2] = {
287 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
289 for (i = 0; i < 10; i++) {
290 result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
291 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
292 offset_test[i][0], result, offset_test[i][1]);
295 DestroyWindow(hwndRichEdit);
298 static int get_scroll_pos_y(HWND hwnd)
301 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
302 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
306 static void move_cursor(HWND hwnd, long charindex)
309 cr.cpMax = charindex;
310 cr.cpMin = charindex;
311 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
314 static void line_scroll(HWND hwnd, int amount)
316 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
319 static void test_EM_SCROLLCARET(void)
322 HWND hwndRichEdit = new_richedit(NULL);
323 const char text[] = "aa\n"
324 "this is a long line of text that should be longer than the "
333 /* Can't verify this */
334 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
336 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
338 /* Caret above visible window */
339 line_scroll(hwndRichEdit, 3);
340 prevY = get_scroll_pos_y(hwndRichEdit);
341 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
342 curY = get_scroll_pos_y(hwndRichEdit);
343 ok(prevY != curY, "%d == %d\n", prevY, curY);
345 /* Caret below visible window */
346 move_cursor(hwndRichEdit, sizeof(text) - 1);
347 line_scroll(hwndRichEdit, -3);
348 prevY = get_scroll_pos_y(hwndRichEdit);
349 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
350 curY = get_scroll_pos_y(hwndRichEdit);
351 ok(prevY != curY, "%d == %d\n", prevY, curY);
353 /* Caret in visible window */
354 move_cursor(hwndRichEdit, sizeof(text) - 2);
355 prevY = get_scroll_pos_y(hwndRichEdit);
356 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
357 curY = get_scroll_pos_y(hwndRichEdit);
358 ok(prevY == curY, "%d != %d\n", prevY, curY);
360 /* Caret still in visible window */
361 line_scroll(hwndRichEdit, -1);
362 prevY = get_scroll_pos_y(hwndRichEdit);
363 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
364 curY = get_scroll_pos_y(hwndRichEdit);
365 ok(prevY == curY, "%d != %d\n", prevY, curY);
367 DestroyWindow(hwndRichEdit);
370 static void test_EM_SETCHARFORMAT(void)
372 HWND hwndRichEdit = new_richedit(NULL);
376 /* Invalid flags, CHARFORMAT2 structure blanked out */
377 memset(&cf2, 0, sizeof(cf2));
378 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
380 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
382 /* A valid flag, CHARFORMAT2 structure blanked out */
383 memset(&cf2, 0, sizeof(cf2));
384 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
386 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
388 /* A valid flag, CHARFORMAT2 structure blanked out */
389 memset(&cf2, 0, sizeof(cf2));
390 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
392 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
394 /* A valid flag, CHARFORMAT2 structure blanked out */
395 memset(&cf2, 0, sizeof(cf2));
396 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
398 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
400 /* A valid flag, CHARFORMAT2 structure blanked out */
401 memset(&cf2, 0, sizeof(cf2));
402 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
404 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
406 /* Invalid flags, CHARFORMAT2 structure minimally filled */
407 memset(&cf2, 0, sizeof(cf2));
408 cf2.cbSize = sizeof(CHARFORMAT2);
409 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
411 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
413 /* A valid flag, CHARFORMAT2 structure minimally filled */
414 memset(&cf2, 0, sizeof(cf2));
415 cf2.cbSize = sizeof(CHARFORMAT2);
416 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
418 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
420 /* A valid flag, CHARFORMAT2 structure minimally filled */
421 memset(&cf2, 0, sizeof(cf2));
422 cf2.cbSize = sizeof(CHARFORMAT2);
423 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
425 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
427 /* A valid flag, CHARFORMAT2 structure minimally filled */
428 memset(&cf2, 0, sizeof(cf2));
429 cf2.cbSize = sizeof(CHARFORMAT2);
430 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
432 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
434 /* A valid flag, CHARFORMAT2 structure minimally filled */
435 memset(&cf2, 0, sizeof(cf2));
436 cf2.cbSize = sizeof(CHARFORMAT2);
437 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
439 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
441 DestroyWindow(hwndRichEdit);
444 static void test_EM_SETTEXTMODE(void)
446 HWND hwndRichEdit = new_richedit(NULL);
447 CHARFORMAT2 cf2, cf2test;
451 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
452 /*Insert text into the control*/
454 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
456 /*Attempt to change the control to plain text mode*/
457 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
458 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
460 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
461 If rich text is pasted, it should have the same formatting as the rest
462 of the text in the control*/
465 *NOTE: If the default text was already italicized, the test will simply
466 reverse; in other words, it will copy a regular "wine" into a plain
467 text window that uses an italicized format*/
468 cf2.cbSize = sizeof(CHARFORMAT2);
469 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
472 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
473 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
475 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
476 however, SCF_ALL has been implemented*/
477 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
478 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
479 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
481 /*Select the string "wine"*/
484 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
486 /*Copy the italicized "wine" to the clipboard*/
487 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
489 /*Reset the formatting to default*/
490 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
491 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
492 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
494 /*Clear the text in the control*/
495 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
497 /*Switch to Plain Text Mode*/
498 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
499 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
501 /*Input "wine" again in normal format*/
502 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
504 /*Paste the italicized "wine" into the control*/
505 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
507 /*Select a character from the first "wine" string*/
510 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
512 /*Retrieve its formatting*/
513 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
516 /*Select a character from the second "wine" string*/
519 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
521 /*Retrieve its formatting*/
522 cf2test.cbSize = sizeof(CHARFORMAT2);
523 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
526 /*Compare the two formattings*/
527 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
528 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
529 cf2.dwEffects, cf2test.dwEffects);
530 /*Test TM_RICHTEXT by: switching back to Rich Text mode
531 printing "wine" in the current format(normal)
532 pasting "wine" from the clipboard(italicized)
533 comparing the two formats(should differ)*/
535 /*Attempt to switch with text in control*/
536 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
537 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
540 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
542 /*Switch into Rich Text mode*/
543 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
544 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
546 /*Print "wine" in normal formatting into the control*/
547 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
549 /*Paste italicized "wine" into the control*/
550 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
552 /*Select text from the first "wine" string*/
555 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
557 /*Retrieve its formatting*/
558 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
561 /*Select text from the second "wine" string*/
564 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
566 /*Retrieve its formatting*/
567 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
570 /*Test that the two formattings are not the same*/
571 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
572 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
573 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
575 DestroyWindow(hwndRichEdit);
578 static void test_TM_PLAINTEXT(void)
580 /*Tests plain text properties*/
582 HWND hwndRichEdit = new_richedit(NULL);
583 CHARFORMAT2 cf2, cf2test;
587 /*Switch to plain text mode*/
589 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
590 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
592 /*Fill control with text*/
594 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
596 /*Select some text and bold it*/
600 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
601 cf2.cbSize = sizeof(CHARFORMAT2);
602 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
605 cf2.dwMask = CFM_BOLD | cf2.dwMask;
606 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
608 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
609 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
611 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD | SCF_SELECTION, (LPARAM) &cf2);
612 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
614 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM)&cf2);
615 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
617 /*Get the formatting of those characters*/
619 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
621 /*Get the formatting of some other characters*/
622 cf2test.cbSize = sizeof(CHARFORMAT2);
625 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
626 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
628 /*Test that they are the same as plain text allows only one formatting*/
630 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
631 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
632 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
634 /*Fill the control with a "wine" string, which when inserted will be bold*/
636 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
638 /*Copy the bolded "wine" string*/
642 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
643 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
645 /*Swap back to rich text*/
647 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
648 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
650 /*Set the default formatting to bold italics*/
652 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
653 cf2.dwMask |= CFM_ITALIC;
654 cf2.dwEffects ^= CFE_ITALIC;
655 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
656 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
658 /*Set the text in the control to "wine", which will be bold and italicized*/
660 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
662 /*Paste the plain text "wine" string, which should take the insert
663 formatting, which at the moment is bold italics*/
665 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
667 /*Select the first "wine" string and retrieve its formatting*/
671 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
672 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
674 /*Select the second "wine" string and retrieve its formatting*/
678 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
679 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
681 /*Compare the two formattings. They should be the same.*/
683 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
684 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
685 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
686 DestroyWindow(hwndRichEdit);
689 static void test_WM_GETTEXT(void)
691 HWND hwndRichEdit = new_richedit(NULL);
692 static const char text[] = "Hello. My name is RichEdit!";
693 static const char text2[] = "Hello. My name is RichEdit!\r";
694 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
695 char buffer[1024] = {0};
698 /* Baseline test with normal-sized buffer */
699 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
700 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
701 ok(result == lstrlen(buffer),
702 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
703 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
704 result = strcmp(buffer,text);
706 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
708 /* Test for returned value of WM_GETTEXTLENGTH */
709 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
710 ok(result == lstrlen(text),
711 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
712 result, lstrlen(text));
714 /* Test for behavior in overflow case */
715 memset(buffer, 0, 1024);
716 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
718 result == lstrlenA(text) - 1, /* XP, win2k3 */
719 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
720 result = strcmp(buffer,text);
722 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
724 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
726 /* Baseline test with normal-sized buffer and carriage return */
727 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
728 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
729 ok(result == lstrlen(buffer),
730 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
731 result = strcmp(buffer,text2_after);
733 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
735 /* Test for returned value of WM_GETTEXTLENGTH */
736 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
737 ok(result == lstrlen(text2_after),
738 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
739 result, lstrlen(text2_after));
741 /* Test for behavior of CRLF conversion in case of overflow */
742 memset(buffer, 0, 1024);
743 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
745 result == lstrlenA(text2) - 1, /* XP, win2k3 */
746 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
747 result = strcmp(buffer,text2);
749 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
751 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
753 DestroyWindow(hwndRichEdit);
756 /* FIXME: need to test unimplemented options and robustly test wparam */
757 static void test_EM_SETOPTIONS(void)
759 HWND hwndRichEdit = new_richedit(NULL);
760 static const char text[] = "Hello. My name is RichEdit!";
761 char buffer[1024] = {0};
763 /* NEGATIVE TESTING - NO OPTIONS SET */
764 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
765 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
767 /* testing no readonly by sending 'a' to the control*/
768 SetFocus(hwndRichEdit);
769 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
770 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
772 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
773 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
775 /* READONLY - sending 'a' to the control */
776 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
777 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
778 SetFocus(hwndRichEdit);
779 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
780 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
781 ok(buffer[0]==text[0],
782 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
784 DestroyWindow(hwndRichEdit);
787 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url, const char * url)
789 CHARFORMAT2W text_format;
790 int link_present = 0;
791 text_format.cbSize = sizeof(text_format);
792 SendMessage(hwnd, EM_SETSEL, 0, 1);
793 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
794 link_present = text_format.dwEffects & CFE_LINK;
796 { /* control text is url; should get CFE_LINK */
797 ok(0 != link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
801 ok(0 == link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
805 static HWND new_static_wnd(HWND parent) {
806 return new_window("Static", 0, parent);
809 static void test_EM_AUTOURLDETECT(void)
816 {"http://www.winehq.org", 1},
817 {"http//winehq.org", 0},
818 {"ww.winehq.org", 0},
819 {"www.winehq.org", 1},
820 {"ftp://192.168.1.1", 1},
821 {"ftp//192.168.1.1", 0},
822 {"mailto:your@email.com", 1},
823 {"prospero:prosperoserver", 1},
825 {"news:newserver", 1},
826 {"wais:waisserver", 1}
831 HWND hwndRichEdit, parent;
833 parent = new_static_wnd(NULL);
834 hwndRichEdit = new_richedit(parent);
835 /* Try and pass EM_AUTOURLDETECT some test wParam values */
836 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
837 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
838 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
839 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
840 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
841 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
842 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
843 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
844 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
845 /* for each url, check the text to see if CFE_LINK effect is present */
846 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
847 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
848 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
849 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
850 check_CFE_LINK_rcvd(hwndRichEdit, 0, urls[i].text);
851 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
852 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
853 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
854 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
856 DestroyWindow(hwndRichEdit);
857 DestroyWindow(parent);
860 static void test_EM_SCROLL(void)
863 int r; /* return value */
864 int expr; /* expected return value */
865 HWND hwndRichEdit = new_richedit(NULL);
866 int y_before, y_after; /* units of lines of text */
868 /* test a richedit box containing a single line of text */
869 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
871 for (i = 0; i < 4; i++) {
872 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
874 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
875 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
876 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
877 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
878 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
879 "(i == %d)\n", y_after, i);
883 * test a richedit box that will scroll. There are two general
884 * cases: the case without any long lines and the case with a long
887 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
889 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
891 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
892 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
893 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
894 "LONG LINE \nb\nc\nd\ne");
895 for (j = 0; j < 12; j++) /* reset scroll position to top */
896 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
898 /* get first visible line */
899 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
900 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
902 /* get new current first visible line */
903 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
905 ok(((r & 0xffffff00) == 0x00010000) &&
906 ((r & 0x000000ff) != 0x00000000),
907 "EM_SCROLL page down didn't scroll by a small positive number of "
908 "lines (r == 0x%08x)\n", r);
909 ok(y_after > y_before, "EM_SCROLL page down not functioning "
910 "(line %d scrolled to line %d\n", y_before, y_after);
914 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
915 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
916 ok(((r & 0xffffff00) == 0x0001ff00),
917 "EM_SCROLL page up didn't scroll by a small negative number of lines "
918 "(r == 0x%08x)\n", r);
919 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
920 "%d scrolled to line %d\n", y_before, y_after);
924 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
926 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
928 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
929 "(r == 0x%08x)\n", r);
930 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
931 "1 line (%d scrolled to %d)\n", y_before, y_after);
935 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
937 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
939 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
940 "(r == 0x%08x)\n", r);
941 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
942 "line (%d scrolled to %d)\n", y_before, y_after);
946 r = SendMessage(hwndRichEdit, EM_SCROLL,
947 SB_LINEUP, 0); /* lineup beyond top */
949 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
952 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
953 ok(y_before == y_after,
954 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
958 r = SendMessage(hwndRichEdit, EM_SCROLL,
959 SB_PAGEUP, 0);/*page up beyond top */
961 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
964 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
965 ok(y_before == y_after,
966 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
968 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
969 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
970 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
971 r = SendMessage(hwndRichEdit, EM_SCROLL,
972 SB_PAGEDOWN, 0); /* page down beyond bot */
973 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
976 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
977 ok(y_before == y_after,
978 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
981 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
982 SendMessage(hwndRichEdit, EM_SCROLL,
983 SB_LINEDOWN, 0); /* line down beyond bot */
984 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
987 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
988 ok(y_before == y_after,
989 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
992 DestroyWindow(hwndRichEdit);
995 static void test_EM_SETUNDOLIMIT(void)
997 /* cases we test for:
998 * default behaviour - limiting at 100 undo's
999 * undo disabled - setting a limit of 0
1000 * undo limited - undo limit set to some to some number, like 2
1001 * bad input - sending a negative number should default to 100 undo's */
1003 HWND hwndRichEdit = new_richedit(NULL);
1008 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1011 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1012 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
1013 also, multiple pastes don't combine like WM_CHAR would */
1014 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1016 /* first case - check the default */
1017 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1018 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
1019 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1020 for (i=0; i<100; i++) /* Undo 100 of them */
1021 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1022 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1023 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
1025 /* second case - cannot undo */
1026 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
1027 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
1028 SendMessage(hwndRichEdit,
1029 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
1030 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1031 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
1033 /* third case - set it to an arbitrary number */
1034 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
1035 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
1036 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1037 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1038 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1039 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
1040 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
1041 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
1042 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1043 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1044 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
1045 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1046 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1047 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
1049 /* fourth case - setting negative numbers should default to 100 undos */
1050 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1051 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
1053 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
1055 DestroyWindow(hwndRichEdit);
1058 static void test_ES_PASSWORD(void)
1060 /* This isn't hugely testable, so we're just going to run it through its paces */
1062 HWND hwndRichEdit = new_richedit(NULL);
1065 /* First, check the default of a regular control */
1066 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1068 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
1070 /* Now, set it to something normal */
1071 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
1072 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1074 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1076 /* Now, set it to something odd */
1077 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
1078 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1080 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1081 DestroyWindow(hwndRichEdit);
1084 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie,
1089 char** str = (char**)dwCookie;
1092 memcpy(*str, pbBuff, *pcb);
1098 static void test_WM_SETTEXT()
1100 HWND hwndRichEdit = new_richedit(NULL);
1101 const char * TestItem1 = "TestSomeText";
1102 const char * TestItem2 = "TestSomeText\r";
1103 const char * TestItem2_after = "TestSomeText\r\n";
1104 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
1105 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
1106 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
1107 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
1108 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
1109 const char * TestItem5_after = "TestSomeText TestSomeText";
1110 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
1111 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
1112 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
1113 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
1115 char buf[1024] = {0};
1120 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
1121 any solitary \r to be converted to \r\n on return. Properly paired
1122 \r\n are not affected. It also shows that the special sequence \r\r\n
1123 gets converted to a single space.
1126 #define TEST_SETTEXT(a, b) \
1127 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
1128 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
1129 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
1130 ok (result == lstrlen(buf), \
1131 "WM_GETTEXT returned %ld instead of expected %u\n", \
1132 result, lstrlen(buf)); \
1133 result = strcmp(b, buf); \
1135 "WM_SETTEXT round trip: strcmp = %ld\n", result);
1137 TEST_SETTEXT(TestItem1, TestItem1)
1138 TEST_SETTEXT(TestItem2, TestItem2_after)
1139 TEST_SETTEXT(TestItem3, TestItem3_after)
1140 TEST_SETTEXT(TestItem3_after, TestItem3_after)
1141 TEST_SETTEXT(TestItem4, TestItem4_after)
1142 TEST_SETTEXT(TestItem5, TestItem5_after)
1143 TEST_SETTEXT(TestItem6, TestItem6_after)
1144 TEST_SETTEXT(TestItem7, TestItem7_after)
1146 /* The following test demonstrates that WM_SETTEXT supports RTF strings */
1147 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
1149 es.dwCookie = (DWORD_PTR)&p;
1151 es.pfnCallback = test_WM_SETTEXT_esCallback;
1152 memset(buf, 0, sizeof(buf));
1153 SendMessage(hwndRichEdit, EM_STREAMOUT,
1154 (WPARAM)(SF_RTF), (LPARAM)&es);
1155 trace("EM_STREAMOUT produced: \n%s\n", buf);
1156 TEST_SETTEXT(buf, TestItem1)
1159 DestroyWindow(hwndRichEdit);
1162 static void test_EM_STREAMOUT(void)
1164 HWND hwndRichEdit = new_richedit(NULL);
1167 char buf[1024] = {0};
1170 const char * TestItem1 = "TestSomeText";
1171 const char * TestItem2 = "TestSomeText\r";
1172 const char * TestItem3 = "TestSomeText\r\n";
1174 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
1176 es.dwCookie = (DWORD_PTR)&p;
1178 es.pfnCallback = test_WM_SETTEXT_esCallback;
1179 memset(buf, 0, sizeof(buf));
1180 SendMessage(hwndRichEdit, EM_STREAMOUT,
1181 (WPARAM)(SF_TEXT), (LPARAM)&es);
1183 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
1184 ok(strcmp(buf, TestItem1) == 0,
1185 "streamed text different, got %s\n", buf);
1187 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
1189 es.dwCookie = (DWORD_PTR)&p;
1191 es.pfnCallback = test_WM_SETTEXT_esCallback;
1192 memset(buf, 0, sizeof(buf));
1193 SendMessage(hwndRichEdit, EM_STREAMOUT,
1194 (WPARAM)(SF_TEXT), (LPARAM)&es);
1196 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
1197 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
1198 ok(strcmp(buf, TestItem3) == 0,
1199 "streamed text different from, got %s\n", buf);
1200 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
1202 es.dwCookie = (DWORD_PTR)&p;
1204 es.pfnCallback = test_WM_SETTEXT_esCallback;
1205 memset(buf, 0, sizeof(buf));
1206 SendMessage(hwndRichEdit, EM_STREAMOUT,
1207 (WPARAM)(SF_TEXT), (LPARAM)&es);
1209 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
1210 ok(strcmp(buf, TestItem3) == 0,
1211 "streamed text different, got %s\n", buf);
1213 DestroyWindow(hwndRichEdit);
1216 static void test_EM_SETTEXTEX(void)
1218 HWND hwndRichEdit = new_richedit(NULL);
1221 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1223 'T', 'e', 'x', 't', 0};
1224 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1228 const char * TestItem2_after = "TestSomeText\r\n";
1229 WCHAR TestItem3[] = {'T', 'e', 's', 't',
1232 '\r','\n','\r','\n', 0};
1233 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
1237 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
1241 WCHAR TestItem4[] = {'T', 'e', 's', 't',
1244 '\r','\r','\n','\r',
1246 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
1250 #define MAX_BUF_LEN 1024
1251 WCHAR buf[MAX_BUF_LEN];
1257 setText.codepage = 1200; /* no constant for unicode */
1258 getText.codepage = 1200; /* no constant for unicode */
1259 getText.cb = MAX_BUF_LEN;
1260 getText.flags = GT_DEFAULT;
1261 getText.lpDefaultChar = NULL;
1262 getText.lpUsedDefChar = NULL;
1265 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1266 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1267 ok(lstrcmpW(buf, TestItem1) == 0,
1268 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1270 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
1271 convert \r to \r\n on return
1273 setText.codepage = 1200; /* no constant for unicode */
1274 getText.codepage = 1200; /* no constant for unicode */
1275 getText.cb = MAX_BUF_LEN;
1276 getText.flags = GT_DEFAULT;
1277 getText.lpDefaultChar = NULL;
1278 getText.lpUsedDefChar = NULL;
1280 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem2);
1281 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1282 ok(lstrcmpW(buf, TestItem2) == 0,
1283 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1285 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
1286 SendMessage(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
1287 ok(strcmp((const char *)buf, TestItem2_after) == 0,
1288 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
1290 /* Baseline test for just-enough buffer space for string */
1291 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1292 getText.codepage = 1200; /* no constant for unicode */
1293 getText.flags = GT_DEFAULT;
1294 getText.lpDefaultChar = NULL;
1295 getText.lpUsedDefChar = NULL;
1296 memset(buf, 0, MAX_BUF_LEN);
1297 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1298 ok(lstrcmpW(buf, TestItem2) == 0,
1299 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1301 /* When there is enough space for one character, but not both, of the CRLF
1302 pair at the end of the string, the CR is not copied at all. That is,
1303 the caller must not see CRLF pairs truncated to CR at the end of the
1306 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1307 getText.codepage = 1200; /* no constant for unicode */
1308 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
1309 getText.lpDefaultChar = NULL;
1310 getText.lpUsedDefChar = NULL;
1311 memset(buf, 0, MAX_BUF_LEN);
1312 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1313 ok(lstrcmpW(buf, TestItem1) == 0,
1314 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1317 /* \r\n pairs get changed into \r */
1318 setText.codepage = 1200; /* no constant for unicode */
1319 getText.codepage = 1200; /* no constant for unicode */
1320 getText.cb = MAX_BUF_LEN;
1321 getText.flags = GT_DEFAULT;
1322 getText.lpDefaultChar = NULL;
1323 getText.lpUsedDefChar = NULL;
1325 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3);
1326 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1327 ok(lstrcmpW(buf, TestItem3_after) == 0,
1328 "EM_SETTEXTEX did not convert properly\n");
1330 /* \n also gets changed to \r */
1331 setText.codepage = 1200; /* no constant for unicode */
1332 getText.codepage = 1200; /* no constant for unicode */
1333 getText.cb = MAX_BUF_LEN;
1334 getText.flags = GT_DEFAULT;
1335 getText.lpDefaultChar = NULL;
1336 getText.lpUsedDefChar = NULL;
1338 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3alt);
1339 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1340 ok(lstrcmpW(buf, TestItem3_after) == 0,
1341 "EM_SETTEXTEX did not convert properly\n");
1343 /* \r\r\n gets changed into single space */
1344 setText.codepage = 1200; /* no constant for unicode */
1345 getText.codepage = 1200; /* no constant for unicode */
1346 getText.cb = MAX_BUF_LEN;
1347 getText.flags = GT_DEFAULT;
1348 getText.lpDefaultChar = NULL;
1349 getText.lpUsedDefChar = NULL;
1351 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem4);
1352 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1353 ok(lstrcmpW(buf, TestItem4_after) == 0,
1354 "EM_SETTEXTEX did not convert properly\n");
1356 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1357 (WPARAM)&setText, (LPARAM) NULL);
1358 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1361 "EM_SETTEXTEX returned %d, instead of 1\n",result);
1362 ok(lstrlenW(buf) == 0,
1363 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
1365 /* put some text back */
1367 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1368 /* select some text */
1371 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1372 /* replace current selection */
1373 setText.flags = ST_SELECTION;
1374 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1375 (WPARAM)&setText, (LPARAM) NULL);
1377 "EM_SETTEXTEX with NULL lParam to replace selection"
1378 " with no text should return 0. Got %i\n",
1381 /* put some text back */
1383 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1384 /* select some text */
1387 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1388 /* replace current selection */
1389 setText.flags = ST_SELECTION;
1390 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1391 (WPARAM)&setText, (LPARAM) TestItem1);
1393 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1394 ok(result == lstrlenW(TestItem1),
1395 "EM_SETTEXTEX with NULL lParam to replace selection"
1396 " with no text should return 0. Got %i\n",
1398 ok(lstrlenW(buf) == 22,
1399 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
1402 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
1403 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "TestSomeText"); /* TestItem1 */
1405 es.dwCookie = (DWORD_PTR)&p;
1407 es.pfnCallback = test_WM_SETTEXT_esCallback;
1408 memset(buf, 0, sizeof(buf));
1409 SendMessage(hwndRichEdit, EM_STREAMOUT,
1410 (WPARAM)(SF_RTF), (LPARAM)&es);
1411 trace("EM_STREAMOUT produced: \n%s\n", (char *)buf);
1413 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
1414 getText.codepage = 1200; /* no constant for unicode */
1415 getText.cb = MAX_BUF_LEN;
1416 getText.flags = GT_DEFAULT;
1417 getText.lpDefaultChar = NULL;
1418 getText.lpUsedDefChar = NULL;
1421 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) buf);
1422 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1423 ok(lstrcmpW(buf, TestItem1) == 0,
1424 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1427 DestroyWindow(hwndRichEdit);
1430 static void test_EM_LIMITTEXT(void)
1434 HWND hwndRichEdit = new_richedit(NULL);
1436 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
1437 * about setting the length to -1 for multiline edit controls doesn't happen.
1440 /* Don't check default gettextlimit case. That's done in other tests */
1442 /* Set textlimit to 100 */
1443 SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
1444 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1446 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
1448 /* Set textlimit to 0 */
1449 SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
1450 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1452 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
1454 /* Set textlimit to -1 */
1455 SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
1456 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1458 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
1460 /* Set textlimit to -2 */
1461 SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
1462 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1464 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
1466 DestroyWindow (hwndRichEdit);
1470 static void test_EM_EXLIMITTEXT(void)
1472 int i, selBegin, selEnd, len1, len2;
1474 char text[1024 + 1];
1475 char buffer[1024 + 1];
1476 int textlimit = 0; /* multiple of 100 */
1477 HWND hwndRichEdit = new_richedit(NULL);
1479 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1480 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
1483 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1484 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1486 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1489 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1490 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1492 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1494 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1495 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1496 /* default for WParam = 0 */
1497 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1499 textlimit = sizeof(text)-1;
1500 memset(text, 'W', textlimit);
1501 text[sizeof(text)-1] = 0;
1502 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1503 /* maxed out text */
1504 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1506 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1507 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1508 len1 = selEnd - selBegin;
1510 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1511 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1512 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1513 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1514 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1515 len2 = selEnd - selBegin;
1518 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1521 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1522 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1523 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1524 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1525 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1526 len1 = selEnd - selBegin;
1529 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1532 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1533 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1534 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1535 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1536 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1537 len2 = selEnd - selBegin;
1540 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1543 /* set text up to the limit, select all the text, then add a char */
1545 memset(text, 'W', textlimit);
1546 text[textlimit] = 0;
1547 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1548 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1549 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1550 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1551 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1552 result = strcmp(buffer, "A");
1553 ok(0 == result, "got string = \"%s\"\n", buffer);
1555 /* WM_SETTEXT not limited */
1557 memset(text, 'W', textlimit);
1558 text[textlimit] = 0;
1559 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
1560 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1561 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1563 ok(10 == i, "expected 10 chars\n");
1564 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1565 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1567 /* try inserting more text at end */
1568 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1569 ok(0 == i, "WM_CHAR wasn't processed\n");
1570 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1572 ok(10 == i, "expected 10 chars, got %i\n", i);
1573 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1574 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1576 /* try inserting text at beginning */
1577 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
1578 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1579 ok(0 == i, "WM_CHAR wasn't processed\n");
1580 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1582 ok(10 == i, "expected 10 chars, got %i\n", i);
1583 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1584 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1586 /* WM_CHAR is limited */
1588 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1589 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1590 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1591 ok(0 == i, "WM_CHAR wasn't processed\n");
1592 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1593 ok(0 == i, "WM_CHAR wasn't processed\n");
1594 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1596 ok(1 == i, "expected 1 chars, got %i instead\n", i);
1598 DestroyWindow(hwndRichEdit);
1601 static void test_EM_GETLIMITTEXT(void)
1604 HWND hwndRichEdit = new_richedit(NULL);
1606 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1607 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1609 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1610 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1611 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1613 DestroyWindow(hwndRichEdit);
1616 static void test_WM_SETFONT(void)
1618 /* There is no invalid input or error conditions for this function.
1619 * NULL wParam and lParam just fall back to their default values
1620 * It should be noted that even if you use a gibberish name for your fonts
1621 * here, it will still work because the name is stored. They will display as
1622 * System, but will report their name to be whatever they were created as */
1624 HWND hwndRichEdit = new_richedit(NULL);
1625 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1626 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1627 FF_DONTCARE, "Marlett");
1628 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1629 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1630 FF_DONTCARE, "MS Sans Serif");
1631 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1632 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1633 FF_DONTCARE, "Courier");
1634 LOGFONTA sentLogFont;
1635 CHARFORMAT2A returnedCF2A;
1637 returnedCF2A.cbSize = sizeof(returnedCF2A);
1639 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1640 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1641 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1643 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1644 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1645 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1646 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1648 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1649 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1650 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1651 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1652 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1653 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1655 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1656 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1657 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1658 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1659 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1660 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1662 /* This last test is special since we send in NULL. We clear the variables
1663 * and just compare to "System" instead of the sent in font name. */
1664 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1665 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1666 returnedCF2A.cbSize = sizeof(returnedCF2A);
1668 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1669 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1670 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1671 ok (!strcmp("System",returnedCF2A.szFaceName),
1672 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1674 DestroyWindow(hwndRichEdit);
1678 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1683 const char** str = (const char**)dwCookie;
1684 int size = strlen(*str);
1685 if(size > 3) /* let's make it piecemeal for fun */
1692 memcpy(pbBuff, *str, *pcb);
1698 static void test_EM_GETMODIFY(void)
1700 HWND hwndRichEdit = new_richedit(NULL);
1703 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1705 'T', 'e', 'x', 't', 0};
1706 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1708 'O', 't', 'h', 'e', 'r',
1709 'T', 'e', 'x', 't', 0};
1710 const char* streamText = "hello world";
1715 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1716 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1717 FF_DONTCARE, "Courier");
1719 setText.codepage = 1200; /* no constant for unicode */
1720 setText.flags = ST_KEEPUNDO;
1723 /* modify flag shouldn't be set when richedit is first created */
1724 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1726 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1728 /* setting modify flag should actually set it */
1729 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1730 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1732 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1734 /* clearing modify flag should actually clear it */
1735 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1736 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1738 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1740 /* setting font doesn't change modify flag */
1741 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1742 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1743 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1745 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1747 /* setting text should set modify flag */
1748 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1749 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1750 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1752 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1754 /* undo previous text doesn't reset modify flag */
1755 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1756 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1758 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1760 /* set text with no flag to keep undo stack should not set modify flag */
1761 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1763 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1764 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1766 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1768 /* WM_SETTEXT doesn't modify */
1769 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1770 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1771 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1773 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1775 /* clear the text */
1776 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1777 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1778 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1780 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1783 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1784 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1785 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1786 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1787 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1789 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1791 /* copy/paste text 1 */
1792 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1793 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1794 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1795 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1796 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1798 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1800 /* copy/paste text 2 */
1801 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1802 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1803 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1804 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1805 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1806 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1808 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1811 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1812 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1813 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1814 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1816 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1819 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1820 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1821 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
1822 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1824 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1826 /* set char format */
1827 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1828 cf2.cbSize = sizeof(CHARFORMAT2);
1829 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1831 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1832 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1833 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1834 result = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1835 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
1836 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1838 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1840 /* set para format */
1841 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1842 pf2.cbSize = sizeof(PARAFORMAT2);
1843 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1845 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1846 pf2.wAlignment = PFA_RIGHT;
1847 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1848 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1850 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1853 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1854 es.dwCookie = (DWORD_PTR)&streamText;
1856 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1857 SendMessage(hwndRichEdit, EM_STREAMIN,
1858 (WPARAM)(SF_TEXT), (LPARAM)&es);
1859 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1861 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1863 DestroyWindow(hwndRichEdit);
1869 long expected_retval;
1870 int expected_getsel_start;
1871 int expected_getsel_end;
1872 int _exsetsel_todo_wine;
1873 int _getsel_todo_wine;
1876 const struct exsetsel_s exsetsel_tests[] = {
1878 {5, 10, 10, 5, 10, 0, 0},
1879 {15, 17, 17, 15, 17, 0, 0},
1880 /* test cpMax > strlen() */
1881 {0, 100, 18, 0, 18, 0, 1},
1882 /* test cpMin == cpMax */
1883 {5, 5, 5, 5, 5, 0, 0},
1884 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1885 {-1, 0, 5, 5, 5, 0, 0},
1886 {-1, 17, 5, 5, 5, 0, 0},
1887 {-1, 18, 5, 5, 5, 0, 0},
1888 /* test cpMin < 0 && cpMax < 0 */
1889 {-1, -1, 17, 17, 17, 0, 0},
1890 {-4, -5, 17, 17, 17, 0, 0},
1891 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1892 {0, -1, 18, 0, 18, 0, 1},
1893 {17, -5, 18, 17, 18, 0, 1},
1894 {18, -3, 17, 17, 17, 0, 0},
1895 /* test if cpMin > cpMax */
1896 {15, 19, 18, 15, 18, 0, 1},
1897 {19, 15, 18, 15, 18, 0, 1}
1900 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1905 cr.cpMin = setsel->min;
1906 cr.cpMax = setsel->max;
1907 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1909 if (setsel->_exsetsel_todo_wine) {
1911 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1914 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1917 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1919 if (setsel->_getsel_todo_wine) {
1921 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1924 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1928 static void test_EM_EXSETSEL(void)
1930 HWND hwndRichEdit = new_richedit(NULL);
1932 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1934 /* sending some text to the window */
1935 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1936 /* 01234567890123456*/
1939 for (i = 0; i < num_tests; i++) {
1940 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1943 DestroyWindow(hwndRichEdit);
1946 static void test_EM_REPLACESEL(int redraw)
1948 HWND hwndRichEdit = new_richedit(NULL);
1949 char buffer[1024] = {0};
1954 /* sending some text to the window */
1955 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1956 /* 01234567890123456*/
1959 /* FIXME add more tests */
1960 SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
1961 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
1962 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
1963 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1964 r = strcmp(buffer, "testing");
1965 ok(0 == r, "expected %d, got %d\n", 0, r);
1967 DestroyWindow(hwndRichEdit);
1969 hwndRichEdit = new_richedit(NULL);
1971 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw);
1972 SendMessage(hwndRichEdit, WM_SETREDRAW, redraw, 0);
1974 /* Test behavior with carriage returns and newlines */
1975 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1976 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1");
1977 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
1978 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1979 r = strcmp(buffer, "RichEdit1");
1980 ok(0 == r, "expected %d, got %d\n", 0, r);
1982 getText.codepage = CP_ACP;
1983 getText.flags = GT_DEFAULT;
1984 getText.lpDefaultChar = NULL;
1985 getText.lpUsedDefChar = NULL;
1986 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1987 ok(strcmp(buffer, "RichEdit1") == 0,
1988 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
1990 /* Test number of lines reported after EM_REPLACESEL */
1991 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
1992 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
1994 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1995 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r");
1996 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
1997 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1998 r = strcmp(buffer, "RichEdit1\r\n");
1999 ok(0 == r, "expected %d, got %d\n", 0, r);
2001 getText.codepage = CP_ACP;
2002 getText.flags = GT_DEFAULT;
2003 getText.lpDefaultChar = NULL;
2004 getText.lpUsedDefChar = NULL;
2005 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2006 ok(strcmp(buffer, "RichEdit1\r") == 0,
2007 "EM_GETTEXTEX returned incorrect string\n");
2009 /* Test number of lines reported after EM_REPLACESEL */
2010 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2011 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2013 /* Win98's riched20 and WinXP's riched20 disagree on what to return from
2014 EM_REPLACESEL. The general rule seems to be that Win98's riched20
2015 returns the number of characters *inserted* into the control (after
2016 required conversions), but WinXP's riched20 returns the number of
2017 characters interpreted from the original lParam. Wine's builtin riched20
2018 implements the WinXP behavior.
2020 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2021 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r\n");
2022 ok(11 == r /* WinXP */ || 10 == r /* Win98 */,
2023 "EM_REPLACESEL returned %d, expected 11 or 10\n", r);
2025 /* Test number of lines reported after EM_REPLACESEL */
2026 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2027 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2029 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2030 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2031 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
2032 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
2034 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2035 r = strcmp(buffer, "RichEdit1\r\n");
2036 ok(0 == r, "expected %d, got %d\n", 0, r);
2038 getText.codepage = CP_ACP;
2039 getText.flags = GT_DEFAULT;
2040 getText.lpDefaultChar = NULL;
2041 getText.lpUsedDefChar = NULL;
2042 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2043 ok(strcmp(buffer, "RichEdit1\r") == 0,
2044 "EM_GETTEXTEX returned incorrect string\n");
2046 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2047 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2048 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
2049 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
2051 /* The following tests show that richedit should handle the special \r\r\n
2052 sequence by turning it into a single space on insertion. However,
2053 EM_REPLACESEL on WinXP returns the number of characters in the original
2057 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2058 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r");
2059 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
2060 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2061 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2062 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2063 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2065 /* Test the actual string */
2067 getText.codepage = CP_ACP;
2068 getText.flags = GT_DEFAULT;
2069 getText.lpDefaultChar = NULL;
2070 getText.lpUsedDefChar = NULL;
2071 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2072 ok(strcmp(buffer, "\r\r") == 0,
2073 "EM_GETTEXTEX returned incorrect string\n");
2075 /* Test number of lines reported after EM_REPLACESEL */
2076 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2077 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
2079 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2080 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n");
2081 ok(3 == r /* WinXP */ || 1 == r /* Win98 */,
2082 "EM_REPLACESEL returned %d, expected 3 or 1\n", r);
2083 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2084 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2085 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
2086 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
2088 /* Test the actual string */
2090 getText.codepage = CP_ACP;
2091 getText.flags = GT_DEFAULT;
2092 getText.lpDefaultChar = NULL;
2093 getText.lpUsedDefChar = NULL;
2094 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2095 ok(strcmp(buffer, " ") == 0,
2096 "EM_GETTEXTEX returned incorrect string\n");
2098 /* Test number of lines reported after EM_REPLACESEL */
2099 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2100 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
2102 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2103 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r");
2104 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
2105 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
2106 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2107 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2108 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
2109 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
2111 /* Test the actual string */
2113 getText.codepage = CP_ACP;
2114 getText.flags = GT_DEFAULT;
2115 getText.lpDefaultChar = NULL;
2116 getText.lpUsedDefChar = NULL;
2117 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2118 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
2119 "EM_GETTEXTEX returned incorrect string\n");
2121 /* Test number of lines reported after EM_REPLACESEL */
2122 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2123 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
2125 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2126 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n");
2127 ok(5 == r /* WinXP */ || 2 == r /* Win98 */,
2128 "EM_REPLACESEL returned %d, expected 5 or 2\n", r);
2129 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2130 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2131 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2132 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2134 /* Test the actual string */
2136 getText.codepage = CP_ACP;
2137 getText.flags = GT_DEFAULT;
2138 getText.lpDefaultChar = NULL;
2139 getText.lpUsedDefChar = NULL;
2140 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2141 ok(strcmp(buffer, " \r") == 0,
2142 "EM_GETTEXTEX returned incorrect string\n");
2144 /* Test number of lines reported after EM_REPLACESEL */
2145 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2146 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2148 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2149 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r");
2150 ok(5 == r /* WinXP */ || 3 == r /* Win98 */,
2151 "EM_REPLACESEL returned %d, expected 5 or 3\n", r);
2152 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2153 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2154 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
2155 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
2157 /* Test the actual string */
2159 getText.codepage = CP_ACP;
2160 getText.flags = GT_DEFAULT;
2161 getText.lpDefaultChar = NULL;
2162 getText.lpUsedDefChar = NULL;
2163 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2164 ok(strcmp(buffer, " \r\r") == 0,
2165 "EM_GETTEXTEX returned incorrect string\n");
2167 /* Test number of lines reported after EM_REPLACESEL */
2168 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2169 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
2171 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2172 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r");
2173 ok(6 == r /* WinXP */ || 5 == r /* Win98 */,
2174 "EM_REPLACESEL returned %d, expected 6 or 5\n", r);
2175 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2176 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2177 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
2178 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
2180 /* Test the actual string */
2182 getText.codepage = CP_ACP;
2183 getText.flags = GT_DEFAULT;
2184 getText.lpDefaultChar = NULL;
2185 getText.lpUsedDefChar = NULL;
2186 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2187 ok(strcmp(buffer, "\rX\r\r\r") == 0,
2188 "EM_GETTEXTEX returned incorrect string\n");
2190 /* Test number of lines reported after EM_REPLACESEL */
2191 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2192 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r);
2194 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2195 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n");
2196 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
2197 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2198 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2199 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2200 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2202 /* Test the actual string */
2204 getText.codepage = CP_ACP;
2205 getText.flags = GT_DEFAULT;
2206 getText.lpDefaultChar = NULL;
2207 getText.lpUsedDefChar = NULL;
2208 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2209 ok(strcmp(buffer, "\r\r") == 0,
2210 "EM_GETTEXTEX returned incorrect string\n");
2212 /* Test number of lines reported after EM_REPLACESEL */
2213 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2214 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
2216 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2217 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n");
2218 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
2219 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
2220 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2221 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2222 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
2223 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
2225 /* Test the actual string */
2227 getText.codepage = CP_ACP;
2228 getText.flags = GT_DEFAULT;
2229 getText.lpDefaultChar = NULL;
2230 getText.lpUsedDefChar = NULL;
2231 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2232 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
2233 "EM_GETTEXTEX returned incorrect string\n");
2235 /* Test number of lines reported after EM_REPLACESEL */
2236 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2237 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
2239 DestroyWindow(hwndRichEdit);
2242 static void test_WM_PASTE(void)
2246 char buffer[1024] = {0};
2247 char key_info[][3] =
2249 /* VirtualKey, ScanCode, WM_CHAR code */
2250 {'C', 0x2e, 3}, /* Ctrl-C */
2251 {'X', 0x2d, 24}, /* Ctrl-X */
2252 {'V', 0x2f, 22}, /* Ctrl-V */
2253 {'Z', 0x2c, 26}, /* Ctrl-Z */
2254 {'Y', 0x15, 25}, /* Ctrl-Y */
2256 const char* text1 = "testing paste\r";
2257 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
2258 const char* text1_after = "testing paste\r\n";
2259 const char* text2 = "testing paste\r\rtesting paste";
2260 const char* text2_after = "testing paste\r\n\r\ntesting paste";
2261 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
2262 HWND hwndRichEdit = new_richedit(NULL);
2264 /* Native riched20 won't obey WM_CHAR messages or WM_KEYDOWN/WM_KEYUP
2265 messages, probably because it inspects the keyboard state itself.
2266 Therefore, native requires this in order to obey Ctrl-<key> keystrokes.
2268 #define SEND_CTRL_KEY(hwnd, k) \
2269 keybd_event(VK_CONTROL, 0x1d, 0, 0);\
2270 keybd_event(k[0], k[1], 0, 0);\
2271 keybd_event(k[0], k[1], KEYEVENTF_KEYUP, 0);\
2272 keybd_event(VK_CONTROL, 0x1d, KEYEVENTF_KEYUP, 0); \
2273 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
2274 TranslateMessage(&msg); \
2275 DispatchMessage(&msg); \
2278 #define SEND_CTRL_C(hwnd) SEND_CTRL_KEY(hwnd, key_info[0])
2279 #define SEND_CTRL_X(hwnd) SEND_CTRL_KEY(hwnd, key_info[1])
2280 #define SEND_CTRL_V(hwnd) SEND_CTRL_KEY(hwnd, key_info[2])
2281 #define SEND_CTRL_Z(hwnd) SEND_CTRL_KEY(hwnd, key_info[3])
2282 #define SEND_CTRL_Y(hwnd) SEND_CTRL_KEY(hwnd, key_info[4])
2284 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
2285 SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
2287 SEND_CTRL_C(hwndRichEdit) /* Copy */
2288 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2289 SEND_CTRL_V(hwndRichEdit) /* Paste */
2290 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2291 /* Pasted text should be visible at this step */
2292 result = strcmp(text1_step1, buffer);
2294 "test paste: strcmp = %i\n", result);
2295 SEND_CTRL_Z(hwndRichEdit) /* Undo */
2296 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2297 /* Text should be the same as before (except for \r -> \r\n conversion) */
2298 result = strcmp(text1_after, buffer);
2300 "test paste: strcmp = %i\n", result);
2302 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
2303 SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
2304 SEND_CTRL_C(hwndRichEdit) /* Copy */
2305 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2306 SEND_CTRL_V(hwndRichEdit) /* Paste */
2307 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2308 /* Pasted text should be visible at this step */
2309 result = strcmp(text3, buffer);
2311 "test paste: strcmp = %i\n", result);
2312 SEND_CTRL_Z(hwndRichEdit) /* Undo */
2313 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2314 /* Text should be the same as before (except for \r -> \r\n conversion) */
2315 result = strcmp(text2_after, buffer);
2317 "test paste: strcmp = %i\n", result);
2318 SEND_CTRL_Y(hwndRichEdit) /* Redo */
2319 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2320 /* Text should revert to post-paste state */
2321 result = strcmp(buffer,text3);
2323 "test paste: strcmp = %i\n", result);
2325 DestroyWindow(hwndRichEdit);
2328 static void test_EM_FORMATRANGE(void)
2333 HWND hwndRichEdit = new_richedit(NULL);
2335 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
2337 hdc = GetDC(hwndRichEdit);
2338 ok(hdc != NULL, "Could not get HDC\n");
2340 fr.hdc = fr.hdcTarget = hdc;
2341 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
2342 fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
2343 fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
2347 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2349 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2352 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2354 ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
2360 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2362 ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
2365 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2367 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2370 DestroyWindow(hwndRichEdit);
2373 static int nCallbackCount = 0;
2375 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
2378 const char text[] = {'t','e','s','t'};
2380 if (sizeof(text) <= cb)
2382 if ((int)dwCookie != nCallbackCount)
2388 memcpy (pbBuff, text, sizeof(text));
2389 *pcb = sizeof(text);
2396 return 1; /* indicates callback failed */
2399 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
2404 const char** str = (const char**)dwCookie;
2405 int size = strlen(*str);
2411 memcpy(pbBuff, *str, *pcb);
2418 static void test_EM_STREAMIN(void)
2420 HWND hwndRichEdit = new_richedit(NULL);
2423 char buffer[1024] = {0};
2425 const char * streamText0 = "{\\rtf1 TestSomeText}";
2426 const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
2427 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
2429 const char * streamText1 =
2430 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \
2431 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \
2434 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
2435 const char * streamText2 =
2436 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \
2437 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \
2438 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \
2439 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \
2440 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \
2441 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \
2442 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
2444 const char * streamText3 = "RichEdit1";
2446 /* Minimal test without \par at the end */
2447 es.dwCookie = (DWORD_PTR)&streamText0;
2449 es.pfnCallback = test_EM_STREAMIN_esCallback;
2450 SendMessage(hwndRichEdit, EM_STREAMIN,
2451 (WPARAM)(SF_RTF), (LPARAM)&es);
2453 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2455 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
2456 result = strcmp (buffer,"TestSomeText");
2458 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
2460 /* Native richedit 2.0 ignores last \par */
2461 es.dwCookie = (DWORD_PTR)&streamText0a;
2463 es.pfnCallback = test_EM_STREAMIN_esCallback;
2464 SendMessage(hwndRichEdit, EM_STREAMIN,
2465 (WPARAM)(SF_RTF), (LPARAM)&es);
2467 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2469 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
2470 result = strcmp (buffer,"TestSomeText");
2472 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
2474 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
2475 es.dwCookie = (DWORD_PTR)&streamText0b;
2477 es.pfnCallback = test_EM_STREAMIN_esCallback;
2478 SendMessage(hwndRichEdit, EM_STREAMIN,
2479 (WPARAM)(SF_RTF), (LPARAM)&es);
2481 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2483 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
2484 result = strcmp (buffer,"TestSomeText\r\n");
2486 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
2488 es.dwCookie = (DWORD_PTR)&streamText1;
2490 es.pfnCallback = test_EM_STREAMIN_esCallback;
2491 SendMessage(hwndRichEdit, EM_STREAMIN,
2492 (WPARAM)(SF_RTF), (LPARAM)&es);
2494 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2496 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
2497 result = strcmp (buffer,"TestSomeText");
2499 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
2501 es.dwCookie = (DWORD_PTR)&streamText2;
2502 SendMessage(hwndRichEdit, EM_STREAMIN,
2503 (WPARAM)(SF_RTF), (LPARAM)&es);
2505 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2507 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result);
2508 ok (strlen(buffer) == 0,
2509 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2511 es.dwCookie = (DWORD_PTR)&streamText3;
2512 SendMessage(hwndRichEdit, EM_STREAMIN,
2513 (WPARAM)(SF_RTF), (LPARAM)&es);
2515 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2517 "EM_STREAMIN: Test 3 returned %ld, expected 9\n", result);
2518 ok (strlen(buffer) == 0,
2519 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
2521 DestroyWindow(hwndRichEdit);
2524 static void test_EM_StreamIn_Undo(void)
2526 /* The purpose of this test is to determine when a EM_StreamIn should be
2527 * undoable. This is important because WM_PASTE currently uses StreamIn and
2528 * pasting should always be undoable but streaming isn't always.
2531 * StreamIn plain text without SFF_SELECTION.
2532 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
2533 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
2534 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
2535 * Feel free to add tests for other text modes or StreamIn things.
2539 HWND hwndRichEdit = new_richedit(NULL);
2542 char buffer[1024] = {0};
2543 const char randomtext[] = "Some text";
2545 es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
2547 /* StreamIn, no SFF_SELECTION */
2548 es.dwCookie = nCallbackCount;
2549 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2550 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2551 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2552 SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
2553 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2554 result = strcmp (buffer,"test");
2556 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
2558 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2559 ok (result == FALSE,
2560 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
2562 /* StreamIn, SFF_SELECTION, but nothing selected */
2563 es.dwCookie = nCallbackCount;
2564 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2565 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2566 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2567 SendMessage(hwndRichEdit, EM_STREAMIN,
2568 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2569 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2570 result = strcmp (buffer,"testSome text");
2572 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2574 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2576 "EM_STREAMIN with SFF_SELECTION but no selection set "
2577 "should create an undo\n");
2579 /* StreamIn, SFF_SELECTION, with a selection */
2580 es.dwCookie = nCallbackCount;
2581 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2582 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2583 SendMessage(hwndRichEdit, EM_SETSEL,4,5);
2584 SendMessage(hwndRichEdit, EM_STREAMIN,
2585 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2586 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2587 result = strcmp (buffer,"Sometesttext");
2589 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2591 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2593 "EM_STREAMIN with SFF_SELECTION and selection set "
2594 "should create an undo\n");
2598 static BOOL is_em_settextex_supported(HWND hwnd)
2600 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
2601 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
2604 static void test_unicode_conversions(void)
2606 static const WCHAR tW[] = {'t',0};
2607 static const WCHAR teW[] = {'t','e',0};
2608 static const WCHAR textW[] = {'t','e','s','t',0};
2609 static const char textA[] = "test";
2613 int is_win9x, em_settextex_supported, ret;
2615 is_win9x = GetVersion() & 0x80000000;
2617 #define set_textA(hwnd, wm_set_text, txt) \
2619 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
2620 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2621 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2622 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2623 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
2625 #define expect_textA(hwnd, wm_get_text, txt) \
2627 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2628 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
2629 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2630 memset(bufA, 0xAA, sizeof(bufA)); \
2631 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2632 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2633 ret = lstrcmpA(bufA, txt); \
2634 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
2637 #define set_textW(hwnd, wm_set_text, txt) \
2639 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
2640 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2641 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2642 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2643 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
2645 #define expect_textW(hwnd, wm_get_text, txt) \
2647 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
2648 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
2649 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2650 memset(bufW, 0xAA, sizeof(bufW)); \
2653 assert(wm_get_text == EM_GETTEXTEX); \
2654 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2655 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2659 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2660 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
2662 ret = lstrcmpW(bufW, txt); \
2663 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
2665 #define expect_empty(hwnd, wm_get_text) \
2667 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2668 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
2669 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2670 memset(bufA, 0xAA, sizeof(bufA)); \
2671 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2672 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
2673 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
2676 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2677 0, 0, 200, 60, 0, 0, 0, 0);
2678 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2680 ret = IsWindowUnicode(hwnd);
2682 ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
2684 ok(ret, "RichEdit20W should be unicode under NT\n");
2686 /* EM_SETTEXTEX is supported starting from version 3.0 */
2687 em_settextex_supported = is_em_settextex_supported(hwnd);
2688 trace("EM_SETTEXTEX is %ssupported on this platform\n",
2689 em_settextex_supported ? "" : "NOT ");
2691 expect_empty(hwnd, WM_GETTEXT);
2692 expect_empty(hwnd, EM_GETTEXTEX);
2694 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
2695 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2696 expect_textA(hwnd, WM_GETTEXT, "t");
2697 expect_textA(hwnd, EM_GETTEXTEX, "t");
2698 expect_textW(hwnd, EM_GETTEXTEX, tW);
2700 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
2701 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2702 expect_textA(hwnd, WM_GETTEXT, "te");
2703 expect_textA(hwnd, EM_GETTEXTEX, "te");
2704 expect_textW(hwnd, EM_GETTEXTEX, teW);
2706 set_textA(hwnd, WM_SETTEXT, NULL);
2707 expect_empty(hwnd, WM_GETTEXT);
2708 expect_empty(hwnd, EM_GETTEXTEX);
2711 set_textA(hwnd, WM_SETTEXT, textW);
2713 set_textA(hwnd, WM_SETTEXT, textA);
2714 expect_textA(hwnd, WM_GETTEXT, textA);
2715 expect_textA(hwnd, EM_GETTEXTEX, textA);
2716 expect_textW(hwnd, EM_GETTEXTEX, textW);
2718 if (em_settextex_supported)
2720 set_textA(hwnd, EM_SETTEXTEX, textA);
2721 expect_textA(hwnd, WM_GETTEXT, textA);
2722 expect_textA(hwnd, EM_GETTEXTEX, textA);
2723 expect_textW(hwnd, EM_GETTEXTEX, textW);
2728 set_textW(hwnd, WM_SETTEXT, textW);
2729 expect_textW(hwnd, WM_GETTEXT, textW);
2730 expect_textA(hwnd, WM_GETTEXT, textA);
2731 expect_textW(hwnd, EM_GETTEXTEX, textW);
2732 expect_textA(hwnd, EM_GETTEXTEX, textA);
2734 if (em_settextex_supported)
2736 set_textW(hwnd, EM_SETTEXTEX, textW);
2737 expect_textW(hwnd, WM_GETTEXT, textW);
2738 expect_textA(hwnd, WM_GETTEXT, textA);
2739 expect_textW(hwnd, EM_GETTEXTEX, textW);
2740 expect_textA(hwnd, EM_GETTEXTEX, textA);
2743 DestroyWindow(hwnd);
2745 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
2746 0, 0, 200, 60, 0, 0, 0, 0);
2747 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2749 ret = IsWindowUnicode(hwnd);
2750 ok(!ret, "RichEdit20A should NOT be unicode\n");
2752 set_textA(hwnd, WM_SETTEXT, textA);
2753 expect_textA(hwnd, WM_GETTEXT, textA);
2754 expect_textA(hwnd, EM_GETTEXTEX, textA);
2755 expect_textW(hwnd, EM_GETTEXTEX, textW);
2757 if (em_settextex_supported)
2759 set_textA(hwnd, EM_SETTEXTEX, textA);
2760 expect_textA(hwnd, WM_GETTEXT, textA);
2761 expect_textA(hwnd, EM_GETTEXTEX, textA);
2762 expect_textW(hwnd, EM_GETTEXTEX, textW);
2767 set_textW(hwnd, WM_SETTEXT, textW);
2768 expect_textW(hwnd, WM_GETTEXT, textW);
2769 expect_textA(hwnd, WM_GETTEXT, textA);
2770 expect_textW(hwnd, EM_GETTEXTEX, textW);
2771 expect_textA(hwnd, EM_GETTEXTEX, textA);
2773 if (em_settextex_supported)
2775 set_textW(hwnd, EM_SETTEXTEX, textW);
2776 expect_textW(hwnd, WM_GETTEXT, textW);
2777 expect_textA(hwnd, WM_GETTEXT, textA);
2778 expect_textW(hwnd, EM_GETTEXTEX, textW);
2779 expect_textA(hwnd, EM_GETTEXTEX, textA);
2782 DestroyWindow(hwnd);
2785 static void test_WM_CHAR(void)
2789 const char * char_list = "abc\rabc\r";
2790 const char * expected_content_single = "abcabc";
2791 const char * expected_content_multi = "abc\r\nabc\r\n";
2792 char buffer[64] = {0};
2795 /* single-line control must IGNORE carriage returns */
2796 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2797 0, 0, 200, 60, 0, 0, 0, 0);
2798 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2801 while (*p != '\0') {
2802 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2803 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2804 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2805 SendMessageA(hwnd, WM_KEYUP, *p, 1);
2809 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2810 ret = strcmp(buffer, expected_content_single);
2811 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2813 DestroyWindow(hwnd);
2815 /* multi-line control inserts CR normally */
2816 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
2817 0, 0, 200, 60, 0, 0, 0, 0);
2818 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2821 while (*p != '\0') {
2822 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2823 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2824 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2825 SendMessageA(hwnd, WM_KEYUP, *p, 1);
2829 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2830 ret = strcmp(buffer, expected_content_multi);
2831 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2833 DestroyWindow(hwnd);
2836 static void test_EM_GETTEXTLENGTHEX(void)
2839 GETTEXTLENGTHEX gtl;
2841 const char * base_string = "base string";
2842 const char * test_string = "a\nb\n\n\r\n";
2843 const char * test_string_after = "a";
2844 const char * test_string_2 = "a\rtest\rstring";
2845 char buffer[64] = {0};
2848 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2849 0, 0, 200, 60, 0, 0, 0, 0);
2850 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2852 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2853 gtl.codepage = CP_ACP;
2854 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2855 ok(ret == 0, "ret %d\n",ret);
2857 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2858 gtl.codepage = CP_ACP;
2859 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2860 ok(ret == 0, "ret %d\n",ret);
2862 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2864 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2865 gtl.codepage = CP_ACP;
2866 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2867 ok(ret == strlen(base_string), "ret %d\n",ret);
2869 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2870 gtl.codepage = CP_ACP;
2871 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2872 ok(ret == strlen(base_string), "ret %d\n",ret);
2874 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2876 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2877 gtl.codepage = CP_ACP;
2878 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2879 ok(ret == 1, "ret %d\n",ret);
2881 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2882 gtl.codepage = CP_ACP;
2883 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2884 ok(ret == 1, "ret %d\n",ret);
2886 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2887 ret = strcmp(buffer, test_string_after);
2888 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2890 DestroyWindow(hwnd);
2893 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
2894 0, 0, 200, 60, 0, 0, 0, 0);
2895 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2897 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2898 gtl.codepage = CP_ACP;
2899 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2900 ok(ret == 0, "ret %d\n",ret);
2902 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2903 gtl.codepage = CP_ACP;
2904 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2905 ok(ret == 0, "ret %d\n",ret);
2907 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2909 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2910 gtl.codepage = CP_ACP;
2911 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2912 ok(ret == strlen(base_string), "ret %d\n",ret);
2914 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2915 gtl.codepage = CP_ACP;
2916 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2917 ok(ret == strlen(base_string), "ret %d\n",ret);
2919 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string_2);
2921 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2922 gtl.codepage = CP_ACP;
2923 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2924 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
2926 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2927 gtl.codepage = CP_ACP;
2928 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2929 ok(ret == strlen(test_string_2), "ret %d\n",ret);
2931 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2933 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2934 gtl.codepage = CP_ACP;
2935 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2936 ok(ret == 10, "ret %d\n",ret);
2938 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2939 gtl.codepage = CP_ACP;
2940 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2941 ok(ret == 6, "ret %d\n",ret);
2943 DestroyWindow(hwnd);
2947 /* globals that parent and child access when checking event masks & notifications */
2948 static HWND eventMaskEditHwnd = 0;
2949 static int queriedEventMask;
2950 static int watchForEventMask = 0;
2952 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
2953 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2955 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
2957 queriedEventMask = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2959 return DefWindowProcA(hwnd, message, wParam, lParam);
2962 /* test event masks in combination with WM_COMMAND */
2963 static void test_eventMask(void)
2968 const char text[] = "foo bar\n";
2971 /* register class to capture WM_COMMAND */
2973 cls.lpfnWndProc = ParentMsgCheckProcA;
2976 cls.hInstance = GetModuleHandleA(0);
2978 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2979 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2980 cls.lpszMenuName = NULL;
2981 cls.lpszClassName = "EventMaskParentClass";
2982 if(!RegisterClassA(&cls)) assert(0);
2984 parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
2985 0, 0, 200, 60, NULL, NULL, NULL, NULL);
2986 ok (parent != 0, "Failed to create parent window\n");
2988 eventMaskEditHwnd = new_richedit(parent);
2989 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
2991 eventMask = ENM_CHANGE | ENM_UPDATE;
2992 ret = SendMessage(eventMaskEditHwnd, EM_SETEVENTMASK, 0, (LPARAM) eventMask);
2993 ok(ret == ENM_NONE, "wrong event mask\n");
2994 ret = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2995 ok(ret == eventMask, "failed to set event mask\n");
2997 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
2998 queriedEventMask = 0; /* initialize to something other than we expect */
2999 watchForEventMask = EN_CHANGE;
3000 ret = SendMessage(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM) text);
3001 ok(ret == TRUE, "failed to set text\n");
3002 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
3003 notification in response to WM_SETTEXT */
3004 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
3005 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
3009 START_TEST( editor )
3014 /* Must explicitly LoadLibrary(). The test has no references to functions in
3015 * RICHED20.DLL, so the linker doesn't actually link to it. */
3016 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
3017 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
3022 test_EM_SCROLLCARET();
3025 test_EM_LINELENGTH();
3026 test_EM_SETCHARFORMAT();
3027 test_EM_SETTEXTMODE();
3028 test_TM_PLAINTEXT();
3029 test_EM_SETOPTIONS();
3031 test_EM_AUTOURLDETECT();
3032 test_EM_SETUNDOLIMIT();
3034 test_EM_SETTEXTEX();
3035 test_EM_LIMITTEXT();
3036 test_EM_EXLIMITTEXT();
3037 test_EM_GETLIMITTEXT();
3039 test_EM_GETMODIFY();
3043 test_EM_STREAMOUT();
3044 test_EM_StreamIn_Undo();
3045 test_EM_FORMATRANGE();
3046 test_unicode_conversions();
3047 test_EM_GETTEXTLENGTHEX();
3048 test_EM_REPLACESEL(1);
3049 test_EM_REPLACESEL(0);
3052 /* Set the environment variable WINETEST_RICHED20 to keep windows
3053 * responsive and open for 30 seconds. This is useful for debugging.
3055 * The message pump uses PeekMessage() to empty the queue and then sleeps for
3056 * 50ms before retrying the queue. */
3057 end = time(NULL) + 30;
3058 if (getenv( "WINETEST_RICHED20" )) {
3059 while (time(NULL) < end) {
3060 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
3061 TranslateMessage(&msg);
3062 DispatchMessage(&msg);
3069 OleFlushClipboard();
3070 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());