riched20: Do not pass NULL lParam to ME_ToUnicode for EM_REPLACESEL.
[wine/hacks.git] / dlls / riched20 / tests / editor.c
bloba1407b7e6ec62a499114b675a22d3d092d59dd5e
1 /*
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
23 #include <stdarg.h>
24 #include <assert.h>
25 #include <windef.h>
26 #include <winbase.h>
27 #include <wingdi.h>
28 #include <winuser.h>
29 #include <winnls.h>
30 #include <ole2.h>
31 #include <richedit.h>
32 #include <time.h>
33 #include <wine/test.h>
35 static HMODULE hmoduleRichEdit;
37 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
38 HWND hwnd;
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());
43 return hwnd;
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";
51 /* ^0 ^10 ^20 ^30 */
53 struct find_s {
54 int start;
55 int end;
56 const char *needle;
57 int flags;
58 int expected_loc;
59 int _todo_wine;
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[] = {
73 /* No-result find */
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},
83 /* Find backwards */
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},
98 /* Find nothing */
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},
113 /* Bad ranges */
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) {
134 int findloc;
135 FINDTEXT ft;
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,
147 int id) {
148 int findloc;
149 FINDTEXTEX ft;
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,
168 int num_tests)
170 int i;
172 for (i = 0; i < num_tests; i++) {
173 if (find[i]._todo_wine) {
174 todo_wine {
175 check_EM_FINDTEXT(hwnd, name, &find[i], i);
176 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
178 } else {
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);
195 /* Haystack text */
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 {
203 int line;
204 size_t buffer_len;
205 const char *text;
206 } gl[] = {
207 {0, 10, "foo bar\r"},
208 {1, 10, "\r"},
209 {2, 10, "bar\r"},
210 {3, 10, "\r"},
212 /* Buffer smaller than line length */
213 {0, 2, "foo bar\r"},
214 {0, 1, "foo bar\r"},
215 {0, 0, "foo bar\r"}
218 static void test_EM_GETLINE(void)
220 int i;
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"
225 "\n"
226 "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++)
233 int nCopied;
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,
243 expected_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),
247 "buffer_len=0\n");
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");
251 else
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)
266 POINT p = {-1, -1};
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);
269 return p.y;
272 static void move_cursor(HWND hwnd, long charindex)
274 CHARRANGE cr;
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)
287 int prevY, curY;
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 "
291 "control's width\n"
292 "cc\n"
293 "dd\n"
294 "ee\n"
295 "ff\n"
296 "gg\n"
297 "hh\n";
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;
340 CHARRANGE cr;
341 int rc = 0;
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*/
356 /*Italicize the text
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,
362 (LPARAM) &cf2);
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"*/
373 cr.cpMin = 0;
374 cr.cpMax = 4;
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*/
398 cr.cpMin = 2;
399 cr.cpMax = 3;
400 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
402 /*Retrieve its formatting*/
403 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
404 (LPARAM) &cf2);
406 /*Select a character from the second "wine" string*/
407 cr.cpMin = 5;
408 cr.cpMax = 6;
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,
414 (LPARAM) &cf2test);
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);
429 /*Clear control*/
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*/
443 cr.cpMin = 1;
444 cr.cpMax = 3;
445 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
447 /*Retrieve its formatting*/
448 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
449 (LPARAM) &cf2);
451 /*Select text from the second "wine" string*/
452 cr.cpMin = 6;
453 cr.cpMax = 7;
454 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
456 /*Retrieve its formatting*/
457 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
458 (LPARAM) &cf2test);
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;
474 CHARRANGE cr;
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*/
487 cr.cpMin = 10;
488 cr.cpMax = 20;
489 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
490 cf2.cbSize = sizeof(CHARFORMAT2);
491 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
492 (LPARAM) &cf2);
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);
505 cr.cpMin = 21;
506 cr.cpMax = 30;
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*/
522 cr.cpMin = 0;
523 cr.cpMax = 4;
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*/
550 cr.cpMin = 1;
551 cr.cpMax = 3;
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*/
557 cr.cpMin = 5;
558 cr.cpMax = 7;
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};
575 int result;
577 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
578 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
579 result = strcmp(buffer,text);
580 ok(result == 0,
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);
600 ok(buffer[0]=='a',
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;
624 if (is_url)
625 { /* control text is url; should get CFE_LINK */
626 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
628 else
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)
640 struct urls_s {
641 const char *text;
642 int is_url;
643 } urls[12] = {
644 {"winehq.org", 0},
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},
653 {"telnet:test", 1},
654 {"news:newserver", 1},
655 {"wais:waisserver", 1}
658 int i;
659 int urlRet=-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)
691 int i, j;
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 */
699 expr = 0x00010000;
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
714 * line.
716 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
717 if (i == 0)
718 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
719 else
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);
741 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);
751 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);
762 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);
773 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);
780 ok(r == 0x00010000,
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);
785 y_before = 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);
792 ok(r == 0x00010000,
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);
804 ok(r == 0x00010000,
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",
808 y_before, y_after);
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);
815 ok(r == 0x00010000,
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",
819 y_before, y_after);
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);
833 CHARRANGE cr;
834 int i;
835 int result;
837 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
838 cr.cpMin = 0;
839 cr.cpMax = 1;
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);
881 ok (result == 100,
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);
892 WCHAR result;
894 /* First, check the default of a regular control */
895 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
896 ok (result == 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);
902 ok (result == 120,
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);
908 ok (result == 1234,
909 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
910 DestroyWindow(hwndRichEdit);
913 static void test_EM_SETTEXTEX(void)
915 HWND hwndRichEdit = new_richedit(NULL);
916 SETTEXTEX setText;
917 GETTEXTEX getText;
918 WCHAR TestItem1[] = {'T', 'e', 's', 't',
919 'S', 'o', 'm', 'e',
920 'T', 'e', 'x', 't', 0};
921 #define MAX_BUF_LEN 1024
922 WCHAR buf[MAX_BUF_LEN];
923 int result;
924 CHARRANGE cr;
926 setText.codepage = 1200; /* no constant for unicode */
927 getText.codepage = 1200; /* no constant for unicode */
928 getText.cb = MAX_BUF_LEN;
929 getText.flags = GT_DEFAULT;
931 setText.flags = 0;
932 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
933 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
934 ok(lstrcmpW(buf, TestItem1) == 0,
935 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
937 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
938 (WPARAM)&setText, (LPARAM) NULL);
939 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
941 ok (result == 1,
942 "EM_SETTEXTEX returned %d, instead of 1\n",result);
943 ok(lstrlenW(buf) == 0,
944 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
946 /* put some text back */
947 setText.flags = 0;
948 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
949 /* select some text */
950 cr.cpMax = 1;
951 cr.cpMin = 3;
952 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
953 /* replace current selection */
954 setText.flags = ST_SELECTION;
955 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
956 (WPARAM)&setText, (LPARAM) NULL);
957 ok(result == 0,
958 "EM_SETTEXTEX with NULL lParam to replace selection"
959 " with no text should return 0. Got %i\n",
960 result);
962 /* put some text back */
963 setText.flags = 0;
964 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
965 /* select some text */
966 cr.cpMax = 1;
967 cr.cpMin = 3;
968 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
969 /* replace current selection */
970 setText.flags = ST_SELECTION;
971 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
972 (WPARAM)&setText, (LPARAM) TestItem1);
973 /* get text */
974 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
975 ok(result == lstrlenW(TestItem1),
976 "EM_SETTEXTEX with NULL lParam to replace selection"
977 " with no text should return 0. Got %i\n",
978 result);
979 ok(lstrlenW(buf) == 22,
980 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
981 lstrlenW(buf) );
983 DestroyWindow(hwndRichEdit);
986 static void test_EM_LIMITTEXT(void)
988 int ret;
990 HWND hwndRichEdit = new_richedit(NULL);
992 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
993 * about setting the length to -1 for multiline edit controls doesn't happen.
996 /* Don't check default gettextlimit case. That's done in other tests */
998 /* Set textlimit to 100 */
999 SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
1000 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1001 ok (ret == 100,
1002 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
1004 /* Set textlimit to 0 */
1005 SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
1006 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1007 ok (ret == 65536,
1008 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
1010 /* Set textlimit to -1 */
1011 SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
1012 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1013 ok (ret == -1,
1014 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
1016 /* Set textlimit to -2 */
1017 SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
1018 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1019 ok (ret == -2,
1020 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
1022 DestroyWindow (hwndRichEdit);
1026 static void test_EM_EXLIMITTEXT(void)
1028 int i, selBegin, selEnd, len1, len2;
1029 int result;
1030 char text[1024 + 1];
1031 char buffer[1024 + 1];
1032 int textlimit = 0; /* multiple of 100 */
1033 HWND hwndRichEdit = new_richedit(NULL);
1035 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1036 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
1038 textlimit = 256000;
1039 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1040 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1041 /* set higher */
1042 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1044 textlimit = 1000;
1045 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1046 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1047 /* set lower */
1048 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1050 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1051 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1052 /* default for WParam = 0 */
1053 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1055 textlimit = sizeof(text)-1;
1056 memset(text, 'W', textlimit);
1057 text[sizeof(text)-1] = 0;
1058 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1059 /* maxed out text */
1060 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1062 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1063 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1064 len1 = selEnd - selBegin;
1066 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1067 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1068 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1069 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1070 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1071 len2 = selEnd - selBegin;
1073 ok(len1 != len2,
1074 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1075 len1,len2,i);
1077 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1078 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1079 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1080 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1081 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1082 len1 = selEnd - selBegin;
1084 ok(len1 != len2,
1085 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1086 len1,len2,i);
1088 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1089 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1090 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1091 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1092 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1093 len2 = selEnd - selBegin;
1095 ok(len1 == len2,
1096 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1097 len1,len2,i);
1099 /* set text up to the limit, select all the text, then add a char */
1100 textlimit = 5;
1101 memset(text, 'W', textlimit);
1102 text[textlimit] = 0;
1103 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1104 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1105 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1106 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1107 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1108 result = strcmp(buffer, "A");
1109 ok(0 == result, "got string = \"%s\"\n", buffer);
1111 DestroyWindow(hwndRichEdit);
1114 static void test_EM_GETLIMITTEXT(void)
1116 int i;
1117 HWND hwndRichEdit = new_richedit(NULL);
1119 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1120 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1122 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1123 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1124 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1126 DestroyWindow(hwndRichEdit);
1129 static void test_WM_SETFONT(void)
1131 /* There is no invalid input or error conditions for this function.
1132 * NULL wParam and lParam just fall back to their default values
1133 * It should be noted that even if you use a gibberish name for your fonts
1134 * here, it will still work because the name is stored. They will display as
1135 * System, but will report their name to be whatever they were created as */
1137 HWND hwndRichEdit = new_richedit(NULL);
1138 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1139 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1140 FF_DONTCARE, "Marlett");
1141 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1142 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1143 FF_DONTCARE, "MS Sans Serif");
1144 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1145 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1146 FF_DONTCARE, "Courier");
1147 LOGFONTA sentLogFont;
1148 CHARFORMAT2A returnedCF2A;
1150 returnedCF2A.cbSize = sizeof(returnedCF2A);
1152 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1153 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1154 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1156 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1157 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1158 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1159 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1161 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1162 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1163 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1164 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1165 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1166 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1168 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1169 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1170 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1171 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1172 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1173 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1175 /* This last test is special since we send in NULL. We clear the variables
1176 * and just compare to "System" instead of the sent in font name. */
1177 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1178 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1179 returnedCF2A.cbSize = sizeof(returnedCF2A);
1181 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1182 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1183 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1184 ok (!strcmp("System",returnedCF2A.szFaceName),
1185 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1187 DestroyWindow(hwndRichEdit);
1191 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1192 LPBYTE pbBuff,
1193 LONG cb,
1194 LONG *pcb)
1196 const char** str = (const char**)dwCookie;
1197 int size = strlen(*str);
1198 if(size > 3) /* let's make it peice-meal for fun */
1199 size = 3;
1200 *pcb = cb;
1201 if (*pcb > size) {
1202 *pcb = size;
1204 if (*pcb > 0) {
1205 memcpy(pbBuff, *str, *pcb);
1206 *str += *pcb;
1208 return 0;
1211 static void test_EM_GETMODIFY(void)
1213 HWND hwndRichEdit = new_richedit(NULL);
1214 LRESULT result;
1215 SETTEXTEX setText;
1216 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1217 'S', 'o', 'm', 'e',
1218 'T', 'e', 'x', 't', 0};
1219 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1220 'S', 'o', 'm', 'e',
1221 'O', 't', 'h', 'e', 'r',
1222 'T', 'e', 'x', 't', 0};
1223 const char* streamText = "hello world";
1224 CHARFORMAT2 cf2;
1225 PARAFORMAT2 pf2;
1226 EDITSTREAM es;
1228 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1229 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1230 FF_DONTCARE, "Courier");
1232 setText.codepage = 1200; /* no constant for unicode */
1233 setText.flags = ST_KEEPUNDO;
1236 /* modify flag shouldn't be set when richedit is first created */
1237 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1238 ok (result == 0,
1239 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1241 /* setting modify flag should actually set it */
1242 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1243 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1244 ok (result != 0,
1245 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1247 /* clearing modify flag should actually clear it */
1248 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1249 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1250 ok (result == 0,
1251 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1253 /* setting font doesn't change modify flag */
1254 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1255 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1256 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1257 ok (result == 0,
1258 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1260 /* setting text should set modify flag */
1261 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1262 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1263 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1264 ok (result != 0,
1265 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1267 /* undo previous text doesn't reset modify flag */
1268 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1269 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1270 ok (result != 0,
1271 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1273 /* set text with no flag to keep undo stack should not set modify flag */
1274 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1275 setText.flags = 0;
1276 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1277 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1278 ok (result == 0,
1279 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1281 /* WM_SETTEXT doesn't modify */
1282 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1283 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1284 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1285 todo_wine {
1286 ok (result == 0,
1287 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1290 /* clear the text */
1291 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1292 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1293 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1294 ok (result == 0,
1295 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1297 /* replace text */
1298 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1299 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1300 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1301 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1302 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1303 ok (result != 0,
1304 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1306 /* copy/paste text 1 */
1307 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1308 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1309 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1310 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1311 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1312 ok (result != 0,
1313 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1315 /* copy/paste text 2 */
1316 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1317 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1318 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1319 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1320 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1321 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1322 ok (result != 0,
1323 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1325 /* press char */
1326 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1327 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1328 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1329 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1330 ok (result != 0,
1331 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1333 /* press del */
1334 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1335 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1336 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
1337 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1338 ok (result != 0,
1339 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1341 /* set char format */
1342 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1343 cf2.cbSize = sizeof(CHARFORMAT2);
1344 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1345 (LPARAM) &cf2);
1346 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1347 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1348 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1349 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1350 ok (result != 0,
1351 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1353 /* set para format */
1354 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1355 pf2.cbSize = sizeof(PARAFORMAT2);
1356 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1357 (LPARAM) &pf2);
1358 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1359 pf2.wAlignment = PFA_RIGHT;
1360 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1361 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1362 ok (result == 0,
1363 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1365 /* EM_STREAM */
1366 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1367 es.dwCookie = (DWORD_PTR)&streamText;
1368 es.dwError = 0;
1369 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1370 SendMessage(hwndRichEdit, EM_STREAMIN,
1371 (WPARAM)(SF_TEXT), (LPARAM)&es);
1372 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1373 ok (result != 0,
1374 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1376 DestroyWindow(hwndRichEdit);
1379 struct exsetsel_s {
1380 long min;
1381 long max;
1382 long expected_retval;
1383 int expected_getsel_start;
1384 int expected_getsel_end;
1385 int _exsetsel_todo_wine;
1386 int _getsel_todo_wine;
1389 const struct exsetsel_s exsetsel_tests[] = {
1390 /* sanity tests */
1391 {5, 10, 10, 5, 10, 0, 0},
1392 {15, 17, 17, 15, 17, 0, 0},
1393 /* test cpMax > strlen() */
1394 {0, 100, 18, 0, 18, 0, 1},
1395 /* test cpMin == cpMax */
1396 {5, 5, 5, 5, 5, 0, 0},
1397 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1398 {-1, 0, 5, 5, 5, 0, 0},
1399 {-1, 17, 5, 5, 5, 0, 0},
1400 {-1, 18, 5, 5, 5, 0, 0},
1401 /* test cpMin < 0 && cpMax < 0 */
1402 {-1, -1, 17, 17, 17, 0, 0},
1403 {-4, -5, 17, 17, 17, 0, 0},
1404 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1405 {0, -1, 18, 0, 18, 0, 1},
1406 {17, -5, 18, 17, 18, 0, 1},
1407 {18, -3, 17, 17, 17, 0, 0},
1408 /* test if cpMin > cpMax */
1409 {15, 19, 18, 15, 18, 0, 1},
1410 {19, 15, 18, 15, 18, 0, 1}
1413 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1414 CHARRANGE cr;
1415 long result;
1416 int start, end;
1418 cr.cpMin = setsel->min;
1419 cr.cpMax = setsel->max;
1420 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1422 if (setsel->_exsetsel_todo_wine) {
1423 todo_wine {
1424 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1426 } else {
1427 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1430 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1432 if (setsel->_getsel_todo_wine) {
1433 todo_wine {
1434 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);
1436 } else {
1437 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);
1441 static void test_EM_EXSETSEL(void)
1443 HWND hwndRichEdit = new_richedit(NULL);
1444 int i;
1445 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1447 /* sending some text to the window */
1448 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1449 /* 01234567890123456*/
1450 /* 10 */
1452 for (i = 0; i < num_tests; i++) {
1453 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1456 DestroyWindow(hwndRichEdit);
1459 static void test_EM_REPLACESEL(void)
1461 HWND hwndRichEdit = new_richedit(NULL);
1462 char buffer[1024] = {0};
1463 int r;
1465 /* sending some text to the window */
1466 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1467 /* 01234567890123456*/
1468 /* 10 */
1470 /* FIXME add more tests */
1471 SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
1472 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
1473 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1474 r = strcmp(buffer, "testing");
1475 ok(0 == r, "expected %d, got %d\n", 0, r);
1477 DestroyWindow(hwndRichEdit);
1480 static void test_WM_PASTE(void)
1482 int result;
1483 char buffer[1024] = {0};
1484 const char* text1 = "testing paste\r";
1485 const char* text2 = "testing paste\r\rtesting paste";
1486 const char* text3 = "testing paste\rpaste\rtesting paste";
1487 HWND hwndRichEdit = new_richedit(NULL);
1489 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
1490 SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
1491 SendMessage(hwndRichEdit, WM_CHAR, 3, 0); /* ctrl-c */
1492 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
1493 SendMessage(hwndRichEdit, WM_CHAR, 22, 0); /* ctrl-v */
1494 SendMessage(hwndRichEdit, WM_CHAR, 26, 0); /* ctrl-z */
1495 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1496 result = strcmp(text1, buffer);
1497 ok(result == 0,
1498 "test paste: strcmp = %i\n", result);
1500 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
1501 SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
1502 SendMessage(hwndRichEdit, WM_CHAR, 3, 0); /* ctrl-c */
1503 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
1504 SendMessage(hwndRichEdit, WM_CHAR, 22, 0); /* ctrl-v */
1505 SendMessage(hwndRichEdit, WM_CHAR, 26, 0); /* ctrl-z */
1506 SendMessage(hwndRichEdit, WM_CHAR, 25, 0); /* ctrl-y */
1507 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1508 result = strcmp(buffer,text3);
1509 ok(result == 0,
1510 "test paste: strcmp = %i\n", result);
1512 DestroyWindow(hwndRichEdit);
1515 static void test_EM_FORMATRANGE(void)
1517 int r;
1518 FORMATRANGE fr;
1519 HDC hdc;
1520 HWND hwndRichEdit = new_richedit(NULL);
1522 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
1524 hdc = GetDC(hwndRichEdit);
1525 ok(hdc != NULL, "Could not get HDC\n");
1527 fr.hdc = fr.hdcTarget = hdc;
1528 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
1529 fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
1530 fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
1531 fr.chrg.cpMin = 0;
1532 fr.chrg.cpMax = 20;
1534 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
1535 todo_wine {
1536 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
1539 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
1540 todo_wine {
1541 ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
1544 fr.chrg.cpMin = 0;
1545 fr.chrg.cpMax = 10;
1547 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
1548 todo_wine {
1549 ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
1552 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
1553 todo_wine {
1554 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
1557 DestroyWindow(hwndRichEdit);
1560 static int nCallbackCount = 0;
1562 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
1563 LONG cb, LONG* pcb)
1565 const char text[] = {'t','e','s','t'};
1567 if (sizeof(text) <= cb)
1569 if ((int)dwCookie != nCallbackCount)
1571 *pcb = 0;
1572 return 0;
1575 memcpy (pbBuff, text, sizeof(text));
1576 *pcb = sizeof(text);
1578 nCallbackCount++;
1580 return 0;
1582 else
1583 return 1; /* indicates callback failed */
1586 static void test_EM_StreamIn_Undo(void)
1588 /* The purpose of this test is to determine when a EM_StreamIn should be
1589 * undoable. This is important because WM_PASTE currently uses StreamIn and
1590 * pasting should always be undoable but streaming isn't always.
1592 * cases to test:
1593 * StreamIn plain text without SFF_SELECTION.
1594 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
1595 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
1596 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
1597 * Feel free to add tests for other text modes or StreamIn things.
1601 HWND hwndRichEdit = new_richedit(NULL);
1602 LRESULT result;
1603 EDITSTREAM es;
1604 char buffer[1024] = {0};
1605 const char randomtext[] = "Some text";
1607 es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
1609 /* StreamIn, no SFF_SELECTION */
1610 es.dwCookie = nCallbackCount;
1611 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1612 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1613 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
1614 SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
1615 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1616 result = strcmp (buffer,"test");
1617 ok (result == 0,
1618 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
1620 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1621 ok (result == FALSE,
1622 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
1624 /* StreamIn, SFF_SELECTION, but nothing selected */
1625 es.dwCookie = nCallbackCount;
1626 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1627 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1628 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
1629 SendMessage(hwndRichEdit, EM_STREAMIN,
1630 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
1631 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1632 result = strcmp (buffer,"testSome text");
1633 ok (result == 0,
1634 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
1636 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1637 ok (result == TRUE,
1638 "EM_STREAMIN with SFF_SELECTION but no selection set "
1639 "should create an undo\n");
1641 /* StreamIn, SFF_SELECTION, with a selection */
1642 es.dwCookie = nCallbackCount;
1643 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1644 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
1645 SendMessage(hwndRichEdit, EM_SETSEL,4,5);
1646 SendMessage(hwndRichEdit, EM_STREAMIN,
1647 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
1648 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1649 result = strcmp (buffer,"Sometesttext");
1650 ok (result == 0,
1651 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
1653 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
1654 ok (result == TRUE,
1655 "EM_STREAMIN with SFF_SELECTION and selection set "
1656 "should create an undo\n");
1660 static BOOL is_em_settextex_supported(HWND hwnd)
1662 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
1663 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
1666 static void test_unicode_conversions(void)
1668 static const WCHAR tW[] = {'t',0};
1669 static const WCHAR teW[] = {'t','e',0};
1670 static const WCHAR textW[] = {'t','e','s','t',0};
1671 static const char textA[] = "test";
1672 char bufA[64];
1673 WCHAR bufW[64];
1674 HWND hwnd;
1675 int is_win9x, em_settextex_supported, ret;
1677 is_win9x = GetVersion() & 0x80000000;
1679 #define set_textA(hwnd, wm_set_text, txt) \
1680 do { \
1681 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
1682 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1683 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1684 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1685 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
1686 } while(0)
1687 #define expect_textA(hwnd, wm_get_text, txt) \
1688 do { \
1689 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1690 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
1691 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1692 memset(bufA, 0xAA, sizeof(bufA)); \
1693 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1694 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1695 ret = lstrcmpA(bufA, txt); \
1696 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
1697 } while(0)
1699 #define set_textW(hwnd, wm_set_text, txt) \
1700 do { \
1701 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
1702 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1703 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1704 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1705 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
1706 } while(0)
1707 #define expect_textW(hwnd, wm_get_text, txt) \
1708 do { \
1709 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
1710 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
1711 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1712 memset(bufW, 0xAA, sizeof(bufW)); \
1713 if (is_win9x) \
1715 assert(wm_get_text == EM_GETTEXTEX); \
1716 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1717 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1719 else \
1721 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1722 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
1724 ret = lstrcmpW(bufW, txt); \
1725 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
1726 } while(0)
1727 #define expect_empty(hwnd, wm_get_text) \
1728 do { \
1729 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1730 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
1731 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1732 memset(bufA, 0xAA, sizeof(bufA)); \
1733 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1734 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
1735 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
1736 } while(0)
1738 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
1739 0, 0, 200, 60, 0, 0, 0, 0);
1740 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1742 ret = IsWindowUnicode(hwnd);
1743 if (is_win9x)
1744 ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
1745 else
1746 ok(ret, "RichEdit20W should be unicode under NT\n");
1748 /* EM_SETTEXTEX is supported starting from version 3.0 */
1749 em_settextex_supported = is_em_settextex_supported(hwnd);
1750 trace("EM_SETTEXTEX is %ssupported on this platform\n",
1751 em_settextex_supported ? "" : "NOT ");
1753 expect_empty(hwnd, WM_GETTEXT);
1754 expect_empty(hwnd, EM_GETTEXTEX);
1756 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
1757 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
1758 expect_textA(hwnd, WM_GETTEXT, "t");
1759 expect_textA(hwnd, EM_GETTEXTEX, "t");
1760 expect_textW(hwnd, EM_GETTEXTEX, tW);
1762 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
1763 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
1764 expect_textA(hwnd, WM_GETTEXT, "te");
1765 expect_textA(hwnd, EM_GETTEXTEX, "te");
1766 expect_textW(hwnd, EM_GETTEXTEX, teW);
1768 set_textA(hwnd, WM_SETTEXT, NULL);
1769 expect_empty(hwnd, WM_GETTEXT);
1770 expect_empty(hwnd, EM_GETTEXTEX);
1772 if (is_win9x)
1773 set_textA(hwnd, WM_SETTEXT, textW);
1774 else
1775 set_textA(hwnd, WM_SETTEXT, textA);
1776 expect_textA(hwnd, WM_GETTEXT, textA);
1777 expect_textA(hwnd, EM_GETTEXTEX, textA);
1778 expect_textW(hwnd, EM_GETTEXTEX, textW);
1780 if (em_settextex_supported)
1782 set_textA(hwnd, EM_SETTEXTEX, textA);
1783 expect_textA(hwnd, WM_GETTEXT, textA);
1784 expect_textA(hwnd, EM_GETTEXTEX, textA);
1785 expect_textW(hwnd, EM_GETTEXTEX, textW);
1788 if (!is_win9x)
1790 set_textW(hwnd, WM_SETTEXT, textW);
1791 expect_textW(hwnd, WM_GETTEXT, textW);
1792 expect_textA(hwnd, WM_GETTEXT, textA);
1793 expect_textW(hwnd, EM_GETTEXTEX, textW);
1794 expect_textA(hwnd, EM_GETTEXTEX, textA);
1796 if (em_settextex_supported)
1798 set_textW(hwnd, EM_SETTEXTEX, textW);
1799 expect_textW(hwnd, WM_GETTEXT, textW);
1800 expect_textA(hwnd, WM_GETTEXT, textA);
1801 expect_textW(hwnd, EM_GETTEXTEX, textW);
1802 expect_textA(hwnd, EM_GETTEXTEX, textA);
1805 DestroyWindow(hwnd);
1807 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
1808 0, 0, 200, 60, 0, 0, 0, 0);
1809 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1811 ret = IsWindowUnicode(hwnd);
1812 ok(!ret, "RichEdit20A should NOT be unicode\n");
1814 set_textA(hwnd, WM_SETTEXT, textA);
1815 expect_textA(hwnd, WM_GETTEXT, textA);
1816 expect_textA(hwnd, EM_GETTEXTEX, textA);
1817 expect_textW(hwnd, EM_GETTEXTEX, textW);
1819 if (em_settextex_supported)
1821 set_textA(hwnd, EM_SETTEXTEX, textA);
1822 expect_textA(hwnd, WM_GETTEXT, textA);
1823 expect_textA(hwnd, EM_GETTEXTEX, textA);
1824 expect_textW(hwnd, EM_GETTEXTEX, textW);
1827 if (!is_win9x)
1829 set_textW(hwnd, WM_SETTEXT, textW);
1830 expect_textW(hwnd, WM_GETTEXT, textW);
1831 expect_textA(hwnd, WM_GETTEXT, textA);
1832 expect_textW(hwnd, EM_GETTEXTEX, textW);
1833 expect_textA(hwnd, EM_GETTEXTEX, textA);
1835 if (em_settextex_supported)
1837 set_textW(hwnd, EM_SETTEXTEX, textW);
1838 expect_textW(hwnd, WM_GETTEXT, textW);
1839 expect_textA(hwnd, WM_GETTEXT, textA);
1840 expect_textW(hwnd, EM_GETTEXTEX, textW);
1841 expect_textA(hwnd, EM_GETTEXTEX, textA);
1844 DestroyWindow(hwnd);
1848 static void test_EM_GETTEXTLENGTHEX(void)
1850 HWND hwnd;
1851 GETTEXTLENGTHEX gtl;
1852 int ret;
1854 /* single line */
1855 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
1856 0, 0, 200, 60, 0, 0, 0, 0);
1857 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1859 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1860 gtl.codepage = CP_ACP;
1861 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1862 ok(ret == 0, "ret %d\n",ret);
1864 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
1865 gtl.codepage = CP_ACP;
1866 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1867 ok(ret == 0, "ret %d\n",ret);
1869 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) "a\nb\n\n\r\n");
1871 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1872 gtl.codepage = CP_ACP;
1873 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1874 todo_wine ok(ret == 1, "ret %d\n",ret);
1876 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
1877 gtl.codepage = CP_ACP;
1878 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1879 todo_wine ok(ret == 1, "ret %d\n",ret);
1881 DestroyWindow(hwnd);
1883 /* multi line */
1884 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
1885 0, 0, 200, 60, 0, 0, 0, 0);
1886 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
1888 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1889 gtl.codepage = CP_ACP;
1890 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1891 todo_wine ok(ret == 0, "ret %d\n",ret);
1893 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
1894 gtl.codepage = CP_ACP;
1895 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1896 ok(ret == 0, "ret %d\n",ret);
1898 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) "a\nb\n\n\r\n");
1900 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
1901 gtl.codepage = CP_ACP;
1902 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1903 todo_wine ok(ret == 10, "ret %d\n",ret);
1905 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
1906 gtl.codepage = CP_ACP;
1907 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
1908 ok(ret == 6, "ret %d\n",ret);
1910 DestroyWindow(hwnd);
1913 START_TEST( editor )
1915 MSG msg;
1916 time_t end;
1918 /* Must explicitly LoadLibrary(). The test has no references to functions in
1919 * RICHED20.DLL, so the linker doesn't actually link to it. */
1920 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
1921 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1923 test_EM_FINDTEXT();
1924 test_EM_GETLINE();
1925 test_EM_SCROLLCARET();
1926 test_EM_SCROLL();
1927 test_EM_SETTEXTMODE();
1928 test_TM_PLAINTEXT();
1929 test_EM_SETOPTIONS();
1930 test_WM_GETTEXT();
1931 test_EM_AUTOURLDETECT();
1932 test_EM_SETUNDOLIMIT();
1933 test_ES_PASSWORD();
1934 test_EM_SETTEXTEX();
1935 test_EM_LIMITTEXT();
1936 test_EM_EXLIMITTEXT();
1937 test_EM_GETLIMITTEXT();
1938 test_WM_SETFONT();
1939 test_EM_GETMODIFY();
1940 test_EM_EXSETSEL();
1941 test_WM_PASTE();
1942 test_EM_StreamIn_Undo();
1943 test_EM_FORMATRANGE();
1944 test_unicode_conversions();
1945 test_EM_GETTEXTLENGTHEX();
1946 test_EM_REPLACESEL();
1948 /* Set the environment variable WINETEST_RICHED20 to keep windows
1949 * responsive and open for 30 seconds. This is useful for debugging.
1951 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1952 * 50ms before retrying the queue. */
1953 end = time(NULL) + 30;
1954 if (getenv( "WINETEST_RICHED20" )) {
1955 while (time(NULL) < end) {
1956 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1957 TranslateMessage(&msg);
1958 DispatchMessage(&msg);
1959 } else {
1960 Sleep(50);
1965 OleFlushClipboard();
1966 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());