2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include <wine/test.h>
35 static HMODULE hmoduleRichEdit;
37 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
39 hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
40 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
41 hmoduleRichEdit, NULL);
42 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
46 static HWND new_richedit(HWND parent) {
47 return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
50 static const char haystack[] = "WINEWine wineWine wine WineWine";
63 struct find_s find_tests[] = {
64 /* Find in empty text */
65 {0, -1, "foo", FR_DOWN, -1, 0},
66 {0, -1, "foo", 0, -1, 0},
67 {0, -1, "", FR_DOWN, -1, 0},
68 {20, 5, "foo", FR_DOWN, -1, 0},
69 {5, 20, "foo", FR_DOWN, -1, 0}
72 struct find_s find_tests2[] = {
74 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
75 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
77 /* Subsequent finds */
78 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
79 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
80 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
81 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
84 {19, 20, "Wine", FR_MATCHCASE, 13, 0},
85 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
86 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
88 /* Case-insensitive */
89 {1, 31, "wInE", FR_DOWN, 4, 0},
90 {1, 31, "Wine", FR_DOWN, 4, 0},
92 /* High-to-low ranges */
93 {20, 5, "Wine", FR_DOWN, -1, 0},
94 {2, 1, "Wine", FR_DOWN, -1, 0},
95 {30, 29, "Wine", FR_DOWN, -1, 0},
96 {20, 5, "Wine", 0, 13, 0},
99 {5, 10, "", FR_DOWN, -1, 0},
100 {10, 5, "", FR_DOWN, -1, 0},
101 {0, -1, "", FR_DOWN, -1, 0},
102 {10, 5, "", 0, -1, 0},
104 /* Whole-word search */
105 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
106 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
107 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
108 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
109 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
110 {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
111 {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
114 {5, 200, "XXX", FR_DOWN, -1, 0},
115 {-20, 20, "Wine", FR_DOWN, -1, 0},
116 {-20, 20, "Wine", FR_DOWN, -1, 0},
117 {-15, -20, "Wine", FR_DOWN, -1, 0},
118 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
120 /* Check the case noted in bug 4479 where matches at end aren't recognized */
121 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
122 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
123 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
124 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
125 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
127 /* The backwards case of bug 4479; bounds look right
128 * Fails because backward find is wrong */
129 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
130 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
133 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
136 memset(&ft, 0, sizeof(ft));
137 ft.chrg.cpMin = f->start;
138 ft.chrg.cpMax = f->end;
139 ft.lpstrText = f->needle;
140 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
141 ok(findloc == f->expected_loc,
142 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
143 name, id, f->needle, f->start, f->end, f->flags, findloc);
146 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
150 memset(&ft, 0, sizeof(ft));
151 ft.chrg.cpMin = f->start;
152 ft.chrg.cpMax = f->end;
153 ft.lpstrText = f->needle;
154 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
155 ok(findloc == f->expected_loc,
156 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
157 name, id, f->needle, f->start, f->end, f->flags, findloc);
158 ok(ft.chrgText.cpMin == f->expected_loc,
159 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
160 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
161 ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
162 : f->expected_loc + strlen(f->needle)),
163 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d\n",
164 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
167 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
172 for (i = 0; i < num_tests; i++) {
173 if (find[i]._todo_wine) {
175 check_EM_FINDTEXT(hwnd, name, &find[i], i);
176 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
179 check_EM_FINDTEXT(hwnd, name, &find[i], i);
180 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
185 static void test_EM_FINDTEXT(void)
187 HWND hwndRichEdit = new_richedit(NULL);
189 /* Empty rich edit control */
190 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
191 sizeof(find_tests)/sizeof(struct find_s));
193 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
196 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
197 sizeof(find_tests2)/sizeof(struct find_s));
199 DestroyWindow(hwndRichEdit);
202 static const struct getline_s {
207 {0, 10, "foo bar\r"},
212 /* Buffer smaller than line length */
218 static void test_EM_GETLINE(void)
221 HWND hwndRichEdit = new_richedit(NULL);
222 static const int nBuf = 1024;
223 char dest[1024], origdest[1024];
224 const char text[] = "foo bar\n"
228 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
230 memset(origdest, 0xBB, nBuf);
231 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
234 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
235 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
236 memset(dest, 0xBB, nBuf);
237 *(WORD *) dest = gl[i].buffer_len;
239 /* EM_GETLINE appends a "\r\0" to the end of the line
240 * nCopied counts up to and including the '\r' */
241 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
242 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
244 /* two special cases since a parameter is passed via dest */
245 if (gl[i].buffer_len == 0)
246 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
248 else if (gl[i].buffer_len == 1)
249 ok(dest[0] == gl[i].text[0] && !dest[1] &&
250 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
253 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
254 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
255 ok(!strncmp(dest + expected_bytes_written, origdest
256 + expected_bytes_written, nBuf - expected_bytes_written),
257 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
261 DestroyWindow(hwndRichEdit);
264 static int get_scroll_pos_y(HWND hwnd)
267 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
268 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
272 static void move_cursor(HWND hwnd, long charindex)
275 cr.cpMax = charindex;
276 cr.cpMin = charindex;
277 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
280 static void line_scroll(HWND hwnd, int amount)
282 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
285 static void test_EM_SCROLLCARET(void)
288 HWND hwndRichEdit = new_richedit(NULL);
289 const char text[] = "aa\n"
290 "this is a long line of text that should be longer than the "
299 /* Can't verify this */
300 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
302 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
304 /* Caret above visible window */
305 line_scroll(hwndRichEdit, 3);
306 prevY = get_scroll_pos_y(hwndRichEdit);
307 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
308 curY = get_scroll_pos_y(hwndRichEdit);
309 ok(prevY != curY, "%d == %d\n", prevY, curY);
311 /* Caret below visible window */
312 move_cursor(hwndRichEdit, sizeof(text) - 1);
313 line_scroll(hwndRichEdit, -3);
314 prevY = get_scroll_pos_y(hwndRichEdit);
315 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
316 curY = get_scroll_pos_y(hwndRichEdit);
317 ok(prevY != curY, "%d == %d\n", prevY, curY);
319 /* Caret in visible window */
320 move_cursor(hwndRichEdit, sizeof(text) - 2);
321 prevY = get_scroll_pos_y(hwndRichEdit);
322 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
323 curY = get_scroll_pos_y(hwndRichEdit);
324 ok(prevY == curY, "%d != %d\n", prevY, curY);
326 /* Caret still in visible window */
327 line_scroll(hwndRichEdit, -1);
328 prevY = get_scroll_pos_y(hwndRichEdit);
329 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
330 curY = get_scroll_pos_y(hwndRichEdit);
331 ok(prevY == curY, "%d != %d\n", prevY, curY);
333 DestroyWindow(hwndRichEdit);
336 static void test_EM_SETTEXTMODE(void)
338 HWND hwndRichEdit = new_richedit(NULL);
339 CHARFORMAT2 cf2, cf2test;
343 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
344 /*Insert text into the control*/
346 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
348 /*Attempt to change the control to plain text mode*/
349 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
350 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
352 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
353 If rich text is pasted, it should have the same formatting as the rest
354 of the text in the control*/
357 *NOTE: If the default text was already italicized, the test will simply
358 reverse; in other words, it will copy a regular "wine" into a plain
359 text window that uses an italicized format*/
360 cf2.cbSize = sizeof(CHARFORMAT2);
361 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
364 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
365 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
367 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
368 however, SCF_ALL has been implemented*/
369 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
370 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
372 /*Select the string "wine"*/
375 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
377 /*Copy the italicized "wine" to the clipboard*/
378 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
380 /*Reset the formatting to default*/
381 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
382 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
384 /*Clear the text in the control*/
385 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
387 /*Switch to Plain Text Mode*/
388 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
389 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
391 /*Input "wine" again in normal format*/
392 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
394 /*Paste the italicized "wine" into the control*/
395 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
397 /*Select a character from the first "wine" string*/
400 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
402 /*Retrieve its formatting*/
403 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
406 /*Select a character from the second "wine" string*/
409 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
411 /*Retrieve its formatting*/
412 cf2test.cbSize = sizeof(CHARFORMAT2);
413 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
416 /*Compare the two formattings*/
417 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
418 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
419 cf2.dwEffects, cf2test.dwEffects);
420 /*Test TM_RICHTEXT by: switching back to Rich Text mode
421 printing "wine" in the current format(normal)
422 pasting "wine" from the clipboard(italicized)
423 comparing the two formats(should differ)*/
425 /*Attempt to switch with text in control*/
426 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
427 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
430 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
432 /*Switch into Rich Text mode*/
433 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
434 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
436 /*Print "wine" in normal formatting into the control*/
437 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
439 /*Paste italicized "wine" into the control*/
440 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
442 /*Select text from the first "wine" string*/
445 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
447 /*Retrieve its formatting*/
448 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
451 /*Select text from the second "wine" string*/
454 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
456 /*Retrieve its formatting*/
457 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
460 /*Test that the two formattings are not the same*/
461 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
462 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
463 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
465 DestroyWindow(hwndRichEdit);
468 static void test_TM_PLAINTEXT(void)
470 /*Tests plain text properties*/
472 HWND hwndRichEdit = new_richedit(NULL);
473 CHARFORMAT2 cf2, cf2test;
476 /*Switch to plain text mode*/
478 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
479 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
481 /*Fill control with text*/
483 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
485 /*Select some text and bold it*/
489 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
490 cf2.cbSize = sizeof(CHARFORMAT2);
491 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
494 cf2.dwMask = CFM_BOLD | cf2.dwMask;
495 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
497 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
499 /*Get the formatting of those characters*/
501 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
503 /*Get the formatting of some other characters*/
504 cf2test.cbSize = sizeof(CHARFORMAT2);
507 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
508 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
510 /*Test that they are the same as plain text allows only one formatting*/
512 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
513 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
514 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
516 /*Fill the control with a "wine" string, which when inserted will be bold*/
518 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
520 /*Copy the bolded "wine" string*/
524 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
525 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
527 /*Swap back to rich text*/
529 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
530 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
532 /*Set the default formatting to bold italics*/
534 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
535 cf2.dwMask |= CFM_ITALIC;
536 cf2.dwEffects ^= CFE_ITALIC;
537 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
539 /*Set the text in the control to "wine", which will be bold and italicized*/
541 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
543 /*Paste the plain text "wine" string, which should take the insert
544 formatting, which at the moment is bold italics*/
546 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
548 /*Select the first "wine" string and retrieve its formatting*/
552 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
553 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
555 /*Select the second "wine" string and retrieve its formatting*/
559 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
560 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
562 /*Compare the two formattings. They should be the same.*/
564 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
565 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
566 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
567 DestroyWindow(hwndRichEdit);
570 static void test_WM_GETTEXT(void)
572 HWND hwndRichEdit = new_richedit(NULL);
573 static const char text[] = "Hello. My name is RichEdit!";
574 char buffer[1024] = {0};
577 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
578 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
579 result = strcmp(buffer,text);
581 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
582 DestroyWindow(hwndRichEdit);
585 /* FIXME: need to test unimplemented options and robustly test wparam */
586 static void test_EM_SETOPTIONS(void)
588 HWND hwndRichEdit = new_richedit(NULL);
589 static const char text[] = "Hello. My name is RichEdit!";
590 char buffer[1024] = {0};
592 /* NEGATIVE TESTING - NO OPTIONS SET */
593 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
594 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
596 /* testing no readonly by sending 'a' to the control*/
597 SetFocus(hwndRichEdit);
598 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
599 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
601 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
602 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
604 /* READONLY - sending 'a' to the control */
605 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
606 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
607 SetFocus(hwndRichEdit);
608 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
609 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
610 ok(buffer[0]==text[0],
611 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
613 DestroyWindow(hwndRichEdit);
616 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
618 CHARFORMAT2W text_format;
619 int link_present = 0;
620 text_format.cbSize = sizeof(text_format);
621 SendMessage(hwnd, EM_SETSEL, 0, 0);
622 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
623 link_present = text_format.dwEffects & CFE_LINK;
625 { /* control text is url; should get CFE_LINK */
626 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
630 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
634 static HWND new_static_wnd(HWND parent) {
635 return new_window("Static", 0, parent);
638 static void test_EM_AUTOURLDETECT(void)
645 {"http://www.winehq.org", 1},
646 {"http//winehq.org", 0},
647 {"ww.winehq.org", 0},
648 {"www.winehq.org", 1},
649 {"ftp://192.168.1.1", 1},
650 {"ftp//192.168.1.1", 0},
651 {"mailto:your@email.com", 1},
652 {"prospero:prosperoserver", 1},
654 {"news:newserver", 1},
655 {"wais:waisserver", 1}
660 HWND hwndRichEdit, parent;
662 parent = new_static_wnd(NULL);
663 hwndRichEdit = new_richedit(parent);
664 /* Try and pass EM_AUTOURLDETECT some test wParam values */
665 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
666 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
667 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
668 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
669 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
670 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
671 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
672 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
673 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
674 /* for each url, check the text to see if CFE_LINK effect is present */
675 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
676 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
677 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
678 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
679 check_CFE_LINK_rcvd(hwndRichEdit, 0);
680 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
681 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
682 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
683 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
685 DestroyWindow(hwndRichEdit);
686 DestroyWindow(parent);
689 static void test_EM_SCROLL(void)
692 int r; /* return value */
693 int expr; /* expected return value */
694 HWND hwndRichEdit = new_richedit(NULL);
695 int y_before, y_after; /* units of lines of text */
697 /* test a richedit box containing a single line of text */
698 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
700 for (i = 0; i < 4; i++) {
701 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
703 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
704 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
705 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
706 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
707 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
708 "(i == %d)\n", y_after, i);
712 * test a richedit box that will scroll. There are two general
713 * cases: the case without any long lines and the case with a long
716 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
718 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
720 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
721 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
722 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
723 "LONG LINE \nb\nc\nd\ne");
724 for (j = 0; j < 12; j++) /* reset scrol position to top */
725 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
727 /* get first visible line */
728 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
729 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
731 /* get new current first visible line */
732 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
734 ok(((r & 0xffffff00) == 0x00010000) &&
735 ((r & 0x000000ff) != 0x00000000),
736 "EM_SCROLL page down didn't scroll by a small positive number of "
737 "lines (r == 0x%08x)\n", r);
738 ok(y_after > y_before, "EM_SCROLL page down not functioning "
739 "(line %d scrolled to line %d\n", y_before, y_after);
743 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
744 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
745 ok(((r & 0xffffff00) == 0x0001ff00),
746 "EM_SCROLL page up didn't scroll by a small negative number of lines "
747 "(r == 0x%08x)\n", r);
748 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
749 "%d scrolled to line %d\n", y_before, y_after);
753 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
755 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
757 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
758 "(r == 0x%08x)\n", r);
759 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
760 "1 line (%d scrolled to %d)\n", y_before, y_after);
764 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
766 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
768 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
769 "(r == 0x%08x)\n", r);
770 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
771 "line (%d scrolled to %d)\n", y_before, y_after);
775 r = SendMessage(hwndRichEdit, EM_SCROLL,
776 SB_LINEUP, 0); /* lineup beyond top */
778 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
781 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
782 ok(y_before == y_after,
783 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
787 r = SendMessage(hwndRichEdit, EM_SCROLL,
788 SB_PAGEUP, 0);/*page up beyond top */
790 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
793 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
794 ok(y_before == y_after,
795 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
797 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
798 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
799 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
800 r = SendMessage(hwndRichEdit, EM_SCROLL,
801 SB_PAGEDOWN, 0); /* page down beyond bot */
802 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
805 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
806 ok(y_before == y_after,
807 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
810 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
811 SendMessage(hwndRichEdit, EM_SCROLL,
812 SB_LINEDOWN, 0); /* line down beyond bot */
813 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
816 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
817 ok(y_before == y_after,
818 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
821 DestroyWindow(hwndRichEdit);
824 static void test_EM_SETUNDOLIMIT(void)
826 /* cases we test for:
827 * default behaviour - limiting at 100 undo's
828 * undo disabled - setting a limit of 0
829 * undo limited - undo limit set to some to some number, like 2
830 * bad input - sending a negative number should default to 100 undo's */
832 HWND hwndRichEdit = new_richedit(NULL);
837 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
840 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
841 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
842 also, multiple pastes don't combine like WM_CHAR would */
843 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
845 /* first case - check the default */
846 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
847 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
848 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
849 for (i=0; i<100; i++) /* Undo 100 of them */
850 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
851 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
852 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
854 /* second case - cannot undo */
855 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
856 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
857 SendMessage(hwndRichEdit,
858 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
859 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
860 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
862 /* third case - set it to an arbitrary number */
863 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
864 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
865 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
866 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
867 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
868 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
869 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
870 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
871 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
872 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
873 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
874 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
875 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
876 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
878 /* fourth case - setting negative numbers should default to 100 undos */
879 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
880 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
882 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
884 DestroyWindow(hwndRichEdit);
887 static void test_ES_PASSWORD(void)
889 /* This isn't hugely testable, so we're just going to run it through its paces */
891 HWND hwndRichEdit = new_richedit(NULL);
894 /* First, check the default of a regular control */
895 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
897 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
899 /* Now, set it to something normal */
900 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
901 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
903 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
905 /* Now, set it to something odd */
906 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
907 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
909 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
910 DestroyWindow(hwndRichEdit);
913 static void test_WM_SETTEXT()
915 HWND hwndRichEdit = new_richedit(NULL);
916 const char * TestItem1 = "TestSomeText";
917 const char * TestItem2 = "TestSomeText\r";
918 const char * TestItem2_after = "TestSomeText\r\n";
919 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
920 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
921 char buf[1024] = {0};
924 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
925 any solitary \r to be converted to \r\n on return. Properly paired
926 \r\n are not affected.
929 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
930 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result);
931 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf);
932 ok (result == strlen(buf),
933 "WM_GETTEXT returned %ld instead of expected %u\n",
934 result, strlen(buf));
935 result = strcmp(TestItem1, buf);
937 "WM_SETTEXT round trip: strcmp = %ld\n", result);
939 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
940 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result);
941 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf);
942 ok (result == strlen(buf),
943 "WM_GETTEXT returned %ld instead of expected %u\n",
944 result, strlen(buf));
945 result = strcmp(TestItem2_after, buf);
947 "WM_SETTEXT round trip: strcmp = %ld\n", result);
949 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
950 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result);
951 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf);
952 ok (result == strlen(buf),
953 "WM_GETTEXT returned %ld instead of expected %u\n",
954 result, strlen(buf));
955 result = strcmp(TestItem3_after, buf);
957 "WM_SETTEXT round trip: strcmp = %ld\n", result);
959 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3_after);
960 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result);
961 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf);
962 ok (result == strlen(buf),
963 "WM_GETTEXT returned %ld instead of expected %u\n",
964 result, strlen(buf));
965 result = strcmp(TestItem3_after, buf);
967 "WM_SETTEXT round trip: strcmp = %ld\n", result);
969 DestroyWindow(hwndRichEdit);
972 static void test_EM_SETTEXTEX(void)
974 HWND hwndRichEdit = new_richedit(NULL);
977 WCHAR TestItem1[] = {'T', 'e', 's', 't',
979 'T', 'e', 'x', 't', 0};
980 WCHAR TestItem2[] = {'T', 'e', 's', 't',
984 const char * TestItem2_after = "TestSomeText\r\n";
985 #define MAX_BUF_LEN 1024
986 WCHAR buf[MAX_BUF_LEN];
990 setText.codepage = 1200; /* no constant for unicode */
991 getText.codepage = 1200; /* no constant for unicode */
992 getText.cb = MAX_BUF_LEN;
993 getText.flags = GT_DEFAULT;
996 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
997 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
998 ok(lstrcmpW(buf, TestItem1) == 0,
999 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1001 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
1002 convert \r to \r\n on return
1004 setText.codepage = 1200; /* no constant for unicode */
1005 getText.codepage = 1200; /* no constant for unicode */
1006 getText.cb = MAX_BUF_LEN;
1007 getText.flags = GT_DEFAULT;
1010 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem2);
1011 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1012 ok(lstrcmpW(buf, TestItem2) == 0,
1013 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1015 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
1016 SendMessage(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
1017 ok(strcmp((const char *)buf, TestItem2_after) == 0,
1018 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
1020 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1021 (WPARAM)&setText, (LPARAM) NULL);
1022 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1025 "EM_SETTEXTEX returned %d, instead of 1\n",result);
1026 ok(lstrlenW(buf) == 0,
1027 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
1029 /* put some text back */
1031 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1032 /* select some text */
1035 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1036 /* replace current selection */
1037 setText.flags = ST_SELECTION;
1038 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1039 (WPARAM)&setText, (LPARAM) NULL);
1041 "EM_SETTEXTEX with NULL lParam to replace selection"
1042 " with no text should return 0. Got %i\n",
1045 /* put some text back */
1047 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1048 /* select some text */
1051 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1052 /* replace current selection */
1053 setText.flags = ST_SELECTION;
1054 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1055 (WPARAM)&setText, (LPARAM) TestItem1);
1057 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1058 ok(result == lstrlenW(TestItem1),
1059 "EM_SETTEXTEX with NULL lParam to replace selection"
1060 " with no text should return 0. Got %i\n",
1062 ok(lstrlenW(buf) == 22,
1063 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
1066 DestroyWindow(hwndRichEdit);
1069 static void test_EM_LIMITTEXT(void)
1073 HWND hwndRichEdit = new_richedit(NULL);
1075 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
1076 * about setting the length to -1 for multiline edit controls doesn't happen.
1079 /* Don't check default gettextlimit case. That's done in other tests */
1081 /* Set textlimit to 100 */
1082 SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
1083 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1085 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
1087 /* Set textlimit to 0 */
1088 SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
1089 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1091 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
1093 /* Set textlimit to -1 */
1094 SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
1095 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1097 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
1099 /* Set textlimit to -2 */
1100 SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
1101 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1103 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
1105 DestroyWindow (hwndRichEdit);
1109 static void test_EM_EXLIMITTEXT(void)
1111 int i, selBegin, selEnd, len1, len2;
1113 char text[1024 + 1];
1114 char buffer[1024 + 1];
1115 int textlimit = 0; /* multiple of 100 */
1116 HWND hwndRichEdit = new_richedit(NULL);
1118 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1119 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
1122 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1123 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1125 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1128 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1129 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1131 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1133 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1134 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1135 /* default for WParam = 0 */
1136 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1138 textlimit = sizeof(text)-1;
1139 memset(text, 'W', textlimit);
1140 text[sizeof(text)-1] = 0;
1141 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1142 /* maxed out text */
1143 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1145 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1146 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1147 len1 = selEnd - selBegin;
1149 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1150 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1151 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1152 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1153 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1154 len2 = selEnd - selBegin;
1157 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1160 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1161 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1162 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1163 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1164 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1165 len1 = selEnd - selBegin;
1168 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1171 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1172 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1173 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1174 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1175 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1176 len2 = selEnd - selBegin;
1179 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1182 /* set text up to the limit, select all the text, then add a char */
1184 memset(text, 'W', textlimit);
1185 text[textlimit] = 0;
1186 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1187 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1188 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1189 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1190 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1191 result = strcmp(buffer, "A");
1192 ok(0 == result, "got string = \"%s\"\n", buffer);
1194 /* WM_SETTEXT not limited */
1196 memset(text, 'W', textlimit);
1197 text[textlimit] = 0;
1198 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
1199 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1200 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1202 ok(10 == i, "expected 10 chars\n");
1203 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1204 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1206 /* try inserting more text at end */
1207 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1208 ok(0 == i, "WM_CHAR wasn't processed");
1209 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1211 ok(10 == i, "expected 10 chars, got %i\n", i);
1212 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1213 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1215 /* try inserting text at beginning */
1216 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
1217 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1218 ok(0 == i, "WM_CHAR wasn't processed");
1219 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1221 ok(10 == i, "expected 10 chars, got %i\n", i);
1222 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1223 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1225 /* WM_CHAR is limited */
1227 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1228 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1229 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1230 ok(0 == i, "WM_CHAR wasn't processed");
1231 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1232 ok(0 == i, "WM_CHAR wasn't processed");
1233 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1235 ok(1 == i, "expected 1 chars, got %i instead\n", i);
1237 DestroyWindow(hwndRichEdit);
1240 static void test_EM_GETLIMITTEXT(void)
1243 HWND hwndRichEdit = new_richedit(NULL);
1245 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1246 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1248 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1249 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1250 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1252 DestroyWindow(hwndRichEdit);
1255 static void test_WM_SETFONT(void)
1257 /* There is no invalid input or error conditions for this function.
1258 * NULL wParam and lParam just fall back to their default values
1259 * It should be noted that even if you use a gibberish name for your fonts
1260 * here, it will still work because the name is stored. They will display as
1261 * System, but will report their name to be whatever they were created as */
1263 HWND hwndRichEdit = new_richedit(NULL);
1264 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1265 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1266 FF_DONTCARE, "Marlett");
1267 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1268 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1269 FF_DONTCARE, "MS Sans Serif");
1270 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1271 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1272 FF_DONTCARE, "Courier");
1273 LOGFONTA sentLogFont;
1274 CHARFORMAT2A returnedCF2A;
1276 returnedCF2A.cbSize = sizeof(returnedCF2A);
1278 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1279 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1280 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1282 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1283 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1284 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1285 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1287 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1288 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1289 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1290 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1291 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1292 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1294 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1295 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1296 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1297 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1298 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1299 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1301 /* This last test is special since we send in NULL. We clear the variables
1302 * and just compare to "System" instead of the sent in font name. */
1303 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1304 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1305 returnedCF2A.cbSize = sizeof(returnedCF2A);
1307 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1308 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1309 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1310 ok (!strcmp("System",returnedCF2A.szFaceName),
1311 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1313 DestroyWindow(hwndRichEdit);
1317 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1322 const char** str = (const char**)dwCookie;
1323 int size = strlen(*str);
1324 if(size > 3) /* let's make it peice-meal for fun */
1331 memcpy(pbBuff, *str, *pcb);
1337 static void test_EM_GETMODIFY(void)
1339 HWND hwndRichEdit = new_richedit(NULL);
1342 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1344 'T', 'e', 'x', 't', 0};
1345 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1347 'O', 't', 'h', 'e', 'r',
1348 'T', 'e', 'x', 't', 0};
1349 const char* streamText = "hello world";
1354 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1355 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1356 FF_DONTCARE, "Courier");
1358 setText.codepage = 1200; /* no constant for unicode */
1359 setText.flags = ST_KEEPUNDO;
1362 /* modify flag shouldn't be set when richedit is first created */
1363 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1365 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1367 /* setting modify flag should actually set it */
1368 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1369 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1371 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1373 /* clearing modify flag should actually clear it */
1374 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1375 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1377 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1379 /* setting font doesn't change modify flag */
1380 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1381 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1382 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1384 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1386 /* setting text should set modify flag */
1387 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1388 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1389 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1391 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1393 /* undo previous text doesn't reset modify flag */
1394 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1395 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1397 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1399 /* set text with no flag to keep undo stack should not set modify flag */
1400 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1402 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1403 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1405 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1407 /* WM_SETTEXT doesn't modify */
1408 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1409 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1410 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1413 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1416 /* clear the text */
1417 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1418 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1419 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1421 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1424 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1425 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1426 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1427 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1428 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1430 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1432 /* copy/paste text 1 */
1433 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1434 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1435 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1436 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1437 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1439 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1441 /* copy/paste text 2 */
1442 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1443 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1444 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1445 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1446 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1447 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1449 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1452 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1453 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1454 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1455 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1457 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1460 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1461 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1462 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
1463 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1465 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1467 /* set char format */
1468 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1469 cf2.cbSize = sizeof(CHARFORMAT2);
1470 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1472 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1473 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1474 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1475 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1477 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1479 /* set para format */
1480 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1481 pf2.cbSize = sizeof(PARAFORMAT2);
1482 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1484 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1485 pf2.wAlignment = PFA_RIGHT;
1486 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1487 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1489 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1492 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1493 es.dwCookie = (DWORD_PTR)&streamText;
1495 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1496 SendMessage(hwndRichEdit, EM_STREAMIN,
1497 (WPARAM)(SF_TEXT), (LPARAM)&es);
1498 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1500 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1502 DestroyWindow(hwndRichEdit);
1508 long expected_retval;
1509 int expected_getsel_start;
1510 int expected_getsel_end;
1511 int _exsetsel_todo_wine;
1512 int _getsel_todo_wine;
1515 const struct exsetsel_s exsetsel_tests[] = {
1517 {5, 10, 10, 5, 10, 0, 0},
1518 {15, 17, 17, 15, 17, 0, 0},
1519 /* test cpMax > strlen() */
1520 {0, 100, 18, 0, 18, 0, 1},
1521 /* test cpMin == cpMax */
1522 {5, 5, 5, 5, 5, 0, 0},
1523 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1524 {-1, 0, 5, 5, 5, 0, 0},
1525 {-1, 17, 5, 5, 5, 0, 0},
1526 {-1, 18, 5, 5, 5, 0, 0},
1527 /* test cpMin < 0 && cpMax < 0 */
1528 {-1, -1, 17, 17, 17, 0, 0},
1529 {-4, -5, 17, 17, 17, 0, 0},
1530 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1531 {0, -1, 18, 0, 18, 0, 1},
1532 {17, -5, 18, 17, 18, 0, 1},
1533 {18, -3, 17, 17, 17, 0, 0},
1534 /* test if cpMin > cpMax */
1535 {15, 19, 18, 15, 18, 0, 1},
1536 {19, 15, 18, 15, 18, 0, 1}
1539 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1544 cr.cpMin = setsel->min;
1545 cr.cpMax = setsel->max;
1546 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1548 if (setsel->_exsetsel_todo_wine) {
1550 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1553 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1556 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1558 if (setsel->_getsel_todo_wine) {
1560 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);
1563 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);
1567 static void test_EM_EXSETSEL(void)
1569 HWND hwndRichEdit = new_richedit(NULL);
1571 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1573 /* sending some text to the window */
1574 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1575 /* 01234567890123456*/
1578 for (i = 0; i < num_tests; i++) {
1579 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1582 DestroyWindow(hwndRichEdit);
1585 static void test_EM_REPLACESEL(void)
1587 HWND hwndRichEdit = new_richedit(NULL);
1588 char buffer[1024] = {0};
1591 /* sending some text to the window */
1592 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1593 /* 01234567890123456*/
1596 /* FIXME add more tests */
1597 SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
1598 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
1599 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1600 r = strcmp(buffer, "testing");
1601 ok(0 == r, "expected %d, got %d\n", 0, r);
1603 DestroyWindow(hwndRichEdit);
1606 static void test_WM_PASTE(void)
1609 char buffer[1024] = {0};
1610 const char* text1 = "testing paste\r";
1611 const char* text1_after = "testing paste\r\n";
1612 const char* text2 = "testing paste\r\rtesting paste";
1613 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
1614 HWND hwndRichEdit = new_richedit(NULL);
1616 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
1617 SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
1618 SendMessage(hwndRichEdit, WM_CHAR, 3, 0); /* ctrl-c */
1619 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
1620 SendMessage(hwndRichEdit, WM_CHAR, 22, 0); /* ctrl-v */
1621 SendMessage(hwndRichEdit, WM_CHAR, 26, 0); /* ctrl-z */
1622 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1623 result = strcmp(text1_after, buffer);
1625 "test paste: strcmp = %i\n", result);
1627 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
1628 SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
1629 SendMessage(hwndRichEdit, WM_CHAR, 3, 0); /* ctrl-c */
1630 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
1631 SendMessage(hwndRichEdit, WM_CHAR, 22, 0); /* ctrl-v */
1632 SendMessage(hwndRichEdit, WM_CHAR, 26, 0); /* ctrl-z */
1633 SendMessage(hwndRichEdit, WM_CHAR, 25, 0); /* ctrl-y */
1634 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1635 result = strcmp(buffer,text3);
1637 "test paste: strcmp = %i\n", result);
1639 DestroyWindow(hwndRichEdit);
1642 static void test_EM_FORMATRANGE(void)
1647 HWND hwndRichEdit = new_richedit(NULL);
1649 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
1651 hdc = GetDC(hwndRichEdit);
1652 ok(hdc != NULL, "Could not get HDC\n");
1654 fr.hdc = fr.hdcTarget = hdc;
1655 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
1656 fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
1657 fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
1661 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
1663 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
1666 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
1668 ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
1674 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
1676 ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
1679 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
1681 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
1684 DestroyWindow(hwndRichEdit);
1687 static int nCallbackCount = 0;
1689 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
1692 const char text[] = {'t','e','s','t'};
1694 if (sizeof(text) <= cb)
1696 if ((int)dwCookie != nCallbackCount)
1702 memcpy (pbBuff, text, sizeof(text));
1703 *pcb = sizeof(text);
1710 return 1; /* indicates callback failed */
1713 static void test_EM_StreamIn_Undo(void)
1715 /* The purpose of this test is to determine when a EM_StreamIn should be
1716 * undoable. This is important because WM_PASTE currently uses StreamIn and
1717 * pasting should always be undoable but streaming isn't always.
1720 * StreamIn plain text without SFF_SELECTION.
1721 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
1722 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
1723 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
1724 * Feel free to add tests for other text modes or StreamIn things.
1728 HWND hwndRichEdit = new_richedit(NULL);
1731 char buffer[1024] = {0};
1732 const char randomtext[] = "Some text";
1734 es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
1736 /* StreamIn, no SFF_SELECTION */
1737 es.dwCookie = nCallbackCount;
1738 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1739 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1740 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
1741 SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
1742 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1743 result = strcmp (buffer,"test");
1745 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
1747 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1748 ok (result == FALSE,
1749 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
1751 /* StreamIn, SFF_SELECTION, but nothing selected */
1752 es.dwCookie = nCallbackCount;
1753 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1754 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1755 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
1756 SendMessage(hwndRichEdit, EM_STREAMIN,
1757 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
1758 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1759 result = strcmp (buffer,"testSome text");
1761 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
1763 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1765 "EM_STREAMIN with SFF_SELECTION but no selection set "
1766 "should create an undo\n");
1768 /* StreamIn, SFF_SELECTION, with a selection */
1769 es.dwCookie = nCallbackCount;
1770 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1771 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1772 SendMessage(hwndRichEdit, EM_SETSEL,4,5);
1773 SendMessage(hwndRichEdit, EM_STREAMIN,
1774 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
1775 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1776 result = strcmp (buffer,"Sometesttext");
1778 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
1780 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1782 "EM_STREAMIN with SFF_SELECTION and selection set "
1783 "should create an undo\n");
1787 static BOOL is_em_settextex_supported(HWND hwnd)
1789 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
1790 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
1793 static void test_unicode_conversions(void)
1795 static const WCHAR tW[] = {'t',0};
1796 static const WCHAR teW[] = {'t','e',0};
1797 static const WCHAR textW[] = {'t','e','s','t',0};
1798 static const char textA[] = "test";
1802 int is_win9x, em_settextex_supported, ret;
1804 is_win9x = GetVersion() & 0x80000000;
1806 #define set_textA(hwnd, wm_set_text, txt) \
1808 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
1809 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1810 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1811 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1812 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
1814 #define expect_textA(hwnd, wm_get_text, txt) \
1816 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1817 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1818 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1819 memset(bufA, 0xAA, sizeof(bufA)); \
1820 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1821 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1822 ret = lstrcmpA(bufA, txt); \
1823 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
1826 #define set_textW(hwnd, wm_set_text, txt) \
1828 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
1829 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1830 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1831 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1832 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
1834 #define expect_textW(hwnd, wm_get_text, txt) \
1836 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
1837 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1838 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1839 memset(bufW, 0xAA, sizeof(bufW)); \
1842 assert(wm_get_text == EM_GETTEXTEX); \
1843 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1844 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1848 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1849 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
1851 ret = lstrcmpW(bufW, txt); \
1852 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
1854 #define expect_empty(hwnd, wm_get_text) \
1856 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1857 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1858 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1859 memset(bufA, 0xAA, sizeof(bufA)); \
1860 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1861 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
1862 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
1865 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
1866 0, 0, 200, 60, 0, 0, 0, 0);
1867 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1869 ret = IsWindowUnicode(hwnd);
1871 ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
1873 ok(ret, "RichEdit20W should be unicode under NT\n");
1875 /* EM_SETTEXTEX is supported starting from version 3.0 */
1876 em_settextex_supported = is_em_settextex_supported(hwnd);
1877 trace("EM_SETTEXTEX is %ssupported on this platform\n",
1878 em_settextex_supported ? "" : "NOT ");
1880 expect_empty(hwnd, WM_GETTEXT);
1881 expect_empty(hwnd, EM_GETTEXTEX);
1883 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
1884 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
1885 expect_textA(hwnd, WM_GETTEXT, "t");
1886 expect_textA(hwnd, EM_GETTEXTEX, "t");
1887 expect_textW(hwnd, EM_GETTEXTEX, tW);
1889 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
1890 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
1891 expect_textA(hwnd, WM_GETTEXT, "te");
1892 expect_textA(hwnd, EM_GETTEXTEX, "te");
1893 expect_textW(hwnd, EM_GETTEXTEX, teW);
1895 set_textA(hwnd, WM_SETTEXT, NULL);
1896 expect_empty(hwnd, WM_GETTEXT);
1897 expect_empty(hwnd, EM_GETTEXTEX);
1900 set_textA(hwnd, WM_SETTEXT, textW);
1902 set_textA(hwnd, WM_SETTEXT, textA);
1903 expect_textA(hwnd, WM_GETTEXT, textA);
1904 expect_textA(hwnd, EM_GETTEXTEX, textA);
1905 expect_textW(hwnd, EM_GETTEXTEX, textW);
1907 if (em_settextex_supported)
1909 set_textA(hwnd, EM_SETTEXTEX, textA);
1910 expect_textA(hwnd, WM_GETTEXT, textA);
1911 expect_textA(hwnd, EM_GETTEXTEX, textA);
1912 expect_textW(hwnd, EM_GETTEXTEX, textW);
1917 set_textW(hwnd, WM_SETTEXT, textW);
1918 expect_textW(hwnd, WM_GETTEXT, textW);
1919 expect_textA(hwnd, WM_GETTEXT, textA);
1920 expect_textW(hwnd, EM_GETTEXTEX, textW);
1921 expect_textA(hwnd, EM_GETTEXTEX, textA);
1923 if (em_settextex_supported)
1925 set_textW(hwnd, EM_SETTEXTEX, textW);
1926 expect_textW(hwnd, WM_GETTEXT, textW);
1927 expect_textA(hwnd, WM_GETTEXT, textA);
1928 expect_textW(hwnd, EM_GETTEXTEX, textW);
1929 expect_textA(hwnd, EM_GETTEXTEX, textA);
1932 DestroyWindow(hwnd);
1934 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
1935 0, 0, 200, 60, 0, 0, 0, 0);
1936 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1938 ret = IsWindowUnicode(hwnd);
1939 ok(!ret, "RichEdit20A should NOT be unicode\n");
1941 set_textA(hwnd, WM_SETTEXT, textA);
1942 expect_textA(hwnd, WM_GETTEXT, textA);
1943 expect_textA(hwnd, EM_GETTEXTEX, textA);
1944 expect_textW(hwnd, EM_GETTEXTEX, textW);
1946 if (em_settextex_supported)
1948 set_textA(hwnd, EM_SETTEXTEX, textA);
1949 expect_textA(hwnd, WM_GETTEXT, textA);
1950 expect_textA(hwnd, EM_GETTEXTEX, textA);
1951 expect_textW(hwnd, EM_GETTEXTEX, textW);
1956 set_textW(hwnd, WM_SETTEXT, textW);
1957 expect_textW(hwnd, WM_GETTEXT, textW);
1958 expect_textA(hwnd, WM_GETTEXT, textA);
1959 expect_textW(hwnd, EM_GETTEXTEX, textW);
1960 expect_textA(hwnd, EM_GETTEXTEX, textA);
1962 if (em_settextex_supported)
1964 set_textW(hwnd, EM_SETTEXTEX, textW);
1965 expect_textW(hwnd, WM_GETTEXT, textW);
1966 expect_textA(hwnd, WM_GETTEXT, textA);
1967 expect_textW(hwnd, EM_GETTEXTEX, textW);
1968 expect_textA(hwnd, EM_GETTEXTEX, textA);
1971 DestroyWindow(hwnd);
1975 static void test_EM_GETTEXTLENGTHEX(void)
1978 GETTEXTLENGTHEX gtl;
1982 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
1983 0, 0, 200, 60, 0, 0, 0, 0);
1984 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1986 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1987 gtl.codepage = CP_ACP;
1988 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
1989 ok(ret == 0, "ret %d\n",ret);
1991 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
1992 gtl.codepage = CP_ACP;
1993 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
1994 ok(ret == 0, "ret %d\n",ret);
1996 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) "a\nb\n\n\r\n");
1998 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1999 gtl.codepage = CP_ACP;
2000 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2001 todo_wine ok(ret == 1, "ret %d\n",ret);
2003 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2004 gtl.codepage = CP_ACP;
2005 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2006 todo_wine ok(ret == 1, "ret %d\n",ret);
2008 DestroyWindow(hwnd);
2011 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
2012 0, 0, 200, 60, 0, 0, 0, 0);
2013 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2015 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2016 gtl.codepage = CP_ACP;
2017 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2018 todo_wine ok(ret == 0, "ret %d\n",ret);
2020 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2021 gtl.codepage = CP_ACP;
2022 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2023 ok(ret == 0, "ret %d\n",ret);
2025 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) "a\nb\n\n\r\n");
2027 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2028 gtl.codepage = CP_ACP;
2029 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2030 todo_wine ok(ret == 10, "ret %d\n",ret);
2032 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2033 gtl.codepage = CP_ACP;
2034 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0);
2035 ok(ret == 6, "ret %d\n",ret);
2037 DestroyWindow(hwnd);
2041 /* globals that parent and child access when checking event masks & notifications */
2042 static HWND eventMaskEditHwnd = 0;
2043 static int queriedEventMask;
2044 static int watchForEventMask = 0;
2046 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
2047 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2049 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
2051 queriedEventMask = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2053 return DefWindowProcA(hwnd, message, wParam, lParam);
2056 /* test event masks in combination with WM_COMMAND */
2057 static void test_eventMask(void)
2062 const char text[] = "foo bar\n";
2065 /* register class to capture WM_COMMAND */
2067 cls.lpfnWndProc = ParentMsgCheckProcA;
2070 cls.hInstance = GetModuleHandleA(0);
2072 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2073 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2074 cls.lpszMenuName = NULL;
2075 cls.lpszClassName = "EventMaskParentClass";
2076 if(!RegisterClassA(&cls)) assert(0);
2078 parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
2079 0, 0, 200, 60, NULL, NULL, NULL, NULL);
2080 ok (parent != 0, "Failed to create parent window\n");
2082 eventMaskEditHwnd = new_richedit(parent);
2083 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
2085 eventMask = ENM_CHANGE | ENM_UPDATE;
2086 ret = SendMessage(eventMaskEditHwnd, EM_SETEVENTMASK, 0, (LPARAM) eventMask);
2087 ok(ret == ENM_NONE, "wrong event mask\n");
2088 ret = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2089 ok(ret == eventMask, "failed to set event mask\n");
2091 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
2092 queriedEventMask = 0; /* initialize to something other than we expect */
2093 watchForEventMask = EN_CHANGE;
2094 ret = SendMessage(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM) text);
2095 ok(ret == TRUE, "failed to set text\n");
2096 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
2097 notification in response to WM_SETTEXT */
2098 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
2099 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
2104 START_TEST( editor )
2109 /* Must explicitly LoadLibrary(). The test has no references to functions in
2110 * RICHED20.DLL, so the linker doesn't actually link to it. */
2111 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
2112 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
2116 test_EM_SCROLLCARET();
2119 test_EM_SETTEXTMODE();
2120 test_TM_PLAINTEXT();
2121 test_EM_SETOPTIONS();
2123 test_EM_AUTOURLDETECT();
2124 test_EM_SETUNDOLIMIT();
2126 test_EM_SETTEXTEX();
2127 test_EM_LIMITTEXT();
2128 test_EM_EXLIMITTEXT();
2129 test_EM_GETLIMITTEXT();
2131 test_EM_GETMODIFY();
2134 test_EM_StreamIn_Undo();
2135 test_EM_FORMATRANGE();
2136 test_unicode_conversions();
2137 test_EM_GETTEXTLENGTHEX();
2138 test_EM_REPLACESEL();
2141 /* Set the environment variable WINETEST_RICHED20 to keep windows
2142 * responsive and open for 30 seconds. This is useful for debugging.
2144 * The message pump uses PeekMessage() to empty the queue and then sleeps for
2145 * 50ms before retrying the queue. */
2146 end = time(NULL) + 30;
2147 if (getenv( "WINETEST_RICHED20" )) {
2148 while (time(NULL) < end) {
2149 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
2150 TranslateMessage(&msg);
2151 DispatchMessage(&msg);
2158 OleFlushClipboard();
2159 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());