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},
132 {0, -1, "wineWine wine", 0, -1, 0},
135 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
138 memset(&ft, 0, sizeof(ft));
139 ft.chrg.cpMin = f->start;
140 ft.chrg.cpMax = f->end;
141 ft.lpstrText = f->needle;
142 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
143 ok(findloc == f->expected_loc,
144 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
145 name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
148 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
152 int expected_end_loc;
154 memset(&ft, 0, sizeof(ft));
155 ft.chrg.cpMin = f->start;
156 ft.chrg.cpMax = f->end;
157 ft.lpstrText = f->needle;
158 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
159 ok(findloc == f->expected_loc,
160 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
161 name, id, f->needle, f->start, f->end, f->flags, findloc);
162 ok(ft.chrgText.cpMin == f->expected_loc,
163 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
164 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
165 expected_end_loc = ((f->expected_loc == -1) ? -1
166 : f->expected_loc + strlen(f->needle));
167 ok(ft.chrgText.cpMax == expected_end_loc,
168 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
169 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
172 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
177 for (i = 0; i < num_tests; i++) {
178 if (find[i]._todo_wine) {
180 check_EM_FINDTEXT(hwnd, name, &find[i], i);
181 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
184 check_EM_FINDTEXT(hwnd, name, &find[i], i);
185 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
190 static void test_EM_FINDTEXT(void)
192 HWND hwndRichEdit = new_richedit(NULL);
195 /* Empty rich edit control */
196 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
197 sizeof(find_tests)/sizeof(struct find_s));
199 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
202 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
203 sizeof(find_tests2)/sizeof(struct find_s));
205 /* Setting a format on an arbitrary range should have no effect in search
206 results. This tests correct offset reporting across runs. */
207 cf2.cbSize = sizeof(CHARFORMAT2);
208 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
210 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
211 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
212 SendMessage(hwndRichEdit, EM_SETSEL, 6, 20);
213 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
215 /* Haystack text, again */
216 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2,
217 sizeof(find_tests2)/sizeof(struct find_s));
219 /* Yet another range */
220 cf2.dwMask = CFM_BOLD | cf2.dwMask;
221 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
222 SendMessage(hwndRichEdit, EM_SETSEL, 11, 15);
223 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
225 /* Haystack text, again */
226 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2,
227 sizeof(find_tests2)/sizeof(struct find_s));
229 DestroyWindow(hwndRichEdit);
232 static const struct getline_s {
237 {0, 10, "foo bar\r"},
242 /* Buffer smaller than line length */
248 static void test_EM_GETLINE(void)
251 HWND hwndRichEdit = new_richedit(NULL);
252 static const int nBuf = 1024;
253 char dest[1024], origdest[1024];
254 const char text[] = "foo bar\n"
258 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
260 memset(origdest, 0xBB, nBuf);
261 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
264 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
265 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
266 memset(dest, 0xBB, nBuf);
267 *(WORD *) dest = gl[i].buffer_len;
269 /* EM_GETLINE appends a "\r\0" to the end of the line
270 * nCopied counts up to and including the '\r' */
271 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
272 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
274 /* two special cases since a parameter is passed via dest */
275 if (gl[i].buffer_len == 0)
276 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
278 else if (gl[i].buffer_len == 1)
279 ok(dest[0] == gl[i].text[0] && !dest[1] &&
280 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
283 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
284 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
285 ok(!strncmp(dest + expected_bytes_written, origdest
286 + expected_bytes_written, nBuf - expected_bytes_written),
287 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
291 DestroyWindow(hwndRichEdit);
294 static void test_EM_LINELENGTH(void)
296 HWND hwndRichEdit = new_richedit(NULL);
302 int offset_test[10][2] = {
317 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
319 for (i = 0; i < 10; i++) {
320 result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
321 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
322 offset_test[i][0], result, offset_test[i][1]);
325 DestroyWindow(hwndRichEdit);
328 static int get_scroll_pos_y(HWND hwnd)
331 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
332 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
336 static void move_cursor(HWND hwnd, long charindex)
339 cr.cpMax = charindex;
340 cr.cpMin = charindex;
341 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
344 static void line_scroll(HWND hwnd, int amount)
346 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
349 static void test_EM_SCROLLCARET(void)
352 HWND hwndRichEdit = new_richedit(NULL);
353 const char text[] = "aa\n"
354 "this is a long line of text that should be longer than the "
363 /* Can't verify this */
364 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
366 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
368 /* Caret above visible window */
369 line_scroll(hwndRichEdit, 3);
370 prevY = get_scroll_pos_y(hwndRichEdit);
371 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
372 curY = get_scroll_pos_y(hwndRichEdit);
373 ok(prevY != curY, "%d == %d\n", prevY, curY);
375 /* Caret below visible window */
376 move_cursor(hwndRichEdit, sizeof(text) - 1);
377 line_scroll(hwndRichEdit, -3);
378 prevY = get_scroll_pos_y(hwndRichEdit);
379 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
380 curY = get_scroll_pos_y(hwndRichEdit);
381 ok(prevY != curY, "%d == %d\n", prevY, curY);
383 /* Caret in visible window */
384 move_cursor(hwndRichEdit, sizeof(text) - 2);
385 prevY = get_scroll_pos_y(hwndRichEdit);
386 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
387 curY = get_scroll_pos_y(hwndRichEdit);
388 ok(prevY == curY, "%d != %d\n", prevY, curY);
390 /* Caret still in visible window */
391 line_scroll(hwndRichEdit, -1);
392 prevY = get_scroll_pos_y(hwndRichEdit);
393 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
394 curY = get_scroll_pos_y(hwndRichEdit);
395 ok(prevY == curY, "%d != %d\n", prevY, curY);
397 DestroyWindow(hwndRichEdit);
400 static void test_EM_SETCHARFORMAT(void)
402 HWND hwndRichEdit = new_richedit(NULL);
405 int tested_effects[] = {
418 /* Invalid flags, CHARFORMAT2 structure blanked out */
419 memset(&cf2, 0, sizeof(cf2));
420 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
422 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
424 /* A valid flag, CHARFORMAT2 structure blanked out */
425 memset(&cf2, 0, sizeof(cf2));
426 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
428 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
430 /* A valid flag, CHARFORMAT2 structure blanked out */
431 memset(&cf2, 0, sizeof(cf2));
432 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
434 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
436 /* A valid flag, CHARFORMAT2 structure blanked out */
437 memset(&cf2, 0, sizeof(cf2));
438 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
440 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
442 /* A valid flag, CHARFORMAT2 structure blanked out */
443 memset(&cf2, 0, sizeof(cf2));
444 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
446 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
448 /* Invalid flags, CHARFORMAT2 structure minimally filled */
449 memset(&cf2, 0, sizeof(cf2));
450 cf2.cbSize = sizeof(CHARFORMAT2);
451 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
453 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
455 /* A valid flag, CHARFORMAT2 structure minimally filled */
456 memset(&cf2, 0, sizeof(cf2));
457 cf2.cbSize = sizeof(CHARFORMAT2);
458 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
460 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
462 /* A valid flag, CHARFORMAT2 structure minimally filled */
463 memset(&cf2, 0, sizeof(cf2));
464 cf2.cbSize = sizeof(CHARFORMAT2);
465 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
467 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
469 /* A valid flag, CHARFORMAT2 structure minimally filled */
470 memset(&cf2, 0, sizeof(cf2));
471 cf2.cbSize = sizeof(CHARFORMAT2);
472 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
474 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
476 /* A valid flag, CHARFORMAT2 structure minimally filled */
477 memset(&cf2, 0, sizeof(cf2));
478 cf2.cbSize = sizeof(CHARFORMAT2);
479 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
481 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
483 cf2.cbSize = sizeof(CHARFORMAT2);
484 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
487 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
488 cf2.cbSize = sizeof(CHARFORMAT2);
489 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
491 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
492 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
494 /* wParam==0 is default char format, does not set modify */
495 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
496 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
497 ok(rc == 0, "Text marked as modified, expected not modified!\n");
498 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf2);
499 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
500 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
501 ok(rc == 0, "Text marked as modified, expected not modified!\n");
503 /* wParam==SCF_SELECTION sets modify if nonempty selection */
504 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
505 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
506 ok(rc == 0, "Text marked as modified, expected not modified!\n");
507 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
508 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
509 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
510 ok(rc == 0, "Text marked as modified, expected not modified!\n");
512 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
513 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
514 ok(rc == 0, "Text marked as modified, expected not modified!\n");
515 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
516 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
517 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
518 ok(rc == 0, "Text marked as modified, expected not modified!\n");
519 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
520 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
521 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
522 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
523 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
525 /* wParam==SCF_ALL sets modify regardless of whether text is present */
526 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
527 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
528 ok(rc == 0, "Text marked as modified, expected not modified!\n");
529 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
530 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
531 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
532 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
534 DestroyWindow(hwndRichEdit);
536 /* EM_GETCHARFORMAT tests */
537 for (i = 0; tested_effects[i]; i++)
539 hwndRichEdit = new_richedit(NULL);
540 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
542 memset(&cf2, 0, sizeof(CHARFORMAT2));
543 cf2.cbSize = sizeof(CHARFORMAT2);
544 cf2.dwMask = tested_effects[i];
545 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
546 cf2.dwMask = CFM_SUPERSCRIPT;
547 cf2.dwEffects = tested_effects[i];
548 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
549 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
551 memset(&cf2, 0, sizeof(CHARFORMAT2));
552 cf2.cbSize = sizeof(CHARFORMAT2);
553 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
554 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
555 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
556 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
558 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
559 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
560 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
561 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
563 memset(&cf2, 0, sizeof(CHARFORMAT2));
564 cf2.cbSize = sizeof(CHARFORMAT2);
565 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
566 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
567 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
568 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
570 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
571 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
572 ok((cf2.dwEffects & tested_effects[i]) == 0,
573 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
575 memset(&cf2, 0, sizeof(CHARFORMAT2));
576 cf2.cbSize = sizeof(CHARFORMAT2);
577 SendMessage(hwndRichEdit, EM_SETSEL, 1, 3);
578 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
579 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
580 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
582 (cf2.dwMask & tested_effects[i]) == 0),
583 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
584 ok((cf2.dwEffects & tested_effects[i]) == 0,
585 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
587 DestroyWindow(hwndRichEdit);
590 for (i = 0; tested_effects[i]; i++)
592 hwndRichEdit = new_richedit(NULL);
593 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
595 memset(&cf2, 0, sizeof(CHARFORMAT2));
596 cf2.cbSize = sizeof(CHARFORMAT2);
597 cf2.dwMask = tested_effects[i];
598 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
599 cf2.dwMask = CFM_SUPERSCRIPT;
600 cf2.dwEffects = tested_effects[i];
601 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
602 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
604 memset(&cf2, 0, sizeof(CHARFORMAT2));
605 cf2.cbSize = sizeof(CHARFORMAT2);
606 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
607 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
608 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
609 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
611 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
612 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
613 ok((cf2.dwEffects & tested_effects[i]) == 0,
614 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
616 memset(&cf2, 0, sizeof(CHARFORMAT2));
617 cf2.cbSize = sizeof(CHARFORMAT2);
618 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
619 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
620 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
621 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
623 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
624 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
625 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
626 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
628 memset(&cf2, 0, sizeof(CHARFORMAT2));
629 cf2.cbSize = sizeof(CHARFORMAT2);
630 SendMessage(hwndRichEdit, EM_SETSEL, 1, 3);
631 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
632 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
633 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
635 (cf2.dwMask & tested_effects[i]) == 0),
636 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
637 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
638 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]);
640 DestroyWindow(hwndRichEdit);
644 static void test_EM_SETTEXTMODE(void)
646 HWND hwndRichEdit = new_richedit(NULL);
647 CHARFORMAT2 cf2, cf2test;
651 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
652 /*Insert text into the control*/
654 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
656 /*Attempt to change the control to plain text mode*/
657 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
658 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
660 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
661 If rich text is pasted, it should have the same formatting as the rest
662 of the text in the control*/
665 *NOTE: If the default text was already italicized, the test will simply
666 reverse; in other words, it will copy a regular "wine" into a plain
667 text window that uses an italicized format*/
668 cf2.cbSize = sizeof(CHARFORMAT2);
669 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
672 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
673 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
675 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
676 ok(rc == 0, "Text marked as modified, expected not modified!\n");
678 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
679 however, SCF_ALL has been implemented*/
680 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
681 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
683 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
684 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
686 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
688 /*Select the string "wine"*/
691 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
693 /*Copy the italicized "wine" to the clipboard*/
694 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
696 /*Reset the formatting to default*/
697 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
698 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
699 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
701 /*Clear the text in the control*/
702 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
704 /*Switch to Plain Text Mode*/
705 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
706 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
708 /*Input "wine" again in normal format*/
709 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
711 /*Paste the italicized "wine" into the control*/
712 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
714 /*Select a character from the first "wine" string*/
717 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
719 /*Retrieve its formatting*/
720 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
723 /*Select a character from the second "wine" string*/
726 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
728 /*Retrieve its formatting*/
729 cf2test.cbSize = sizeof(CHARFORMAT2);
730 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
733 /*Compare the two formattings*/
734 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
735 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
736 cf2.dwEffects, cf2test.dwEffects);
737 /*Test TM_RICHTEXT by: switching back to Rich Text mode
738 printing "wine" in the current format(normal)
739 pasting "wine" from the clipboard(italicized)
740 comparing the two formats(should differ)*/
742 /*Attempt to switch with text in control*/
743 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
744 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
747 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
749 /*Switch into Rich Text mode*/
750 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
751 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
753 /*Print "wine" in normal formatting into the control*/
754 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
756 /*Paste italicized "wine" into the control*/
757 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
759 /*Select text from the first "wine" string*/
762 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
764 /*Retrieve its formatting*/
765 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
768 /*Select text from the second "wine" string*/
771 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
773 /*Retrieve its formatting*/
774 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
777 /*Test that the two formattings are not the same*/
778 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
779 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
780 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
782 DestroyWindow(hwndRichEdit);
785 static void test_TM_PLAINTEXT(void)
787 /*Tests plain text properties*/
789 HWND hwndRichEdit = new_richedit(NULL);
790 CHARFORMAT2 cf2, cf2test;
794 /*Switch to plain text mode*/
796 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
797 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
799 /*Fill control with text*/
801 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
803 /*Select some text and bold it*/
807 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
808 cf2.cbSize = sizeof(CHARFORMAT2);
809 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
812 cf2.dwMask = CFM_BOLD | cf2.dwMask;
813 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
815 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
816 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
818 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD | SCF_SELECTION, (LPARAM) &cf2);
819 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
821 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM)&cf2);
822 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
824 /*Get the formatting of those characters*/
826 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
828 /*Get the formatting of some other characters*/
829 cf2test.cbSize = sizeof(CHARFORMAT2);
832 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
833 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
835 /*Test that they are the same as plain text allows only one formatting*/
837 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
838 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
839 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
841 /*Fill the control with a "wine" string, which when inserted will be bold*/
843 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
845 /*Copy the bolded "wine" string*/
849 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
850 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
852 /*Swap back to rich text*/
854 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
855 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
857 /*Set the default formatting to bold italics*/
859 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
860 cf2.dwMask |= CFM_ITALIC;
861 cf2.dwEffects ^= CFE_ITALIC;
862 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
863 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
865 /*Set the text in the control to "wine", which will be bold and italicized*/
867 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
869 /*Paste the plain text "wine" string, which should take the insert
870 formatting, which at the moment is bold italics*/
872 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
874 /*Select the first "wine" string and retrieve its formatting*/
878 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
879 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
881 /*Select the second "wine" string and retrieve its formatting*/
885 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
886 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
888 /*Compare the two formattings. They should be the same.*/
890 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
891 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
892 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
893 DestroyWindow(hwndRichEdit);
896 static void test_WM_GETTEXT(void)
898 HWND hwndRichEdit = new_richedit(NULL);
899 static const char text[] = "Hello. My name is RichEdit!";
900 static const char text2[] = "Hello. My name is RichEdit!\r";
901 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
902 char buffer[1024] = {0};
905 /* Baseline test with normal-sized buffer */
906 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
907 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
908 ok(result == lstrlen(buffer),
909 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
910 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
911 result = strcmp(buffer,text);
913 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
915 /* Test for returned value of WM_GETTEXTLENGTH */
916 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
917 ok(result == lstrlen(text),
918 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
919 result, lstrlen(text));
921 /* Test for behavior in overflow case */
922 memset(buffer, 0, 1024);
923 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
925 result == lstrlenA(text) - 1, /* XP, win2k3 */
926 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
927 result = strcmp(buffer,text);
929 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
931 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
933 /* Baseline test with normal-sized buffer and carriage return */
934 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
935 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
936 ok(result == lstrlen(buffer),
937 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
938 result = strcmp(buffer,text2_after);
940 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
942 /* Test for returned value of WM_GETTEXTLENGTH */
943 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
944 ok(result == lstrlen(text2_after),
945 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
946 result, lstrlen(text2_after));
948 /* Test for behavior of CRLF conversion in case of overflow */
949 memset(buffer, 0, 1024);
950 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
952 result == lstrlenA(text2) - 1, /* XP, win2k3 */
953 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
954 result = strcmp(buffer,text2);
956 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
958 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
960 DestroyWindow(hwndRichEdit);
963 static void test_EM_GETTEXTRANGE(void)
965 HWND hwndRichEdit = new_richedit(NULL);
966 const char * text1 = "foo bar\r\nfoo bar";
967 const char * text2 = "foo bar\rfoo bar";
968 const char * expect = "bar\rfoo";
969 char buffer[1024] = {0};
971 TEXTRANGEA textRange;
973 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
975 textRange.lpstrText = buffer;
976 textRange.chrg.cpMin = 4;
977 textRange.chrg.cpMax = 11;
978 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
979 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
980 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
982 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
984 textRange.lpstrText = buffer;
985 textRange.chrg.cpMin = 4;
986 textRange.chrg.cpMax = 11;
987 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
988 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
989 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
991 DestroyWindow(hwndRichEdit);
994 static void test_EM_GETSELTEXT(void)
996 HWND hwndRichEdit = new_richedit(NULL);
997 const char * text1 = "foo bar\r\nfoo bar";
998 const char * text2 = "foo bar\rfoo bar";
999 const char * expect = "bar\rfoo";
1000 char buffer[1024] = {0};
1003 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1005 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
1006 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1007 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1008 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1010 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1012 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
1013 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1014 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1015 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1017 DestroyWindow(hwndRichEdit);
1020 /* FIXME: need to test unimplemented options and robustly test wparam */
1021 static void test_EM_SETOPTIONS(void)
1023 HWND hwndRichEdit = new_richedit(NULL);
1024 static const char text[] = "Hello. My name is RichEdit!";
1025 char buffer[1024] = {0};
1027 /* NEGATIVE TESTING - NO OPTIONS SET */
1028 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1029 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
1031 /* testing no readonly by sending 'a' to the control*/
1032 SetFocus(hwndRichEdit);
1033 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1034 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1036 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
1037 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1039 /* READONLY - sending 'a' to the control */
1040 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1041 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
1042 SetFocus(hwndRichEdit);
1043 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1044 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1045 ok(buffer[0]==text[0],
1046 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1048 DestroyWindow(hwndRichEdit);
1051 static int check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
1053 CHARFORMAT2W text_format;
1054 text_format.cbSize = sizeof(text_format);
1055 SendMessage(hwnd, EM_SETSEL, sel_start, sel_end);
1056 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
1057 return (text_format.dwEffects & CFE_LINK) ? 1 : 0;
1060 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url, const char * url)
1062 int link_present = 0;
1064 link_present = check_CFE_LINK_selection(hwnd, 0, 1);
1066 { /* control text is url; should get CFE_LINK */
1067 ok(0 != link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
1071 ok(0 == link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
1075 static HWND new_static_wnd(HWND parent) {
1076 return new_window("Static", 0, parent);
1079 static void test_EM_AUTOURLDETECT(void)
1086 {"http://www.winehq.org", 1},
1087 {"http//winehq.org", 0},
1088 {"ww.winehq.org", 0},
1089 {"www.winehq.org", 1},
1090 {"ftp://192.168.1.1", 1},
1091 {"ftp//192.168.1.1", 0},
1092 {"mailto:your@email.com", 1},
1093 {"prospero:prosperoserver", 1},
1095 {"news:newserver", 1},
1096 {"wais:waisserver", 1}
1101 HWND hwndRichEdit, parent;
1103 /* All of the following should cause the URL to be detected */
1104 const char * templates_delim[] = {
1105 "This is some text with X on it",
1106 "This is some text with (X) on it",
1107 "This is some text with X\r on it",
1108 "This is some text with ---X--- on it",
1109 "This is some text with \"X\" on it",
1110 "This is some text with 'X' on it",
1111 "This is some text with 'X' on it",
1112 "This is some text with :X: on it",
1114 "This text ends with X",
1116 "This is some text with X) on it",
1117 "This is some text with X--- on it",
1118 "This is some text with X\" on it",
1119 "This is some text with X' on it",
1120 "This is some text with X: on it",
1122 "This is some text with (X on it",
1123 "This is some text with \rX on it",
1124 "This is some text with ---X on it",
1125 "This is some text with \"X on it",
1126 "This is some text with 'X on it",
1127 "This is some text with :X on it",
1129 /* None of these should cause the URL to be detected */
1130 const char * templates_non_delim[] = {
1131 "This is some text with |X| on it",
1132 "This is some text with *X* on it",
1133 "This is some text with /X/ on it",
1134 "This is some text with +X+ on it",
1135 "This is some text with %X% on it",
1136 "This is some text with #X# on it",
1137 "This is some text with @X@ on it",
1138 "This is some text with \\X\\ on it",
1139 "This is some text with |X on it",
1140 "This is some text with *X on it",
1141 "This is some text with /X on it",
1142 "This is some text with +X on it",
1143 "This is some text with %X on it",
1144 "This is some text with #X on it",
1145 "This is some text with @X on it",
1146 "This is some text with \\X on it",
1148 /* All of these cause the URL detection to be extended by one more byte,
1149 thus demonstrating that the tested character is considered as part
1151 const char * templates_xten_delim[] = {
1152 "This is some text with X| on it",
1153 "This is some text with X* on it",
1154 "This is some text with X/ on it",
1155 "This is some text with X+ on it",
1156 "This is some text with X% on it",
1157 "This is some text with X# on it",
1158 "This is some text with X@ on it",
1159 "This is some text with X\\ on it",
1164 parent = new_static_wnd(NULL);
1165 hwndRichEdit = new_richedit(parent);
1166 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1167 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
1168 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
1169 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
1170 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
1171 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1172 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
1173 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
1174 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
1175 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
1176 /* for each url, check the text to see if CFE_LINK effect is present */
1177 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1179 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
1180 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
1181 check_CFE_LINK_rcvd(hwndRichEdit, 0, urls[i].text);
1183 /* Link detection should happen immediately upon WM_SETTEXT */
1184 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1185 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
1186 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
1188 DestroyWindow(hwndRichEdit);
1190 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1191 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1192 hwndRichEdit = new_richedit(parent);
1194 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1199 at_pos = strchr(templates_delim[j], 'X');
1200 at_offset = at_pos - templates_delim[j];
1201 strncpy(buffer, templates_delim[j], at_offset);
1202 buffer[at_offset] = '\0';
1203 strcat(buffer, urls[i].text);
1204 strcat(buffer, templates_delim[j] + at_offset + 1);
1205 end_offset = at_offset + strlen(urls[i].text);
1207 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1208 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1210 /* This assumes no templates start with the URL itself, and that they
1211 have at least two characters before the URL text */
1212 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1213 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1214 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1215 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1216 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1217 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1221 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1222 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1223 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1224 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1228 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1229 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1230 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1231 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1233 if (buffer[end_offset] != '\0')
1235 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1236 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1237 if (buffer[end_offset +1] != '\0')
1239 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1240 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1245 for (j = 0; j < sizeof(templates_non_delim) / sizeof(const char *); j++) {
1250 at_pos = strchr(templates_non_delim[j], 'X');
1251 at_offset = at_pos - templates_non_delim[j];
1252 strncpy(buffer, templates_non_delim[j], at_offset);
1253 buffer[at_offset] = '\0';
1254 strcat(buffer, urls[i].text);
1255 strcat(buffer, templates_non_delim[j] + at_offset + 1);
1256 end_offset = at_offset + strlen(urls[i].text);
1258 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1259 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1261 /* This assumes no templates start with the URL itself, and that they
1262 have at least two characters before the URL text */
1263 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1264 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1265 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1266 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1267 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1268 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1270 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1271 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1272 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1273 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1274 if (buffer[end_offset] != '\0')
1276 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1277 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1278 if (buffer[end_offset +1] != '\0')
1280 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1281 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1286 for (j = 0; j < sizeof(templates_xten_delim) / sizeof(const char *); j++) {
1291 at_pos = strchr(templates_xten_delim[j], 'X');
1292 at_offset = at_pos - templates_xten_delim[j];
1293 strncpy(buffer, templates_xten_delim[j], at_offset);
1294 buffer[at_offset] = '\0';
1295 strcat(buffer, urls[i].text);
1296 strcat(buffer, templates_xten_delim[j] + at_offset + 1);
1297 end_offset = at_offset + strlen(urls[i].text);
1299 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1300 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1302 /* This assumes no templates start with the URL itself, and that they
1303 have at least two characters before the URL text */
1304 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1305 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1306 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1307 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1308 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1309 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1313 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1314 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1315 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1316 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1317 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1318 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
1322 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1323 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1324 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1325 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1326 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1327 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
1329 if (buffer[end_offset +1] != '\0')
1331 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1332 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer);
1333 if (buffer[end_offset +2] != '\0')
1335 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
1336 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
1341 DestroyWindow(hwndRichEdit);
1342 hwndRichEdit = NULL;
1347 keybd_event('\r', 0x1c, 0, 0); \
1348 keybd_event('\r', 0x1c, KEYEVENTF_KEYUP, 0); \
1349 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
1350 TranslateMessage(&msg); \
1351 DispatchMessage(&msg); \
1357 keybd_event(0x08, 0x0e, 0, 0); \
1358 keybd_event(0x08, 0x0e, KEYEVENTF_KEYUP, 0); \
1359 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
1360 TranslateMessage(&msg); \
1361 DispatchMessage(&msg); \
1365 /* Test detection of URLs within normal text - WM_CHAR case. */
1366 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1367 hwndRichEdit = new_richedit(parent);
1369 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1375 at_pos = strchr(templates_delim[j], 'X');
1376 at_offset = at_pos - templates_delim[j];
1377 end_offset = at_offset + strlen(urls[i].text);
1379 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1380 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
1381 for (u = 0; templates_delim[j][u]; u++) {
1382 if (templates_delim[j][u] == '\r') {
1384 } else if (templates_delim[j][u] != 'X') {
1385 SendMessage(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
1387 for (v = 0; urls[i].text[v]; v++) {
1388 SendMessage(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
1392 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1393 trace("Using template: %s\n", templates_delim[j]);
1395 /* This assumes no templates start with the URL itself, and that they
1396 have at least two characters before the URL text */
1397 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1398 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1399 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1400 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1401 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1402 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1406 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1407 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1408 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1409 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1413 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1414 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1415 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1416 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1418 if (buffer[end_offset] != '\0')
1420 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1421 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1422 if (buffer[end_offset +1] != '\0')
1424 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1425 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1429 /* The following will insert a paragraph break after the first character
1430 of the URL candidate, thus breaking the URL. It is expected that the
1431 CFE_LINK attribute should break across both pieces of the URL */
1432 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
1434 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1436 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1437 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1438 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1439 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1440 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1441 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1443 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1444 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1445 /* end_offset moved because of paragraph break */
1446 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1447 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
1448 if (buffer[end_offset+1] != '\0')
1450 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
1451 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
1452 if (buffer[end_offset +2] != '\0')
1454 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
1455 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
1459 /* The following will remove the just-inserted paragraph break, thus
1460 restoring the URL */
1461 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
1463 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1465 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1466 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1467 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1468 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1469 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1470 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1474 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1475 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1476 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1477 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1481 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1482 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1483 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1484 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1486 if (buffer[end_offset] != '\0')
1488 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1489 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1490 if (buffer[end_offset +1] != '\0')
1492 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1493 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1497 DestroyWindow(hwndRichEdit);
1498 hwndRichEdit = NULL;
1501 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
1502 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1505 hwndRichEdit = new_richedit(parent);
1507 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
1509 1) Set entire text, a la WM_SETTEXT
1510 2) Set a selection of the text to the URL
1511 3) Set a portion of the text at a time, which eventually results in
1513 All of them should give equivalent results
1516 /* Set entire text in one go, like WM_SETTEXT */
1517 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1522 st.codepage = CP_ACP;
1523 st.flags = ST_DEFAULT;
1525 at_pos = strchr(templates_delim[j], 'X');
1526 at_offset = at_pos - templates_delim[j];
1527 strncpy(buffer, templates_delim[j], at_offset);
1528 buffer[at_offset] = '\0';
1529 strcat(buffer, urls[i].text);
1530 strcat(buffer, templates_delim[j] + at_offset + 1);
1531 end_offset = at_offset + strlen(urls[i].text);
1533 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1534 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) buffer);
1536 /* This assumes no templates start with the URL itself, and that they
1537 have at least two characters before the URL text */
1538 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1539 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1540 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1541 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1542 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1543 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1547 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1548 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1549 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1550 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1554 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1555 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1556 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1557 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1559 if (buffer[end_offset] != '\0')
1561 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1562 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1563 if (buffer[end_offset +1] != '\0')
1565 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1566 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1571 /* Set selection with X to the URL */
1572 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1577 at_pos = strchr(templates_delim[j], 'X');
1578 at_offset = at_pos - templates_delim[j];
1579 end_offset = at_offset + strlen(urls[i].text);
1581 st.codepage = CP_ACP;
1582 st.flags = ST_DEFAULT;
1583 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1584 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) templates_delim[j]);
1585 st.flags = ST_SELECTION;
1586 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
1587 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) urls[i].text);
1588 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1590 /* This assumes no templates start with the URL itself, and that they
1591 have at least two characters before the URL text */
1592 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1593 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1594 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1595 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1596 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1597 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1601 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1602 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1603 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1604 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1608 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1609 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1610 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1611 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1613 if (buffer[end_offset] != '\0')
1615 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1616 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1617 if (buffer[end_offset +1] != '\0')
1619 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1620 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1625 /* Set selection with X to the first character of the URL, then the rest */
1626 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1631 at_pos = strchr(templates_delim[j], 'X');
1632 at_offset = at_pos - templates_delim[j];
1633 end_offset = at_offset + strlen(urls[i].text);
1635 strcpy(buffer, "YY");
1636 buffer[0] = urls[i].text[0];
1638 st.codepage = CP_ACP;
1639 st.flags = ST_DEFAULT;
1640 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1641 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) templates_delim[j]);
1642 st.flags = ST_SELECTION;
1643 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
1644 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) buffer);
1645 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
1646 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1));
1647 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1649 /* This assumes no templates start with the URL itself, and that they
1650 have at least two characters before the URL text */
1651 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1652 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1653 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1654 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1655 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1656 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1660 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1661 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1662 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1663 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1667 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1668 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1669 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1670 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1672 if (buffer[end_offset] != '\0')
1674 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1675 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1676 if (buffer[end_offset +1] != '\0')
1678 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1679 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1684 DestroyWindow(hwndRichEdit);
1685 hwndRichEdit = NULL;
1688 DestroyWindow(parent);
1691 static void test_EM_SCROLL(void)
1694 int r; /* return value */
1695 int expr; /* expected return value */
1696 HWND hwndRichEdit = new_richedit(NULL);
1697 int y_before, y_after; /* units of lines of text */
1699 /* test a richedit box containing a single line of text */
1700 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
1702 for (i = 0; i < 4; i++) {
1703 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
1705 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
1706 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1707 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
1708 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
1709 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
1710 "(i == %d)\n", y_after, i);
1714 * test a richedit box that will scroll. There are two general
1715 * cases: the case without any long lines and the case with a long
1718 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
1720 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
1722 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
1723 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
1724 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
1725 "LONG LINE \nb\nc\nd\ne");
1726 for (j = 0; j < 12; j++) /* reset scroll position to top */
1727 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
1729 /* get first visible line */
1730 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1731 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
1733 /* get new current first visible line */
1734 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1736 ok(((r & 0xffffff00) == 0x00010000) &&
1737 ((r & 0x000000ff) != 0x00000000),
1738 "EM_SCROLL page down didn't scroll by a small positive number of "
1739 "lines (r == 0x%08x)\n", r);
1740 ok(y_after > y_before, "EM_SCROLL page down not functioning "
1741 "(line %d scrolled to line %d\n", y_before, y_after);
1745 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
1746 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1747 ok(((r & 0xffffff00) == 0x0001ff00),
1748 "EM_SCROLL page up didn't scroll by a small negative number of lines "
1749 "(r == 0x%08x)\n", r);
1750 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
1751 "%d scrolled to line %d\n", y_before, y_after);
1755 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
1757 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1759 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
1760 "(r == 0x%08x)\n", r);
1761 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
1762 "1 line (%d scrolled to %d)\n", y_before, y_after);
1766 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
1768 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1770 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
1771 "(r == 0x%08x)\n", r);
1772 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
1773 "line (%d scrolled to %d)\n", y_before, y_after);
1777 r = SendMessage(hwndRichEdit, EM_SCROLL,
1778 SB_LINEUP, 0); /* lineup beyond top */
1780 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1783 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
1784 ok(y_before == y_after,
1785 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
1789 r = SendMessage(hwndRichEdit, EM_SCROLL,
1790 SB_PAGEUP, 0);/*page up beyond top */
1792 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1795 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
1796 ok(y_before == y_after,
1797 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
1799 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
1800 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
1801 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1802 r = SendMessage(hwndRichEdit, EM_SCROLL,
1803 SB_PAGEDOWN, 0); /* page down beyond bot */
1804 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1807 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
1808 ok(y_before == y_after,
1809 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
1812 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1813 SendMessage(hwndRichEdit, EM_SCROLL,
1814 SB_LINEDOWN, 0); /* line down beyond bot */
1815 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
1818 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
1819 ok(y_before == y_after,
1820 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
1823 DestroyWindow(hwndRichEdit);
1826 static void test_EM_SETUNDOLIMIT(void)
1828 /* cases we test for:
1829 * default behaviour - limiting at 100 undo's
1830 * undo disabled - setting a limit of 0
1831 * undo limited - undo limit set to some to some number, like 2
1832 * bad input - sending a negative number should default to 100 undo's */
1834 HWND hwndRichEdit = new_richedit(NULL);
1839 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1842 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1843 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
1844 also, multiple pastes don't combine like WM_CHAR would */
1845 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1847 /* first case - check the default */
1848 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1849 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
1850 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1851 for (i=0; i<100; i++) /* Undo 100 of them */
1852 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1853 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1854 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
1856 /* second case - cannot undo */
1857 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
1858 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
1859 SendMessage(hwndRichEdit,
1860 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
1861 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1862 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
1864 /* third case - set it to an arbitrary number */
1865 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
1866 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
1867 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1868 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1869 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1870 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
1871 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
1872 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
1873 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1874 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1875 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
1876 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1877 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1878 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
1880 /* fourth case - setting negative numbers should default to 100 undos */
1881 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1882 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
1884 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
1886 DestroyWindow(hwndRichEdit);
1889 static void test_ES_PASSWORD(void)
1891 /* This isn't hugely testable, so we're just going to run it through its paces */
1893 HWND hwndRichEdit = new_richedit(NULL);
1896 /* First, check the default of a regular control */
1897 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1899 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
1901 /* Now, set it to something normal */
1902 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
1903 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1905 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1907 /* Now, set it to something odd */
1908 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
1909 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1911 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1912 DestroyWindow(hwndRichEdit);
1915 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie,
1920 char** str = (char**)dwCookie;
1923 memcpy(*str, pbBuff, *pcb);
1929 static void test_WM_SETTEXT()
1931 HWND hwndRichEdit = new_richedit(NULL);
1932 const char * TestItem1 = "TestSomeText";
1933 const char * TestItem2 = "TestSomeText\r";
1934 const char * TestItem2_after = "TestSomeText\r\n";
1935 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
1936 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
1937 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
1938 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
1939 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
1940 const char * TestItem5_after = "TestSomeText TestSomeText";
1941 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
1942 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
1943 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
1944 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
1946 char buf[1024] = {0};
1951 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
1952 any solitary \r to be converted to \r\n on return. Properly paired
1953 \r\n are not affected. It also shows that the special sequence \r\r\n
1954 gets converted to a single space.
1957 #define TEST_SETTEXT(a, b) \
1958 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
1959 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
1960 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
1961 ok (result == lstrlen(buf), \
1962 "WM_GETTEXT returned %ld instead of expected %u\n", \
1963 result, lstrlen(buf)); \
1964 result = strcmp(b, buf); \
1966 "WM_SETTEXT round trip: strcmp = %ld\n", result);
1968 TEST_SETTEXT(TestItem1, TestItem1)
1969 TEST_SETTEXT(TestItem2, TestItem2_after)
1970 TEST_SETTEXT(TestItem3, TestItem3_after)
1971 TEST_SETTEXT(TestItem3_after, TestItem3_after)
1972 TEST_SETTEXT(TestItem4, TestItem4_after)
1973 TEST_SETTEXT(TestItem5, TestItem5_after)
1974 TEST_SETTEXT(TestItem6, TestItem6_after)
1975 TEST_SETTEXT(TestItem7, TestItem7_after)
1977 /* The following test demonstrates that WM_SETTEXT supports RTF strings */
1978 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
1980 es.dwCookie = (DWORD_PTR)&p;
1982 es.pfnCallback = test_WM_SETTEXT_esCallback;
1983 memset(buf, 0, sizeof(buf));
1984 SendMessage(hwndRichEdit, EM_STREAMOUT,
1985 (WPARAM)(SF_RTF), (LPARAM)&es);
1986 trace("EM_STREAMOUT produced: \n%s\n", buf);
1987 TEST_SETTEXT(buf, TestItem1)
1990 DestroyWindow(hwndRichEdit);
1993 static void test_EM_STREAMOUT(void)
1995 HWND hwndRichEdit = new_richedit(NULL);
1998 char buf[1024] = {0};
2001 const char * TestItem1 = "TestSomeText";
2002 const char * TestItem2 = "TestSomeText\r";
2003 const char * TestItem3 = "TestSomeText\r\n";
2005 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
2007 es.dwCookie = (DWORD_PTR)&p;
2009 es.pfnCallback = test_WM_SETTEXT_esCallback;
2010 memset(buf, 0, sizeof(buf));
2011 SendMessage(hwndRichEdit, EM_STREAMOUT,
2012 (WPARAM)(SF_TEXT), (LPARAM)&es);
2014 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
2015 ok(strcmp(buf, TestItem1) == 0,
2016 "streamed text different, got %s\n", buf);
2018 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
2020 es.dwCookie = (DWORD_PTR)&p;
2022 es.pfnCallback = test_WM_SETTEXT_esCallback;
2023 memset(buf, 0, sizeof(buf));
2024 SendMessage(hwndRichEdit, EM_STREAMOUT,
2025 (WPARAM)(SF_TEXT), (LPARAM)&es);
2027 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
2028 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
2029 ok(strcmp(buf, TestItem3) == 0,
2030 "streamed text different from, got %s\n", buf);
2031 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
2033 es.dwCookie = (DWORD_PTR)&p;
2035 es.pfnCallback = test_WM_SETTEXT_esCallback;
2036 memset(buf, 0, sizeof(buf));
2037 SendMessage(hwndRichEdit, EM_STREAMOUT,
2038 (WPARAM)(SF_TEXT), (LPARAM)&es);
2040 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
2041 ok(strcmp(buf, TestItem3) == 0,
2042 "streamed text different, got %s\n", buf);
2044 DestroyWindow(hwndRichEdit);
2047 static void test_EM_SETTEXTEX(void)
2049 HWND hwndRichEdit = new_richedit(NULL);
2052 WCHAR TestItem1[] = {'T', 'e', 's', 't',
2054 'T', 'e', 'x', 't', 0};
2055 WCHAR TestItem2[] = {'T', 'e', 's', 't',
2059 const char * TestItem2_after = "TestSomeText\r\n";
2060 WCHAR TestItem3[] = {'T', 'e', 's', 't',
2063 '\r','\n','\r','\n', 0};
2064 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
2068 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
2072 WCHAR TestItem4[] = {'T', 'e', 's', 't',
2075 '\r','\r','\n','\r',
2077 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
2081 #define MAX_BUF_LEN 1024
2082 WCHAR buf[MAX_BUF_LEN];
2088 setText.codepage = 1200; /* no constant for unicode */
2089 getText.codepage = 1200; /* no constant for unicode */
2090 getText.cb = MAX_BUF_LEN;
2091 getText.flags = GT_DEFAULT;
2092 getText.lpDefaultChar = NULL;
2093 getText.lpUsedDefChar = NULL;
2096 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
2097 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2098 ok(lstrcmpW(buf, TestItem1) == 0,
2099 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
2101 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
2102 convert \r to \r\n on return
2104 setText.codepage = 1200; /* no constant for unicode */
2105 getText.codepage = 1200; /* no constant for unicode */
2106 getText.cb = MAX_BUF_LEN;
2107 getText.flags = GT_DEFAULT;
2108 getText.lpDefaultChar = NULL;
2109 getText.lpUsedDefChar = NULL;
2111 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem2);
2112 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2113 ok(lstrcmpW(buf, TestItem2) == 0,
2114 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
2116 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
2117 SendMessage(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
2118 ok(strcmp((const char *)buf, TestItem2_after) == 0,
2119 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
2121 /* Baseline test for just-enough buffer space for string */
2122 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
2123 getText.codepage = 1200; /* no constant for unicode */
2124 getText.flags = GT_DEFAULT;
2125 getText.lpDefaultChar = NULL;
2126 getText.lpUsedDefChar = NULL;
2127 memset(buf, 0, MAX_BUF_LEN);
2128 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2129 ok(lstrcmpW(buf, TestItem2) == 0,
2130 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
2132 /* When there is enough space for one character, but not both, of the CRLF
2133 pair at the end of the string, the CR is not copied at all. That is,
2134 the caller must not see CRLF pairs truncated to CR at the end of the
2137 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
2138 getText.codepage = 1200; /* no constant for unicode */
2139 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
2140 getText.lpDefaultChar = NULL;
2141 getText.lpUsedDefChar = NULL;
2142 memset(buf, 0, MAX_BUF_LEN);
2143 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2144 ok(lstrcmpW(buf, TestItem1) == 0,
2145 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
2148 /* \r\n pairs get changed into \r */
2149 setText.codepage = 1200; /* no constant for unicode */
2150 getText.codepage = 1200; /* no constant for unicode */
2151 getText.cb = MAX_BUF_LEN;
2152 getText.flags = GT_DEFAULT;
2153 getText.lpDefaultChar = NULL;
2154 getText.lpUsedDefChar = NULL;
2156 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3);
2157 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2158 ok(lstrcmpW(buf, TestItem3_after) == 0,
2159 "EM_SETTEXTEX did not convert properly\n");
2161 /* \n also gets changed to \r */
2162 setText.codepage = 1200; /* no constant for unicode */
2163 getText.codepage = 1200; /* no constant for unicode */
2164 getText.cb = MAX_BUF_LEN;
2165 getText.flags = GT_DEFAULT;
2166 getText.lpDefaultChar = NULL;
2167 getText.lpUsedDefChar = NULL;
2169 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3alt);
2170 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2171 ok(lstrcmpW(buf, TestItem3_after) == 0,
2172 "EM_SETTEXTEX did not convert properly\n");
2174 /* \r\r\n gets changed into single space */
2175 setText.codepage = 1200; /* no constant for unicode */
2176 getText.codepage = 1200; /* no constant for unicode */
2177 getText.cb = MAX_BUF_LEN;
2178 getText.flags = GT_DEFAULT;
2179 getText.lpDefaultChar = NULL;
2180 getText.lpUsedDefChar = NULL;
2182 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem4);
2183 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2184 ok(lstrcmpW(buf, TestItem4_after) == 0,
2185 "EM_SETTEXTEX did not convert properly\n");
2187 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
2188 (WPARAM)&setText, (LPARAM) NULL);
2189 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2192 "EM_SETTEXTEX returned %d, instead of 1\n",result);
2193 ok(lstrlenW(buf) == 0,
2194 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
2196 /* put some text back */
2198 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
2199 /* select some text */
2202 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
2203 /* replace current selection */
2204 setText.flags = ST_SELECTION;
2205 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
2206 (WPARAM)&setText, (LPARAM) NULL);
2208 "EM_SETTEXTEX with NULL lParam to replace selection"
2209 " with no text should return 0. Got %i\n",
2212 /* put some text back */
2214 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
2215 /* select some text */
2218 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
2219 /* replace current selection */
2220 setText.flags = ST_SELECTION;
2221 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
2222 (WPARAM)&setText, (LPARAM) TestItem1);
2224 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2225 ok(result == lstrlenW(TestItem1),
2226 "EM_SETTEXTEX with NULL lParam to replace selection"
2227 " with no text should return 0. Got %i\n",
2229 ok(lstrlenW(buf) == 22,
2230 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
2233 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
2234 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "TestSomeText"); /* TestItem1 */
2236 es.dwCookie = (DWORD_PTR)&p;
2238 es.pfnCallback = test_WM_SETTEXT_esCallback;
2239 memset(buf, 0, sizeof(buf));
2240 SendMessage(hwndRichEdit, EM_STREAMOUT,
2241 (WPARAM)(SF_RTF), (LPARAM)&es);
2242 trace("EM_STREAMOUT produced: \n%s\n", (char *)buf);
2244 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
2245 getText.codepage = 1200; /* no constant for unicode */
2246 getText.cb = MAX_BUF_LEN;
2247 getText.flags = GT_DEFAULT;
2248 getText.lpDefaultChar = NULL;
2249 getText.lpUsedDefChar = NULL;
2252 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) buf);
2253 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
2254 ok(lstrcmpW(buf, TestItem1) == 0,
2255 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
2258 DestroyWindow(hwndRichEdit);
2261 static void test_EM_LIMITTEXT(void)
2265 HWND hwndRichEdit = new_richedit(NULL);
2267 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
2268 * about setting the length to -1 for multiline edit controls doesn't happen.
2271 /* Don't check default gettextlimit case. That's done in other tests */
2273 /* Set textlimit to 100 */
2274 SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
2275 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2277 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
2279 /* Set textlimit to 0 */
2280 SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
2281 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2283 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
2285 /* Set textlimit to -1 */
2286 SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
2287 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2289 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
2291 /* Set textlimit to -2 */
2292 SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
2293 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2295 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
2297 DestroyWindow (hwndRichEdit);
2301 static void test_EM_EXLIMITTEXT(void)
2303 int i, selBegin, selEnd, len1, len2;
2305 char text[1024 + 1];
2306 char buffer[1024 + 1];
2307 int textlimit = 0; /* multiple of 100 */
2308 HWND hwndRichEdit = new_richedit(NULL);
2310 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2311 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
2314 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
2315 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2317 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
2320 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
2321 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2323 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
2325 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
2326 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2327 /* default for WParam = 0 */
2328 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
2330 textlimit = sizeof(text)-1;
2331 memset(text, 'W', textlimit);
2332 text[sizeof(text)-1] = 0;
2333 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
2334 /* maxed out text */
2335 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
2337 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
2338 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
2339 len1 = selEnd - selBegin;
2341 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
2342 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
2343 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
2344 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
2345 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
2346 len2 = selEnd - selBegin;
2349 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
2352 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
2353 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
2354 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
2355 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
2356 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
2357 len1 = selEnd - selBegin;
2360 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
2363 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
2364 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
2365 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
2366 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
2367 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
2368 len2 = selEnd - selBegin;
2371 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
2374 /* set text up to the limit, select all the text, then add a char */
2376 memset(text, 'W', textlimit);
2377 text[textlimit] = 0;
2378 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
2379 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
2380 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
2381 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
2382 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2383 result = strcmp(buffer, "A");
2384 ok(0 == result, "got string = \"%s\"\n", buffer);
2386 /* WM_SETTEXT not limited */
2388 memset(text, 'W', textlimit);
2389 text[textlimit] = 0;
2390 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
2391 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
2392 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2394 ok(10 == i, "expected 10 chars\n");
2395 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2396 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
2398 /* try inserting more text at end */
2399 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2400 ok(0 == i, "WM_CHAR wasn't processed\n");
2401 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2403 ok(10 == i, "expected 10 chars, got %i\n", i);
2404 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2405 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
2407 /* try inserting text at beginning */
2408 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
2409 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2410 ok(0 == i, "WM_CHAR wasn't processed\n");
2411 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2413 ok(10 == i, "expected 10 chars, got %i\n", i);
2414 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2415 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
2417 /* WM_CHAR is limited */
2419 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
2420 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
2421 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2422 ok(0 == i, "WM_CHAR wasn't processed\n");
2423 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2424 ok(0 == i, "WM_CHAR wasn't processed\n");
2425 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2427 ok(1 == i, "expected 1 chars, got %i instead\n", i);
2429 DestroyWindow(hwndRichEdit);
2432 static void test_EM_GETLIMITTEXT(void)
2435 HWND hwndRichEdit = new_richedit(NULL);
2437 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2438 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
2440 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
2441 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
2442 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
2444 DestroyWindow(hwndRichEdit);
2447 static void test_WM_SETFONT(void)
2449 /* There is no invalid input or error conditions for this function.
2450 * NULL wParam and lParam just fall back to their default values
2451 * It should be noted that even if you use a gibberish name for your fonts
2452 * here, it will still work because the name is stored. They will display as
2453 * System, but will report their name to be whatever they were created as */
2455 HWND hwndRichEdit = new_richedit(NULL);
2456 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
2457 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
2458 FF_DONTCARE, "Marlett");
2459 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
2460 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
2461 FF_DONTCARE, "MS Sans Serif");
2462 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
2463 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
2464 FF_DONTCARE, "Courier");
2465 LOGFONTA sentLogFont;
2466 CHARFORMAT2A returnedCF2A;
2468 returnedCF2A.cbSize = sizeof(returnedCF2A);
2470 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
2471 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
2472 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
2474 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
2475 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
2476 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
2477 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
2479 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
2480 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
2481 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
2482 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
2483 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
2484 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
2486 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
2487 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
2488 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
2489 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
2490 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
2491 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
2493 /* This last test is special since we send in NULL. We clear the variables
2494 * and just compare to "System" instead of the sent in font name. */
2495 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
2496 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
2497 returnedCF2A.cbSize = sizeof(returnedCF2A);
2499 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
2500 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
2501 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
2502 ok (!strcmp("System",returnedCF2A.szFaceName),
2503 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
2505 DestroyWindow(hwndRichEdit);
2509 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
2514 const char** str = (const char**)dwCookie;
2515 int size = strlen(*str);
2516 if(size > 3) /* let's make it piecemeal for fun */
2523 memcpy(pbBuff, *str, *pcb);
2529 static void test_EM_GETMODIFY(void)
2531 HWND hwndRichEdit = new_richedit(NULL);
2534 WCHAR TestItem1[] = {'T', 'e', 's', 't',
2536 'T', 'e', 'x', 't', 0};
2537 WCHAR TestItem2[] = {'T', 'e', 's', 't',
2539 'O', 't', 'h', 'e', 'r',
2540 'T', 'e', 'x', 't', 0};
2541 const char* streamText = "hello world";
2546 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
2547 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
2548 FF_DONTCARE, "Courier");
2550 setText.codepage = 1200; /* no constant for unicode */
2551 setText.flags = ST_KEEPUNDO;
2554 /* modify flag shouldn't be set when richedit is first created */
2555 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2557 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
2559 /* setting modify flag should actually set it */
2560 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
2561 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2563 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
2565 /* clearing modify flag should actually clear it */
2566 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2567 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2569 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
2571 /* setting font doesn't change modify flag */
2572 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2573 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
2574 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2576 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
2578 /* setting text should set modify flag */
2579 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2580 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
2581 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2583 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
2585 /* undo previous text doesn't reset modify flag */
2586 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
2587 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2589 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
2591 /* set text with no flag to keep undo stack should not set modify flag */
2592 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2594 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
2595 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2597 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
2599 /* WM_SETTEXT doesn't modify */
2600 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2601 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
2602 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2604 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
2606 /* clear the text */
2607 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2608 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
2609 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2611 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
2614 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2615 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
2616 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
2617 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
2618 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2620 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
2622 /* copy/paste text 1 */
2623 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2624 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
2625 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
2626 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
2627 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2629 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
2631 /* copy/paste text 2 */
2632 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2633 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
2634 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
2635 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
2636 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
2637 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2639 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
2642 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2643 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
2644 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2645 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2647 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
2650 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
2651 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2652 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
2653 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2655 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
2657 /* set char format */
2658 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2659 cf2.cbSize = sizeof(CHARFORMAT2);
2660 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
2662 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
2663 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
2664 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
2665 result = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
2666 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
2667 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2669 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
2671 /* set para format */
2672 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2673 pf2.cbSize = sizeof(PARAFORMAT2);
2674 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
2676 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
2677 pf2.wAlignment = PFA_RIGHT;
2678 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
2679 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2681 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
2684 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
2685 es.dwCookie = (DWORD_PTR)&streamText;
2687 es.pfnCallback = test_EM_GETMODIFY_esCallback;
2688 SendMessage(hwndRichEdit, EM_STREAMIN,
2689 (WPARAM)(SF_TEXT), (LPARAM)&es);
2690 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
2692 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
2694 DestroyWindow(hwndRichEdit);
2700 long expected_retval;
2701 int expected_getsel_start;
2702 int expected_getsel_end;
2703 int _exsetsel_todo_wine;
2704 int _getsel_todo_wine;
2707 const struct exsetsel_s exsetsel_tests[] = {
2709 {5, 10, 10, 5, 10, 0, 0},
2710 {15, 17, 17, 15, 17, 0, 0},
2711 /* test cpMax > strlen() */
2712 {0, 100, 18, 0, 18, 0, 1},
2713 /* test cpMin == cpMax */
2714 {5, 5, 5, 5, 5, 0, 0},
2715 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
2716 {-1, 0, 5, 5, 5, 0, 0},
2717 {-1, 17, 5, 5, 5, 0, 0},
2718 {-1, 18, 5, 5, 5, 0, 0},
2719 /* test cpMin < 0 && cpMax < 0 */
2720 {-1, -1, 17, 17, 17, 0, 0},
2721 {-4, -5, 17, 17, 17, 0, 0},
2722 /* test cMin >=0 && cpMax < 0 (bug 6814) */
2723 {0, -1, 18, 0, 18, 0, 1},
2724 {17, -5, 18, 17, 18, 0, 1},
2725 {18, -3, 17, 17, 17, 0, 0},
2726 /* test if cpMin > cpMax */
2727 {15, 19, 18, 15, 18, 0, 1},
2728 {19, 15, 18, 15, 18, 0, 1}
2731 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
2736 cr.cpMin = setsel->min;
2737 cr.cpMax = setsel->max;
2738 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
2740 if (setsel->_exsetsel_todo_wine) {
2742 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
2745 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
2748 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
2750 if (setsel->_getsel_todo_wine) {
2752 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);
2755 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);
2759 static void test_EM_EXSETSEL(void)
2761 HWND hwndRichEdit = new_richedit(NULL);
2763 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
2765 /* sending some text to the window */
2766 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
2767 /* 01234567890123456*/
2770 for (i = 0; i < num_tests; i++) {
2771 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
2774 DestroyWindow(hwndRichEdit);
2777 static void test_EM_REPLACESEL(int redraw)
2779 HWND hwndRichEdit = new_richedit(NULL);
2780 char buffer[1024] = {0};
2785 /* sending some text to the window */
2786 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
2787 /* 01234567890123456*/
2790 /* FIXME add more tests */
2791 SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
2792 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
2793 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
2794 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2795 r = strcmp(buffer, "testing");
2796 ok(0 == r, "expected %d, got %d\n", 0, r);
2798 DestroyWindow(hwndRichEdit);
2800 hwndRichEdit = new_richedit(NULL);
2802 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw);
2803 SendMessage(hwndRichEdit, WM_SETREDRAW, redraw, 0);
2805 /* Test behavior with carriage returns and newlines */
2806 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2807 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1");
2808 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
2809 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2810 r = strcmp(buffer, "RichEdit1");
2811 ok(0 == r, "expected %d, got %d\n", 0, r);
2813 getText.codepage = CP_ACP;
2814 getText.flags = GT_DEFAULT;
2815 getText.lpDefaultChar = NULL;
2816 getText.lpUsedDefChar = NULL;
2817 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2818 ok(strcmp(buffer, "RichEdit1") == 0,
2819 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
2821 /* Test number of lines reported after EM_REPLACESEL */
2822 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2823 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
2825 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2826 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r");
2827 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
2828 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2829 r = strcmp(buffer, "RichEdit1\r\n");
2830 ok(0 == r, "expected %d, got %d\n", 0, r);
2832 getText.codepage = CP_ACP;
2833 getText.flags = GT_DEFAULT;
2834 getText.lpDefaultChar = NULL;
2835 getText.lpUsedDefChar = NULL;
2836 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2837 ok(strcmp(buffer, "RichEdit1\r") == 0,
2838 "EM_GETTEXTEX returned incorrect string\n");
2840 /* Test number of lines reported after EM_REPLACESEL */
2841 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2842 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2844 /* Win98's riched20 and WinXP's riched20 disagree on what to return from
2845 EM_REPLACESEL. The general rule seems to be that Win98's riched20
2846 returns the number of characters *inserted* into the control (after
2847 required conversions), but WinXP's riched20 returns the number of
2848 characters interpreted from the original lParam. Wine's builtin riched20
2849 implements the WinXP behavior.
2851 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2852 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r\n");
2853 ok(11 == r /* WinXP */ || 10 == r /* Win98 */,
2854 "EM_REPLACESEL returned %d, expected 11 or 10\n", r);
2856 /* Test number of lines reported after EM_REPLACESEL */
2857 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2858 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2860 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2861 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2862 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
2863 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
2865 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2866 r = strcmp(buffer, "RichEdit1\r\n");
2867 ok(0 == r, "expected %d, got %d\n", 0, r);
2869 getText.codepage = CP_ACP;
2870 getText.flags = GT_DEFAULT;
2871 getText.lpDefaultChar = NULL;
2872 getText.lpUsedDefChar = NULL;
2873 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2874 ok(strcmp(buffer, "RichEdit1\r") == 0,
2875 "EM_GETTEXTEX returned incorrect string\n");
2877 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2878 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2879 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
2880 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
2882 /* The following tests show that richedit should handle the special \r\r\n
2883 sequence by turning it into a single space on insertion. However,
2884 EM_REPLACESEL on WinXP returns the number of characters in the original
2888 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2889 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r");
2890 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
2891 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2892 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2893 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2894 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2896 /* Test the actual string */
2898 getText.codepage = CP_ACP;
2899 getText.flags = GT_DEFAULT;
2900 getText.lpDefaultChar = NULL;
2901 getText.lpUsedDefChar = NULL;
2902 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2903 ok(strcmp(buffer, "\r\r") == 0,
2904 "EM_GETTEXTEX returned incorrect string\n");
2906 /* Test number of lines reported after EM_REPLACESEL */
2907 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2908 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
2910 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2911 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n");
2912 ok(3 == r /* WinXP */ || 1 == r /* Win98 */,
2913 "EM_REPLACESEL returned %d, expected 3 or 1\n", r);
2914 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2915 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2916 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
2917 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
2919 /* Test the actual string */
2921 getText.codepage = CP_ACP;
2922 getText.flags = GT_DEFAULT;
2923 getText.lpDefaultChar = NULL;
2924 getText.lpUsedDefChar = NULL;
2925 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2926 ok(strcmp(buffer, " ") == 0,
2927 "EM_GETTEXTEX returned incorrect string\n");
2929 /* Test number of lines reported after EM_REPLACESEL */
2930 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2931 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
2933 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2934 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r");
2935 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
2936 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
2937 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2938 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2939 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
2940 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
2942 /* Test the actual string */
2944 getText.codepage = CP_ACP;
2945 getText.flags = GT_DEFAULT;
2946 getText.lpDefaultChar = NULL;
2947 getText.lpUsedDefChar = NULL;
2948 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2949 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
2950 "EM_GETTEXTEX returned incorrect string\n");
2952 /* Test number of lines reported after EM_REPLACESEL */
2953 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2954 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
2956 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2957 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n");
2958 ok(5 == r /* WinXP */ || 2 == r /* Win98 */,
2959 "EM_REPLACESEL returned %d, expected 5 or 2\n", r);
2960 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2961 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2962 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2963 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2965 /* Test the actual string */
2967 getText.codepage = CP_ACP;
2968 getText.flags = GT_DEFAULT;
2969 getText.lpDefaultChar = NULL;
2970 getText.lpUsedDefChar = NULL;
2971 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2972 ok(strcmp(buffer, " \r") == 0,
2973 "EM_GETTEXTEX returned incorrect string\n");
2975 /* Test number of lines reported after EM_REPLACESEL */
2976 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
2977 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
2979 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2980 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r");
2981 ok(5 == r /* WinXP */ || 3 == r /* Win98 */,
2982 "EM_REPLACESEL returned %d, expected 5 or 3\n", r);
2983 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2984 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2985 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
2986 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
2988 /* Test the actual string */
2990 getText.codepage = CP_ACP;
2991 getText.flags = GT_DEFAULT;
2992 getText.lpDefaultChar = NULL;
2993 getText.lpUsedDefChar = NULL;
2994 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2995 ok(strcmp(buffer, " \r\r") == 0,
2996 "EM_GETTEXTEX returned incorrect string\n");
2998 /* Test number of lines reported after EM_REPLACESEL */
2999 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
3000 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
3002 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
3003 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r");
3004 ok(6 == r /* WinXP */ || 5 == r /* Win98 */,
3005 "EM_REPLACESEL returned %d, expected 6 or 5\n", r);
3006 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
3007 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
3008 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
3009 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
3011 /* Test the actual string */
3013 getText.codepage = CP_ACP;
3014 getText.flags = GT_DEFAULT;
3015 getText.lpDefaultChar = NULL;
3016 getText.lpUsedDefChar = NULL;
3017 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
3018 ok(strcmp(buffer, "\rX\r\r\r") == 0,
3019 "EM_GETTEXTEX returned incorrect string\n");
3021 /* Test number of lines reported after EM_REPLACESEL */
3022 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
3023 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r);
3025 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
3026 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n");
3027 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
3028 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
3029 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
3030 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
3031 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
3033 /* Test the actual string */
3035 getText.codepage = CP_ACP;
3036 getText.flags = GT_DEFAULT;
3037 getText.lpDefaultChar = NULL;
3038 getText.lpUsedDefChar = NULL;
3039 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
3040 ok(strcmp(buffer, "\r\r") == 0,
3041 "EM_GETTEXTEX returned incorrect string\n");
3043 /* Test number of lines reported after EM_REPLACESEL */
3044 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
3045 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
3047 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
3048 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n");
3049 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
3050 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
3051 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
3052 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
3053 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
3054 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
3056 /* Test the actual string */
3058 getText.codepage = CP_ACP;
3059 getText.flags = GT_DEFAULT;
3060 getText.lpDefaultChar = NULL;
3061 getText.lpUsedDefChar = NULL;
3062 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
3063 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
3064 "EM_GETTEXTEX returned incorrect string\n");
3066 /* Test number of lines reported after EM_REPLACESEL */
3067 r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
3068 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
3070 DestroyWindow(hwndRichEdit);
3073 static void test_WM_PASTE(void)
3077 char buffer[1024] = {0};
3078 char key_info[][3] =
3080 /* VirtualKey, ScanCode, WM_CHAR code */
3081 {'C', 0x2e, 3}, /* Ctrl-C */
3082 {'X', 0x2d, 24}, /* Ctrl-X */
3083 {'V', 0x2f, 22}, /* Ctrl-V */
3084 {'Z', 0x2c, 26}, /* Ctrl-Z */
3085 {'Y', 0x15, 25}, /* Ctrl-Y */
3087 const char* text1 = "testing paste\r";
3088 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
3089 const char* text1_after = "testing paste\r\n";
3090 const char* text2 = "testing paste\r\rtesting paste";
3091 const char* text2_after = "testing paste\r\n\r\ntesting paste";
3092 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
3093 HWND hwndRichEdit = new_richedit(NULL);
3095 /* Native riched20 won't obey WM_CHAR messages or WM_KEYDOWN/WM_KEYUP
3096 messages, probably because it inspects the keyboard state itself.
3097 Therefore, native requires this in order to obey Ctrl-<key> keystrokes.
3099 #define SEND_CTRL_KEY(hwnd, k) \
3100 keybd_event(VK_CONTROL, 0x1d, 0, 0);\
3101 keybd_event(k[0], k[1], 0, 0);\
3102 keybd_event(k[0], k[1], KEYEVENTF_KEYUP, 0);\
3103 keybd_event(VK_CONTROL, 0x1d, KEYEVENTF_KEYUP, 0); \
3104 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
3105 TranslateMessage(&msg); \
3106 DispatchMessage(&msg); \
3109 #define SEND_CTRL_C(hwnd) SEND_CTRL_KEY(hwnd, key_info[0])
3110 #define SEND_CTRL_X(hwnd) SEND_CTRL_KEY(hwnd, key_info[1])
3111 #define SEND_CTRL_V(hwnd) SEND_CTRL_KEY(hwnd, key_info[2])
3112 #define SEND_CTRL_Z(hwnd) SEND_CTRL_KEY(hwnd, key_info[3])
3113 #define SEND_CTRL_Y(hwnd) SEND_CTRL_KEY(hwnd, key_info[4])
3115 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
3116 SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
3118 SEND_CTRL_C(hwndRichEdit) /* Copy */
3119 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
3120 SEND_CTRL_V(hwndRichEdit) /* Paste */
3121 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3122 /* Pasted text should be visible at this step */
3123 result = strcmp(text1_step1, buffer);
3125 "test paste: strcmp = %i\n", result);
3126 SEND_CTRL_Z(hwndRichEdit) /* Undo */
3127 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3128 /* Text should be the same as before (except for \r -> \r\n conversion) */
3129 result = strcmp(text1_after, buffer);
3131 "test paste: strcmp = %i\n", result);
3133 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
3134 SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
3135 SEND_CTRL_C(hwndRichEdit) /* Copy */
3136 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
3137 SEND_CTRL_V(hwndRichEdit) /* Paste */
3138 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3139 /* Pasted text should be visible at this step */
3140 result = strcmp(text3, buffer);
3142 "test paste: strcmp = %i\n", result);
3143 SEND_CTRL_Z(hwndRichEdit) /* Undo */
3144 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3145 /* Text should be the same as before (except for \r -> \r\n conversion) */
3146 result = strcmp(text2_after, buffer);
3148 "test paste: strcmp = %i\n", result);
3149 SEND_CTRL_Y(hwndRichEdit) /* Redo */
3150 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3151 /* Text should revert to post-paste state */
3152 result = strcmp(buffer,text3);
3154 "test paste: strcmp = %i\n", result);
3156 DestroyWindow(hwndRichEdit);
3159 static void test_EM_FORMATRANGE(void)
3164 HWND hwndRichEdit = new_richedit(NULL);
3166 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
3168 hdc = GetDC(hwndRichEdit);
3169 ok(hdc != NULL, "Could not get HDC\n");
3171 fr.hdc = fr.hdcTarget = hdc;
3172 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
3173 fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
3174 fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
3178 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
3180 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
3183 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
3185 ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
3191 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
3193 ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
3196 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
3198 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
3201 DestroyWindow(hwndRichEdit);
3204 static int nCallbackCount = 0;
3206 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
3209 const char text[] = {'t','e','s','t'};
3211 if (sizeof(text) <= cb)
3213 if ((int)dwCookie != nCallbackCount)
3219 memcpy (pbBuff, text, sizeof(text));
3220 *pcb = sizeof(text);
3227 return 1; /* indicates callback failed */
3230 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
3235 const char** str = (const char**)dwCookie;
3236 int size = strlen(*str);
3242 memcpy(pbBuff, *str, *pcb);
3249 static void test_EM_STREAMIN(void)
3251 HWND hwndRichEdit = new_richedit(NULL);
3254 char buffer[1024] = {0};
3256 const char * streamText0 = "{\\rtf1 TestSomeText}";
3257 const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
3258 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
3260 const char * streamText1 =
3261 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \
3262 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \
3265 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
3266 const char * streamText2 =
3267 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \
3268 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \
3269 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \
3270 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \
3271 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \
3272 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \
3273 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
3275 const char * streamText3 = "RichEdit1";
3277 /* Minimal test without \par at the end */
3278 es.dwCookie = (DWORD_PTR)&streamText0;
3280 es.pfnCallback = test_EM_STREAMIN_esCallback;
3281 SendMessage(hwndRichEdit, EM_STREAMIN,
3282 (WPARAM)(SF_RTF), (LPARAM)&es);
3284 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3286 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
3287 result = strcmp (buffer,"TestSomeText");
3289 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
3290 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
3292 /* Native richedit 2.0 ignores last \par */
3293 es.dwCookie = (DWORD_PTR)&streamText0a;
3295 es.pfnCallback = test_EM_STREAMIN_esCallback;
3296 SendMessage(hwndRichEdit, EM_STREAMIN,
3297 (WPARAM)(SF_RTF), (LPARAM)&es);
3299 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3301 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
3302 result = strcmp (buffer,"TestSomeText");
3304 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
3305 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0);
3307 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
3308 es.dwCookie = (DWORD_PTR)&streamText0b;
3310 es.pfnCallback = test_EM_STREAMIN_esCallback;
3311 SendMessage(hwndRichEdit, EM_STREAMIN,
3312 (WPARAM)(SF_RTF), (LPARAM)&es);
3314 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3316 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
3317 result = strcmp (buffer,"TestSomeText\r\n");
3319 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
3320 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0);
3322 es.dwCookie = (DWORD_PTR)&streamText1;
3324 es.pfnCallback = test_EM_STREAMIN_esCallback;
3325 SendMessage(hwndRichEdit, EM_STREAMIN,
3326 (WPARAM)(SF_RTF), (LPARAM)&es);
3328 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3330 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
3331 result = strcmp (buffer,"TestSomeText");
3333 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
3334 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0);
3336 es.dwCookie = (DWORD_PTR)&streamText2;
3338 SendMessage(hwndRichEdit, EM_STREAMIN,
3339 (WPARAM)(SF_RTF), (LPARAM)&es);
3341 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3343 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result);
3344 ok (strlen(buffer) == 0,
3345 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
3346 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16);
3348 es.dwCookie = (DWORD_PTR)&streamText3;
3350 SendMessage(hwndRichEdit, EM_STREAMIN,
3351 (WPARAM)(SF_RTF), (LPARAM)&es);
3353 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3355 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
3356 ok (strlen(buffer) == 0,
3357 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
3358 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16);
3360 DestroyWindow(hwndRichEdit);
3363 static void test_EM_StreamIn_Undo(void)
3365 /* The purpose of this test is to determine when a EM_StreamIn should be
3366 * undoable. This is important because WM_PASTE currently uses StreamIn and
3367 * pasting should always be undoable but streaming isn't always.
3370 * StreamIn plain text without SFF_SELECTION.
3371 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
3372 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
3373 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
3374 * Feel free to add tests for other text modes or StreamIn things.
3378 HWND hwndRichEdit = new_richedit(NULL);
3381 char buffer[1024] = {0};
3382 const char randomtext[] = "Some text";
3384 es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
3386 /* StreamIn, no SFF_SELECTION */
3387 es.dwCookie = nCallbackCount;
3388 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3389 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
3390 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
3391 SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
3392 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3393 result = strcmp (buffer,"test");
3395 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
3397 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
3398 ok (result == FALSE,
3399 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
3401 /* StreamIn, SFF_SELECTION, but nothing selected */
3402 es.dwCookie = nCallbackCount;
3403 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3404 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
3405 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
3406 SendMessage(hwndRichEdit, EM_STREAMIN,
3407 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
3408 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3409 result = strcmp (buffer,"testSome text");
3411 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
3413 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
3415 "EM_STREAMIN with SFF_SELECTION but no selection set "
3416 "should create an undo\n");
3418 /* StreamIn, SFF_SELECTION, with a selection */
3419 es.dwCookie = nCallbackCount;
3420 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3421 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
3422 SendMessage(hwndRichEdit, EM_SETSEL,4,5);
3423 SendMessage(hwndRichEdit, EM_STREAMIN,
3424 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
3425 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
3426 result = strcmp (buffer,"Sometesttext");
3428 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
3430 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
3432 "EM_STREAMIN with SFF_SELECTION and selection set "
3433 "should create an undo\n");
3437 static BOOL is_em_settextex_supported(HWND hwnd)
3439 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
3440 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
3443 static void test_unicode_conversions(void)
3445 static const WCHAR tW[] = {'t',0};
3446 static const WCHAR teW[] = {'t','e',0};
3447 static const WCHAR textW[] = {'t','e','s','t',0};
3448 static const char textA[] = "test";
3452 int is_win9x, em_settextex_supported, ret;
3454 is_win9x = GetVersion() & 0x80000000;
3456 #define set_textA(hwnd, wm_set_text, txt) \
3458 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
3459 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
3460 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
3461 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
3462 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
3464 #define expect_textA(hwnd, wm_get_text, txt) \
3466 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
3467 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
3468 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
3469 memset(bufA, 0xAA, sizeof(bufA)); \
3470 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
3471 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
3472 ret = lstrcmpA(bufA, txt); \
3473 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
3476 #define set_textW(hwnd, wm_set_text, txt) \
3478 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
3479 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
3480 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
3481 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
3482 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
3484 #define expect_textW(hwnd, wm_get_text, txt) \
3486 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
3487 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
3488 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
3489 memset(bufW, 0xAA, sizeof(bufW)); \
3492 assert(wm_get_text == EM_GETTEXTEX); \
3493 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
3494 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
3498 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
3499 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
3501 ret = lstrcmpW(bufW, txt); \
3502 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
3504 #define expect_empty(hwnd, wm_get_text) \
3506 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
3507 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
3508 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
3509 memset(bufA, 0xAA, sizeof(bufA)); \
3510 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
3511 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
3512 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
3515 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
3516 0, 0, 200, 60, 0, 0, 0, 0);
3517 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3519 ret = IsWindowUnicode(hwnd);
3521 ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
3523 ok(ret, "RichEdit20W should be unicode under NT\n");
3525 /* EM_SETTEXTEX is supported starting from version 3.0 */
3526 em_settextex_supported = is_em_settextex_supported(hwnd);
3527 trace("EM_SETTEXTEX is %ssupported on this platform\n",
3528 em_settextex_supported ? "" : "NOT ");
3530 expect_empty(hwnd, WM_GETTEXT);
3531 expect_empty(hwnd, EM_GETTEXTEX);
3533 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
3534 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
3535 expect_textA(hwnd, WM_GETTEXT, "t");
3536 expect_textA(hwnd, EM_GETTEXTEX, "t");
3537 expect_textW(hwnd, EM_GETTEXTEX, tW);
3539 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
3540 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
3541 expect_textA(hwnd, WM_GETTEXT, "te");
3542 expect_textA(hwnd, EM_GETTEXTEX, "te");
3543 expect_textW(hwnd, EM_GETTEXTEX, teW);
3545 set_textA(hwnd, WM_SETTEXT, NULL);
3546 expect_empty(hwnd, WM_GETTEXT);
3547 expect_empty(hwnd, EM_GETTEXTEX);
3550 set_textA(hwnd, WM_SETTEXT, textW);
3552 set_textA(hwnd, WM_SETTEXT, textA);
3553 expect_textA(hwnd, WM_GETTEXT, textA);
3554 expect_textA(hwnd, EM_GETTEXTEX, textA);
3555 expect_textW(hwnd, EM_GETTEXTEX, textW);
3557 if (em_settextex_supported)
3559 set_textA(hwnd, EM_SETTEXTEX, textA);
3560 expect_textA(hwnd, WM_GETTEXT, textA);
3561 expect_textA(hwnd, EM_GETTEXTEX, textA);
3562 expect_textW(hwnd, EM_GETTEXTEX, textW);
3567 set_textW(hwnd, WM_SETTEXT, textW);
3568 expect_textW(hwnd, WM_GETTEXT, textW);
3569 expect_textA(hwnd, WM_GETTEXT, textA);
3570 expect_textW(hwnd, EM_GETTEXTEX, textW);
3571 expect_textA(hwnd, EM_GETTEXTEX, textA);
3573 if (em_settextex_supported)
3575 set_textW(hwnd, EM_SETTEXTEX, textW);
3576 expect_textW(hwnd, WM_GETTEXT, textW);
3577 expect_textA(hwnd, WM_GETTEXT, textA);
3578 expect_textW(hwnd, EM_GETTEXTEX, textW);
3579 expect_textA(hwnd, EM_GETTEXTEX, textA);
3582 DestroyWindow(hwnd);
3584 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
3585 0, 0, 200, 60, 0, 0, 0, 0);
3586 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3588 ret = IsWindowUnicode(hwnd);
3589 ok(!ret, "RichEdit20A should NOT be unicode\n");
3591 set_textA(hwnd, WM_SETTEXT, textA);
3592 expect_textA(hwnd, WM_GETTEXT, textA);
3593 expect_textA(hwnd, EM_GETTEXTEX, textA);
3594 expect_textW(hwnd, EM_GETTEXTEX, textW);
3596 if (em_settextex_supported)
3598 set_textA(hwnd, EM_SETTEXTEX, textA);
3599 expect_textA(hwnd, WM_GETTEXT, textA);
3600 expect_textA(hwnd, EM_GETTEXTEX, textA);
3601 expect_textW(hwnd, EM_GETTEXTEX, textW);
3606 set_textW(hwnd, WM_SETTEXT, textW);
3607 expect_textW(hwnd, WM_GETTEXT, textW);
3608 expect_textA(hwnd, WM_GETTEXT, textA);
3609 expect_textW(hwnd, EM_GETTEXTEX, textW);
3610 expect_textA(hwnd, EM_GETTEXTEX, textA);
3612 if (em_settextex_supported)
3614 set_textW(hwnd, EM_SETTEXTEX, textW);
3615 expect_textW(hwnd, WM_GETTEXT, textW);
3616 expect_textA(hwnd, WM_GETTEXT, textA);
3617 expect_textW(hwnd, EM_GETTEXTEX, textW);
3618 expect_textA(hwnd, EM_GETTEXTEX, textA);
3621 DestroyWindow(hwnd);
3624 static void test_WM_CHAR(void)
3628 const char * char_list = "abc\rabc\r";
3629 const char * expected_content_single = "abcabc";
3630 const char * expected_content_multi = "abc\r\nabc\r\n";
3631 char buffer[64] = {0};
3634 /* single-line control must IGNORE carriage returns */
3635 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
3636 0, 0, 200, 60, 0, 0, 0, 0);
3637 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3640 while (*p != '\0') {
3641 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
3642 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
3643 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
3644 SendMessageA(hwnd, WM_KEYUP, *p, 1);
3648 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
3649 ret = strcmp(buffer, expected_content_single);
3650 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
3652 DestroyWindow(hwnd);
3654 /* multi-line control inserts CR normally */
3655 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
3656 0, 0, 200, 60, 0, 0, 0, 0);
3657 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3660 while (*p != '\0') {
3661 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
3662 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
3663 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
3664 SendMessageA(hwnd, WM_KEYUP, *p, 1);
3668 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
3669 ret = strcmp(buffer, expected_content_multi);
3670 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
3672 DestroyWindow(hwnd);
3675 static void test_EM_GETTEXTLENGTHEX(void)
3678 GETTEXTLENGTHEX gtl;
3680 const char * base_string = "base string";
3681 const char * test_string = "a\nb\n\n\r\n";
3682 const char * test_string_after = "a";
3683 const char * test_string_2 = "a\rtest\rstring";
3684 char buffer[64] = {0};
3687 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
3688 0, 0, 200, 60, 0, 0, 0, 0);
3689 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3691 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3692 gtl.codepage = CP_ACP;
3693 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3694 ok(ret == 0, "ret %d\n",ret);
3696 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3697 gtl.codepage = CP_ACP;
3698 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3699 ok(ret == 0, "ret %d\n",ret);
3701 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
3703 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3704 gtl.codepage = CP_ACP;
3705 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3706 ok(ret == strlen(base_string), "ret %d\n",ret);
3708 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3709 gtl.codepage = CP_ACP;
3710 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3711 ok(ret == strlen(base_string), "ret %d\n",ret);
3713 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
3715 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3716 gtl.codepage = CP_ACP;
3717 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3718 ok(ret == 1, "ret %d\n",ret);
3720 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3721 gtl.codepage = CP_ACP;
3722 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3723 ok(ret == 1, "ret %d\n",ret);
3725 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
3726 ret = strcmp(buffer, test_string_after);
3727 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
3729 DestroyWindow(hwnd);
3732 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
3733 0, 0, 200, 60, 0, 0, 0, 0);
3734 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
3736 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3737 gtl.codepage = CP_ACP;
3738 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3739 ok(ret == 0, "ret %d\n",ret);
3741 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3742 gtl.codepage = CP_ACP;
3743 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3744 ok(ret == 0, "ret %d\n",ret);
3746 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
3748 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3749 gtl.codepage = CP_ACP;
3750 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3751 ok(ret == strlen(base_string), "ret %d\n",ret);
3753 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3754 gtl.codepage = CP_ACP;
3755 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3756 ok(ret == strlen(base_string), "ret %d\n",ret);
3758 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string_2);
3760 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3761 gtl.codepage = CP_ACP;
3762 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3763 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
3765 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3766 gtl.codepage = CP_ACP;
3767 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3768 ok(ret == strlen(test_string_2), "ret %d\n",ret);
3770 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
3772 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
3773 gtl.codepage = CP_ACP;
3774 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3775 ok(ret == 10, "ret %d\n",ret);
3777 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
3778 gtl.codepage = CP_ACP;
3779 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
3780 ok(ret == 6, "ret %d\n",ret);
3782 DestroyWindow(hwnd);
3786 /* globals that parent and child access when checking event masks & notifications */
3787 static HWND eventMaskEditHwnd = 0;
3788 static int queriedEventMask;
3789 static int watchForEventMask = 0;
3791 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
3792 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3794 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
3796 queriedEventMask = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
3798 return DefWindowProcA(hwnd, message, wParam, lParam);
3801 /* test event masks in combination with WM_COMMAND */
3802 static void test_eventMask(void)
3807 const char text[] = "foo bar\n";
3810 /* register class to capture WM_COMMAND */
3812 cls.lpfnWndProc = ParentMsgCheckProcA;
3815 cls.hInstance = GetModuleHandleA(0);
3817 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3818 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3819 cls.lpszMenuName = NULL;
3820 cls.lpszClassName = "EventMaskParentClass";
3821 if(!RegisterClassA(&cls)) assert(0);
3823 parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
3824 0, 0, 200, 60, NULL, NULL, NULL, NULL);
3825 ok (parent != 0, "Failed to create parent window\n");
3827 eventMaskEditHwnd = new_richedit(parent);
3828 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
3830 eventMask = ENM_CHANGE | ENM_UPDATE;
3831 ret = SendMessage(eventMaskEditHwnd, EM_SETEVENTMASK, 0, (LPARAM) eventMask);
3832 ok(ret == ENM_NONE, "wrong event mask\n");
3833 ret = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
3834 ok(ret == eventMask, "failed to set event mask\n");
3836 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
3837 queriedEventMask = 0; /* initialize to something other than we expect */
3838 watchForEventMask = EN_CHANGE;
3839 ret = SendMessage(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM) text);
3840 ok(ret == TRUE, "failed to set text\n");
3841 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
3842 notification in response to WM_SETTEXT */
3843 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
3844 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
3848 static int received_WM_NOTIFY = 0;
3849 static int modify_at_WM_NOTIFY = 0;
3850 static HWND hwndRichedit_WM_NOTIFY;
3852 static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3854 if(message == WM_NOTIFY)
3856 received_WM_NOTIFY = 1;
3857 modify_at_WM_NOTIFY = SendMessage(hwndRichedit_WM_NOTIFY, EM_GETMODIFY, 0, 0);
3859 return DefWindowProcA(hwnd, message, wParam, lParam);
3862 static void test_WM_NOTIFY(void)
3868 /* register class to capture WM_NOTIFY */
3870 cls.lpfnWndProc = WM_NOTIFY_ParentMsgCheckProcA;
3873 cls.hInstance = GetModuleHandleA(0);
3875 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3876 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3877 cls.lpszMenuName = NULL;
3878 cls.lpszClassName = "WM_NOTIFY_ParentClass";
3879 if(!RegisterClassA(&cls)) assert(0);
3881 parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
3882 0, 0, 200, 60, NULL, NULL, NULL, NULL);
3883 ok (parent != 0, "Failed to create parent window\n");
3885 hwndRichedit_WM_NOTIFY = new_richedit(parent);
3886 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n");
3888 SendMessage(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_SELCHANGE);
3890 /* Notifications for selection change should only be sent when selection
3891 actually changes. EM_SETCHARFORMAT is one message that calls
3892 ME_CommitUndo, which should check whether message should be sent */
3893 received_WM_NOTIFY = 0;
3894 cf2.cbSize = sizeof(CHARFORMAT2);
3895 SendMessage(hwndRichedit_WM_NOTIFY, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
3897 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
3898 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
3899 SendMessage(hwndRichedit_WM_NOTIFY, EM_SETCHARFORMAT, 0, (LPARAM) &cf2);
3900 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
3902 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
3904 received_WM_NOTIFY = 0;
3905 modify_at_WM_NOTIFY = 0;
3906 SendMessage(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext");
3907 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
3908 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
3910 received_WM_NOTIFY = 0;
3911 modify_at_WM_NOTIFY = 0;
3912 SendMessage(hwndRichedit_WM_NOTIFY, EM_SETSEL, 4, 4);
3913 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
3915 received_WM_NOTIFY = 0;
3916 modify_at_WM_NOTIFY = 0;
3917 SendMessage(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext");
3918 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
3919 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
3921 DestroyWindow(hwndRichedit_WM_NOTIFY);
3922 DestroyWindow(parent);
3925 START_TEST( editor )
3930 /* Must explicitly LoadLibrary(). The test has no references to functions in
3931 * RICHED20.DLL, so the linker doesn't actually link to it. */
3932 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
3933 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
3937 test_EM_SCROLLCARET();
3940 test_EM_LINELENGTH();
3941 test_EM_SETCHARFORMAT();
3942 test_EM_SETTEXTMODE();
3943 test_TM_PLAINTEXT();
3944 test_EM_SETOPTIONS();
3946 test_EM_GETTEXTRANGE();
3947 test_EM_GETSELTEXT();
3948 test_EM_SETUNDOLIMIT();
3950 test_EM_SETTEXTEX();
3951 test_EM_LIMITTEXT();
3952 test_EM_EXLIMITTEXT();
3953 test_EM_GETLIMITTEXT();
3955 test_EM_GETMODIFY();
3958 test_EM_AUTOURLDETECT();
3960 test_EM_STREAMOUT();
3961 test_EM_StreamIn_Undo();
3962 test_EM_FORMATRANGE();
3963 test_unicode_conversions();
3964 test_EM_GETTEXTLENGTHEX();
3965 test_EM_REPLACESEL(1);
3966 test_EM_REPLACESEL(0);
3970 /* Set the environment variable WINETEST_RICHED20 to keep windows
3971 * responsive and open for 30 seconds. This is useful for debugging.
3973 * The message pump uses PeekMessage() to empty the queue and then sleeps for
3974 * 50ms before retrying the queue. */
3975 end = time(NULL) + 30;
3976 if (getenv( "WINETEST_RICHED20" )) {
3977 while (time(NULL) < end) {
3978 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
3979 TranslateMessage(&msg);
3980 DispatchMessage(&msg);
3987 OleFlushClipboard();
3988 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());