Autosyncing with Wine HEAD
[reactos.git] / rostests / winetests / riched20 / editor.c
1 /*
2 * Unit test suite for rich edit control
3 *
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
7 *
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.
12 *
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.
17 *
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
21 */
22
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>
34
35 static HMODULE hmoduleRichEdit;
36
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;
44 }
45
46 static HWND new_richedit(HWND parent) {
47 return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
48 }
49
50 static const char haystack[] = "WINEWine wineWine wine WineWine";
51 /* ^0 ^10 ^20 ^30 */
52
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;
60 };
61
62
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}
70 };
71
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},
76
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},
82
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},
87
88 /* Case-insensitive */
89 {1, 31, "wInE", FR_DOWN, 4, 0},
90 {1, 31, "Wine", FR_DOWN, 4, 0},
91
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},
97
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},
103
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},
112
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},
119
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},
126
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}
131 };
132
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);
144 }
145
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);
165 }
166
167 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
168 int num_tests)
169 {
170 int i;
171
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);
177 }
178 } else {
179 check_EM_FINDTEXT(hwnd, name, &find[i], i);
180 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
181 }
182 }
183 }
184
185 static void test_EM_FINDTEXT(void)
186 {
187 HWND hwndRichEdit = new_richedit(NULL);
188
189 /* Empty rich edit control */
190 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
191 sizeof(find_tests)/sizeof(struct find_s));
192
193 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
194
195 /* Haystack text */
196 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
197 sizeof(find_tests2)/sizeof(struct find_s));
198
199 DestroyWindow(hwndRichEdit);
200 }
201
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"},
211
212 /* Buffer smaller than line length */
213 {0, 2, "foo bar\r"},
214 {0, 1, "foo bar\r"},
215 {0, 0, "foo bar\r"}
216 };
217
218 static void test_EM_GETLINE(void)
219 {
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";
227
228 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
229
230 memset(origdest, 0xBB, nBuf);
231 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
232 {
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;
238
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
252 {
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);
258 }
259 }
260
261 DestroyWindow(hwndRichEdit);
262 }
263
264 static int get_scroll_pos_y(HWND hwnd)
265 {
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;
270 }
271
272 static void move_cursor(HWND hwnd, long charindex)
273 {
274 CHARRANGE cr;
275 cr.cpMax = charindex;
276 cr.cpMin = charindex;
277 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
278 }
279
280 static void line_scroll(HWND hwnd, int amount)
281 {
282 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
283 }
284
285 static void test_EM_SCROLLCARET(void)
286 {
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";
298
299 /* Can't verify this */
300 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
301
302 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
303
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);
310
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);
318
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);
325
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);
332
333 DestroyWindow(hwndRichEdit);
334 }
335
336 static void test_EM_SETCHARFORMAT(void)
337 {
338 HWND hwndRichEdit = new_richedit(NULL);
339 CHARFORMAT2 cf2;
340 int rc = 0;
341
342 /* Invalid flags, CHARFORMAT2 structure blanked out */
343 memset(&cf2, 0, sizeof(cf2));
344 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
345 (LPARAM) &cf2);
346 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
347
348 /* A valid flag, CHARFORMAT2 structure blanked out */
349 memset(&cf2, 0, sizeof(cf2));
350 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
351 (LPARAM) &cf2);
352 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
353
354 /* A valid flag, CHARFORMAT2 structure blanked out */
355 memset(&cf2, 0, sizeof(cf2));
356 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
357 (LPARAM) &cf2);
358 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
359
360 /* A valid flag, CHARFORMAT2 structure blanked out */
361 memset(&cf2, 0, sizeof(cf2));
362 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
363 (LPARAM) &cf2);
364 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
365
366 /* A valid flag, CHARFORMAT2 structure blanked out */
367 memset(&cf2, 0, sizeof(cf2));
368 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
369 (LPARAM) &cf2);
370 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
371
372 /* Invalid flags, CHARFORMAT2 structure minimally filled */
373 memset(&cf2, 0, sizeof(cf2));
374 cf2.cbSize = sizeof(CHARFORMAT2);
375 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
376 (LPARAM) &cf2);
377 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
378
379 /* A valid flag, CHARFORMAT2 structure minimally filled */
380 memset(&cf2, 0, sizeof(cf2));
381 cf2.cbSize = sizeof(CHARFORMAT2);
382 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
383 (LPARAM) &cf2);
384 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
385
386 /* A valid flag, CHARFORMAT2 structure minimally filled */
387 memset(&cf2, 0, sizeof(cf2));
388 cf2.cbSize = sizeof(CHARFORMAT2);
389 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
390 (LPARAM) &cf2);
391 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
392
393 /* A valid flag, CHARFORMAT2 structure minimally filled */
394 memset(&cf2, 0, sizeof(cf2));
395 cf2.cbSize = sizeof(CHARFORMAT2);
396 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
397 (LPARAM) &cf2);
398 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
399
400 /* A valid flag, CHARFORMAT2 structure minimally filled */
401 memset(&cf2, 0, sizeof(cf2));
402 cf2.cbSize = sizeof(CHARFORMAT2);
403 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
404 (LPARAM) &cf2);
405 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
406
407 DestroyWindow(hwndRichEdit);
408 }
409
410 static void test_EM_SETTEXTMODE(void)
411 {
412 HWND hwndRichEdit = new_richedit(NULL);
413 CHARFORMAT2 cf2, cf2test;
414 CHARRANGE cr;
415 int rc = 0;
416
417 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
418 /*Insert text into the control*/
419
420 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
421
422 /*Attempt to change the control to plain text mode*/
423 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
424 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
425
426 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
427 If rich text is pasted, it should have the same formatting as the rest
428 of the text in the control*/
429
430 /*Italicize the text
431 *NOTE: If the default text was already italicized, the test will simply
432 reverse; in other words, it will copy a regular "wine" into a plain
433 text window that uses an italicized format*/
434 cf2.cbSize = sizeof(CHARFORMAT2);
435 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
436 (LPARAM) &cf2);
437
438 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
439 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
440
441 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
442 however, SCF_ALL has been implemented*/
443 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
444 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
445 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
446
447 /*Select the string "wine"*/
448 cr.cpMin = 0;
449 cr.cpMax = 4;
450 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
451
452 /*Copy the italicized "wine" to the clipboard*/
453 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
454
455 /*Reset the formatting to default*/
456 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
457 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
458 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
459
460 /*Clear the text in the control*/
461 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
462
463 /*Switch to Plain Text Mode*/
464 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
465 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
466
467 /*Input "wine" again in normal format*/
468 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
469
470 /*Paste the italicized "wine" into the control*/
471 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
472
473 /*Select a character from the first "wine" string*/
474 cr.cpMin = 2;
475 cr.cpMax = 3;
476 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
477
478 /*Retrieve its formatting*/
479 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
480 (LPARAM) &cf2);
481
482 /*Select a character from the second "wine" string*/
483 cr.cpMin = 5;
484 cr.cpMax = 6;
485 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
486
487 /*Retrieve its formatting*/
488 cf2test.cbSize = sizeof(CHARFORMAT2);
489 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
490 (LPARAM) &cf2test);
491
492 /*Compare the two formattings*/
493 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
494 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
495 cf2.dwEffects, cf2test.dwEffects);
496 /*Test TM_RICHTEXT by: switching back to Rich Text mode
497 printing "wine" in the current format(normal)
498 pasting "wine" from the clipboard(italicized)
499 comparing the two formats(should differ)*/
500
501 /*Attempt to switch with text in control*/
502 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
503 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
504
505 /*Clear control*/
506 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
507
508 /*Switch into Rich Text mode*/
509 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
510 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
511
512 /*Print "wine" in normal formatting into the control*/
513 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
514
515 /*Paste italicized "wine" into the control*/
516 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
517
518 /*Select text from the first "wine" string*/
519 cr.cpMin = 1;
520 cr.cpMax = 3;
521 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
522
523 /*Retrieve its formatting*/
524 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
525 (LPARAM) &cf2);
526
527 /*Select text from the second "wine" string*/
528 cr.cpMin = 6;
529 cr.cpMax = 7;
530 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
531
532 /*Retrieve its formatting*/
533 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
534 (LPARAM) &cf2test);
535
536 /*Test that the two formattings are not the same*/
537 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
538 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
539 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
540
541 DestroyWindow(hwndRichEdit);
542 }
543
544 static void test_TM_PLAINTEXT(void)
545 {
546 /*Tests plain text properties*/
547
548 HWND hwndRichEdit = new_richedit(NULL);
549 CHARFORMAT2 cf2, cf2test;
550 CHARRANGE cr;
551 int rc = 0;
552
553 /*Switch to plain text mode*/
554
555 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
556 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
557
558 /*Fill control with text*/
559
560 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
561
562 /*Select some text and bold it*/
563
564 cr.cpMin = 10;
565 cr.cpMax = 20;
566 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
567 cf2.cbSize = sizeof(CHARFORMAT2);
568 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
569 (LPARAM) &cf2);
570
571 cf2.dwMask = CFM_BOLD | cf2.dwMask;
572 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
573
574 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
575 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
576
577 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD | SCF_SELECTION, (LPARAM) &cf2);
578 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
579
580 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM)&cf2);
581 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
582
583 /*Get the formatting of those characters*/
584
585 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
586
587 /*Get the formatting of some other characters*/
588 cf2test.cbSize = sizeof(CHARFORMAT2);
589 cr.cpMin = 21;
590 cr.cpMax = 30;
591 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
592 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
593
594 /*Test that they are the same as plain text allows only one formatting*/
595
596 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
597 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
598 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
599
600 /*Fill the control with a "wine" string, which when inserted will be bold*/
601
602 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
603
604 /*Copy the bolded "wine" string*/
605
606 cr.cpMin = 0;
607 cr.cpMax = 4;
608 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
609 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
610
611 /*Swap back to rich text*/
612
613 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
614 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
615
616 /*Set the default formatting to bold italics*/
617
618 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
619 cf2.dwMask |= CFM_ITALIC;
620 cf2.dwEffects ^= CFE_ITALIC;
621 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
622 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
623
624 /*Set the text in the control to "wine", which will be bold and italicized*/
625
626 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
627
628 /*Paste the plain text "wine" string, which should take the insert
629 formatting, which at the moment is bold italics*/
630
631 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
632
633 /*Select the first "wine" string and retrieve its formatting*/
634
635 cr.cpMin = 1;
636 cr.cpMax = 3;
637 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
638 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
639
640 /*Select the second "wine" string and retrieve its formatting*/
641
642 cr.cpMin = 5;
643 cr.cpMax = 7;
644 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
645 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
646
647 /*Compare the two formattings. They should be the same.*/
648
649 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
650 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
651 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
652 DestroyWindow(hwndRichEdit);
653 }
654
655 static void test_WM_GETTEXT(void)
656 {
657 HWND hwndRichEdit = new_richedit(NULL);
658 static const char text[] = "Hello. My name is RichEdit!";
659 static const char text2[] = "Hello. My name is RichEdit!\r";
660 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
661 char buffer[1024] = {0};
662 int result;
663
664 /* Baseline test with normal-sized buffer */
665 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
666 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
667 ok(result == lstrlen(buffer),
668 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
669 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
670 result = strcmp(buffer,text);
671 ok(result == 0,
672 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
673
674 /* Test for returned value of WM_GETTEXTLENGTH */
675 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
676 ok(result == lstrlen(text),
677 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
678 result, lstrlen(text));
679
680 /* Test for behavior in overflow case */
681 memset(buffer, 0, 1024);
682 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
683 ok(result == 0,
684 "WM_GETTEXT returned %d, expected 0\n", result);
685 result = strcmp(buffer,text);
686 ok(result == 0,
687 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
688
689 /* Baseline test with normal-sized buffer and carriage return */
690 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
691 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
692 ok(result == lstrlen(buffer),
693 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
694 result = strcmp(buffer,text2_after);
695 ok(result == 0,
696 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
697
698 /* Test for returned value of WM_GETTEXTLENGTH */
699 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
700 ok(result == lstrlen(text2_after),
701 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
702 result, lstrlen(text2_after));
703
704 /* Test for behavior of CRLF conversion in case of overflow */
705 memset(buffer, 0, 1024);
706 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
707 ok(result == 0,
708 "WM_GETTEXT returned %d, expected 0\n", result);
709 result = strcmp(buffer,text2);
710 ok(result == 0,
711 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
712
713 DestroyWindow(hwndRichEdit);
714 }
715
716 /* FIXME: need to test unimplemented options and robustly test wparam */
717 static void test_EM_SETOPTIONS(void)
718 {
719 HWND hwndRichEdit = new_richedit(NULL);
720 static const char text[] = "Hello. My name is RichEdit!";
721 char buffer[1024] = {0};
722
723 /* NEGATIVE TESTING - NO OPTIONS SET */
724 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
725 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
726
727 /* testing no readonly by sending 'a' to the control*/
728 SetFocus(hwndRichEdit);
729 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
730 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
731 ok(buffer[0]=='a',
732 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
733 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
734
735 /* READONLY - sending 'a' to the control */
736 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
737 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
738 SetFocus(hwndRichEdit);
739 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
740 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
741 ok(buffer[0]==text[0],
742 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
743
744 DestroyWindow(hwndRichEdit);
745 }
746
747 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url, const char * url)
748 {
749 CHARFORMAT2W text_format;
750 int link_present = 0;
751 text_format.cbSize = sizeof(text_format);
752 SendMessage(hwnd, EM_SETSEL, 0, 1);
753 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
754 link_present = text_format.dwEffects & CFE_LINK;
755 if (is_url)
756 { /* control text is url; should get CFE_LINK */
757 ok(0 != link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
758 }
759 else
760 {
761 ok(0 == link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
762 }
763 }
764
765 static HWND new_static_wnd(HWND parent) {
766 return new_window("Static", 0, parent);
767 }
768
769 static void test_EM_AUTOURLDETECT(void)
770 {
771 struct urls_s {
772 const char *text;
773 int is_url;
774 } urls[12] = {
775 {"winehq.org", 0},
776 {"http://www.winehq.org", 1},
777 {"http//winehq.org", 0},
778 {"ww.winehq.org", 0},
779 {"www.winehq.org", 1},
780 {"ftp://192.168.1.1", 1},
781 {"ftp//192.168.1.1", 0},
782 {"mailto:your@email.com", 1},
783 {"prospero:prosperoserver", 1},
784 {"telnet:test", 1},
785 {"news:newserver", 1},
786 {"wais:waisserver", 1}
787 };
788
789 int i;
790 int urlRet=-1;
791 HWND hwndRichEdit, parent;
792
793 parent = new_static_wnd(NULL);
794 hwndRichEdit = new_richedit(parent);
795 /* Try and pass EM_AUTOURLDETECT some test wParam values */
796 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
797 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
798 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
799 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
800 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
801 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
802 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
803 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
804 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
805 /* for each url, check the text to see if CFE_LINK effect is present */
806 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
807 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
808 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
809 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
810 check_CFE_LINK_rcvd(hwndRichEdit, 0, urls[i].text);
811 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
812 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
813 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
814 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
815 }
816 DestroyWindow(hwndRichEdit);
817 DestroyWindow(parent);
818 }
819
820 static void test_EM_SCROLL(void)
821 {
822 int i, j;
823 int r; /* return value */
824 int expr; /* expected return value */
825 HWND hwndRichEdit = new_richedit(NULL);
826 int y_before, y_after; /* units of lines of text */
827
828 /* test a richedit box containing a single line of text */
829 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
830 expr = 0x00010000;
831 for (i = 0; i < 4; i++) {
832 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
833
834 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
835 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
836 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
837 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
838 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
839 "(i == %d)\n", y_after, i);
840 }
841
842 /*
843 * test a richedit box that will scroll. There are two general
844 * cases: the case without any long lines and the case with a long
845 * line.
846 */
847 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
848 if (i == 0)
849 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
850 else
851 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
852 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
853 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
854 "LONG LINE \nb\nc\nd\ne");
855 for (j = 0; j < 12; j++) /* reset scrol position to top */
856 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
857
858 /* get first visible line */
859 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
860 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
861
862 /* get new current first visible line */
863 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
864
865 ok(((r & 0xffffff00) == 0x00010000) &&
866 ((r & 0x000000ff) != 0x00000000),
867 "EM_SCROLL page down didn't scroll by a small positive number of "
868 "lines (r == 0x%08x)\n", r);
869 ok(y_after > y_before, "EM_SCROLL page down not functioning "
870 "(line %d scrolled to line %d\n", y_before, y_after);
871
872 y_before = y_after;
873
874 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
875 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
876 ok(((r & 0xffffff00) == 0x0001ff00),
877 "EM_SCROLL page up didn't scroll by a small negative number of lines "
878 "(r == 0x%08x)\n", r);
879 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
880 "%d scrolled to line %d\n", y_before, y_after);
881
882 y_before = y_after;
883
884 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
885
886 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
887
888 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
889 "(r == 0x%08x)\n", r);
890 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
891 "1 line (%d scrolled to %d)\n", y_before, y_after);
892
893 y_before = y_after;
894
895 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
896
897 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
898
899 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
900 "(r == 0x%08x)\n", r);
901 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
902 "line (%d scrolled to %d)\n", y_before, y_after);
903
904 y_before = y_after;
905
906 r = SendMessage(hwndRichEdit, EM_SCROLL,
907 SB_LINEUP, 0); /* lineup beyond top */
908
909 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
910
911 ok(r == 0x00010000,
912 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
913 ok(y_before == y_after,
914 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
915
916 y_before = y_after;
917
918 r = SendMessage(hwndRichEdit, EM_SCROLL,
919 SB_PAGEUP, 0);/*page up beyond top */
920
921 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
922
923 ok(r == 0x00010000,
924 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
925 ok(y_before == y_after,
926 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
927
928 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
929 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
930 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
931 r = SendMessage(hwndRichEdit, EM_SCROLL,
932 SB_PAGEDOWN, 0); /* page down beyond bot */
933 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
934
935 ok(r == 0x00010000,
936 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
937 ok(y_before == y_after,
938 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
939 y_before, y_after);
940
941 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
942 SendMessage(hwndRichEdit, EM_SCROLL,
943 SB_LINEDOWN, 0); /* line down beyond bot */
944 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
945
946 ok(r == 0x00010000,
947 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
948 ok(y_before == y_after,
949 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
950 y_before, y_after);
951 }
952 DestroyWindow(hwndRichEdit);
953 }
954
955 static void test_EM_SETUNDOLIMIT(void)
956 {
957 /* cases we test for:
958 * default behaviour - limiting at 100 undo's
959 * undo disabled - setting a limit of 0
960 * undo limited - undo limit set to some to some number, like 2
961 * bad input - sending a negative number should default to 100 undo's */
962
963 HWND hwndRichEdit = new_richedit(NULL);
964 CHARRANGE cr;
965 int i;
966 int result;
967
968 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
969 cr.cpMin = 0;
970 cr.cpMax = 1;
971 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
972 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
973 also, multiple pastes don't combine like WM_CHAR would */
974 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
975
976 /* first case - check the default */
977 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
978 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
979 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
980 for (i=0; i<100; i++) /* Undo 100 of them */
981 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
982 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
983 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
984
985 /* second case - cannot undo */
986 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
987 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
988 SendMessage(hwndRichEdit,
989 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
990 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
991 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
992
993 /* third case - set it to an arbitrary number */
994 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
995 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
996 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
997 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
998 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
999 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
1000 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
1001 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
1002 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1003 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1004 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
1005 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1006 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1007 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
1008
1009 /* fourth case - setting negative numbers should default to 100 undos */
1010 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
1011 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
1012 ok (result == 100,
1013 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
1014
1015 DestroyWindow(hwndRichEdit);
1016 }
1017
1018 static void test_ES_PASSWORD(void)
1019 {
1020 /* This isn't hugely testable, so we're just going to run it through its paces */
1021
1022 HWND hwndRichEdit = new_richedit(NULL);
1023 WCHAR result;
1024
1025 /* First, check the default of a regular control */
1026 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1027 ok (result == 0,
1028 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
1029
1030 /* Now, set it to something normal */
1031 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
1032 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1033 ok (result == 120,
1034 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1035
1036 /* Now, set it to something odd */
1037 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
1038 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1039 ok (result == 1234,
1040 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1041 DestroyWindow(hwndRichEdit);
1042 }
1043
1044 static void test_WM_SETTEXT()
1045 {
1046 HWND hwndRichEdit = new_richedit(NULL);
1047 const char * TestItem1 = "TestSomeText";
1048 const char * TestItem2 = "TestSomeText\r";
1049 const char * TestItem2_after = "TestSomeText\r\n";
1050 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
1051 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
1052 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
1053 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
1054 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
1055 const char * TestItem5_after = "TestSomeText TestSomeText";
1056 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
1057 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
1058 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
1059 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
1060 char buf[1024] = {0};
1061 LRESULT result;
1062
1063 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
1064 any solitary \r to be converted to \r\n on return. Properly paired
1065 \r\n are not affected. It also shows that the special sequence \r\r\n
1066 gets converted to a single space.
1067 */
1068
1069 #define TEST_SETTEXT(a, b) \
1070 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
1071 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
1072 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
1073 ok (result == lstrlen(buf), \
1074 "WM_GETTEXT returned %ld instead of expected %u\n", \
1075 result, lstrlen(buf)); \
1076 result = strcmp(b, buf); \
1077 ok(result == 0, \
1078 "WM_SETTEXT round trip: strcmp = %ld\n", result);
1079
1080 TEST_SETTEXT(TestItem1, TestItem1)
1081 TEST_SETTEXT(TestItem2, TestItem2_after)
1082 TEST_SETTEXT(TestItem3, TestItem3_after)
1083 TEST_SETTEXT(TestItem3_after, TestItem3_after)
1084 TEST_SETTEXT(TestItem4, TestItem4_after)
1085 TEST_SETTEXT(TestItem5, TestItem5_after)
1086 TEST_SETTEXT(TestItem6, TestItem6_after)
1087 TEST_SETTEXT(TestItem7, TestItem7_after)
1088
1089 #undef TEST_SETTEXT
1090 DestroyWindow(hwndRichEdit);
1091 }
1092
1093 static void test_EM_SETTEXTEX(void)
1094 {
1095 HWND hwndRichEdit = new_richedit(NULL);
1096 SETTEXTEX setText;
1097 GETTEXTEX getText;
1098 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1099 'S', 'o', 'm', 'e',
1100 'T', 'e', 'x', 't', 0};
1101 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1102 'S', 'o', 'm', 'e',
1103 'T', 'e', 'x', 't',
1104 '\r', 0};
1105 const char * TestItem2_after = "TestSomeText\r\n";
1106 WCHAR TestItem3[] = {'T', 'e', 's', 't',
1107 'S', 'o', 'm', 'e',
1108 'T', 'e', 'x', 't',
1109 '\r','\n','\r','\n', 0};
1110 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
1111 'S', 'o', 'm', 'e',
1112 'T', 'e', 'x', 't',
1113 '\n','\n', 0};
1114 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
1115 'S', 'o', 'm', 'e',
1116 'T', 'e', 'x', 't',
1117 '\r','\r', 0};
1118 WCHAR TestItem4[] = {'T', 'e', 's', 't',
1119 'S', 'o', 'm', 'e',
1120 'T', 'e', 'x', 't',
1121 '\r','\r','\n','\r',
1122 '\n', 0};
1123 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
1124 'S', 'o', 'm', 'e',
1125 'T', 'e', 'x', 't',
1126 ' ','\r', 0};
1127 #define MAX_BUF_LEN 1024
1128 WCHAR buf[MAX_BUF_LEN];
1129 int result;
1130 CHARRANGE cr;
1131
1132 setText.codepage = 1200; /* no constant for unicode */
1133 getText.codepage = 1200; /* no constant for unicode */
1134 getText.cb = MAX_BUF_LEN;
1135 getText.flags = GT_DEFAULT;
1136 getText.lpDefaultChar = NULL;
1137 getText.lpUsedDefChar = NULL;
1138
1139 setText.flags = 0;
1140 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1141 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1142 ok(lstrcmpW(buf, TestItem1) == 0,
1143 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1144
1145 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
1146 convert \r to \r\n on return
1147 */
1148 setText.codepage = 1200; /* no constant for unicode */
1149 getText.codepage = 1200; /* no constant for unicode */
1150 getText.cb = MAX_BUF_LEN;
1151 getText.flags = GT_DEFAULT;
1152 getText.lpDefaultChar = NULL;
1153 getText.lpUsedDefChar = NULL;
1154 setText.flags = 0;
1155 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem2);
1156 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1157 ok(lstrcmpW(buf, TestItem2) == 0,
1158 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1159
1160 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
1161 SendMessage(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
1162 ok(strcmp((const char *)buf, TestItem2_after) == 0,
1163 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
1164
1165 /* Baseline test for just-enough buffer space for string */
1166 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1167 getText.codepage = 1200; /* no constant for unicode */
1168 getText.flags = GT_DEFAULT;
1169 getText.lpDefaultChar = NULL;
1170 getText.lpUsedDefChar = NULL;
1171 memset(buf, 0, MAX_BUF_LEN);
1172 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1173 ok(lstrcmpW(buf, TestItem2) == 0,
1174 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1175
1176 /* When there is enough space for one character, but not both, of the CRLF
1177 pair at the end of the string, the CR is not copied at all. That is,
1178 the caller must not see CRLF pairs truncated to CR at the end of the
1179 string.
1180 */
1181 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1182 getText.codepage = 1200; /* no constant for unicode */
1183 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
1184 getText.lpDefaultChar = NULL;
1185 getText.lpUsedDefChar = NULL;
1186 memset(buf, 0, MAX_BUF_LEN);
1187 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1188 ok(lstrcmpW(buf, TestItem1) == 0,
1189 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1190
1191
1192 /* \r\n pairs get changed into \r */
1193 setText.codepage = 1200; /* no constant for unicode */
1194 getText.codepage = 1200; /* no constant for unicode */
1195 getText.cb = MAX_BUF_LEN;
1196 getText.flags = GT_DEFAULT;
1197 getText.lpDefaultChar = NULL;
1198 getText.lpUsedDefChar = NULL;
1199 setText.flags = 0;
1200 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3);
1201 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1202 ok(lstrcmpW(buf, TestItem3_after) == 0,
1203 "EM_SETTEXTEX did not convert properly\n");
1204
1205 /* \n also gets changed to \r */
1206 setText.codepage = 1200; /* no constant for unicode */
1207 getText.codepage = 1200; /* no constant for unicode */
1208 getText.cb = MAX_BUF_LEN;
1209 getText.flags = GT_DEFAULT;
1210 getText.lpDefaultChar = NULL;
1211 getText.lpUsedDefChar = NULL;
1212 setText.flags = 0;
1213 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3alt);
1214 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1215 ok(lstrcmpW(buf, TestItem3_after) == 0,
1216 "EM_SETTEXTEX did not convert properly\n");
1217
1218 /* \r\r\n gets changed into single space */
1219 setText.codepage = 1200; /* no constant for unicode */
1220 getText.codepage = 1200; /* no constant for unicode */
1221 getText.cb = MAX_BUF_LEN;
1222 getText.flags = GT_DEFAULT;
1223 getText.lpDefaultChar = NULL;
1224 getText.lpUsedDefChar = NULL;
1225 setText.flags = 0;
1226 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem4);
1227 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1228 ok(lstrcmpW(buf, TestItem4_after) == 0,
1229 "EM_SETTEXTEX did not convert properly\n");
1230
1231 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1232 (WPARAM)&setText, (LPARAM) NULL);
1233 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1234
1235 ok (result == 1,
1236 "EM_SETTEXTEX returned %d, instead of 1\n",result);
1237 ok(lstrlenW(buf) == 0,
1238 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
1239
1240 /* put some text back */
1241 setText.flags = 0;
1242 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1243 /* select some text */
1244 cr.cpMax = 1;
1245 cr.cpMin = 3;
1246 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1247 /* replace current selection */
1248 setText.flags = ST_SELECTION;
1249 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1250 (WPARAM)&setText, (LPARAM) NULL);
1251 ok(result == 0,
1252 "EM_SETTEXTEX with NULL lParam to replace selection"
1253 " with no text should return 0. Got %i\n",
1254 result);
1255
1256 /* put some text back */
1257 setText.flags = 0;
1258 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1259 /* select some text */
1260 cr.cpMax = 1;
1261 cr.cpMin = 3;
1262 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1263 /* replace current selection */
1264 setText.flags = ST_SELECTION;
1265 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1266 (WPARAM)&setText, (LPARAM) TestItem1);
1267 /* get text */
1268 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1269 ok(result == lstrlenW(TestItem1),
1270 "EM_SETTEXTEX with NULL lParam to replace selection"
1271 " with no text should return 0. Got %i\n",
1272 result);
1273 ok(lstrlenW(buf) == 22,
1274 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
1275 lstrlenW(buf) );
1276
1277 DestroyWindow(hwndRichEdit);
1278 }
1279
1280 static void test_EM_LIMITTEXT(void)
1281 {
1282 int ret;
1283
1284 HWND hwndRichEdit = new_richedit(NULL);
1285
1286 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
1287 * about setting the length to -1 for multiline edit controls doesn't happen.
1288 */
1289
1290 /* Don't check default gettextlimit case. That's done in other tests */
1291
1292 /* Set textlimit to 100 */
1293 SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
1294 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1295 ok (ret == 100,
1296 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
1297
1298 /* Set textlimit to 0 */
1299 SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
1300 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1301 ok (ret == 65536,
1302 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
1303
1304 /* Set textlimit to -1 */
1305 SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
1306 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1307 ok (ret == -1,
1308 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
1309
1310 /* Set textlimit to -2 */
1311 SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
1312 ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1313 ok (ret == -2,
1314 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
1315
1316 DestroyWindow (hwndRichEdit);
1317 }
1318
1319
1320 static void test_EM_EXLIMITTEXT(void)
1321 {
1322 int i, selBegin, selEnd, len1, len2;
1323 int result;
1324 char text[1024 + 1];
1325 char buffer[1024 + 1];
1326 int textlimit = 0; /* multiple of 100 */
1327 HWND hwndRichEdit = new_richedit(NULL);
1328
1329 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1330 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
1331
1332 textlimit = 256000;
1333 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1334 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1335 /* set higher */
1336 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1337
1338 textlimit = 1000;
1339 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1340 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1341 /* set lower */
1342 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1343
1344 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1345 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1346 /* default for WParam = 0 */
1347 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1348
1349 textlimit = sizeof(text)-1;
1350 memset(text, 'W', textlimit);
1351 text[sizeof(text)-1] = 0;
1352 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1353 /* maxed out text */
1354 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1355
1356 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1357 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1358 len1 = selEnd - selBegin;
1359
1360 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1361 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1362 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1363 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1364 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1365 len2 = selEnd - selBegin;
1366
1367 ok(len1 != len2,
1368 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1369 len1,len2,i);
1370
1371 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1372 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1373 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1374 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1375 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1376 len1 = selEnd - selBegin;
1377
1378 ok(len1 != len2,
1379 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1380 len1,len2,i);
1381
1382 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1383 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1384 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1385 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1386 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1387 len2 = selEnd - selBegin;
1388
1389 ok(len1 == len2,
1390 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1391 len1,len2,i);
1392
1393 /* set text up to the limit, select all the text, then add a char */
1394 textlimit = 5;
1395 memset(text, 'W', textlimit);
1396 text[textlimit] = 0;
1397 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1398 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1399 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1400 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1401 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1402 result = strcmp(buffer, "A");
1403 ok(0 == result, "got string = \"%s\"\n", buffer);
1404
1405 /* WM_SETTEXT not limited */
1406 textlimit = 10;
1407 memset(text, 'W', textlimit);
1408 text[textlimit] = 0;
1409 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
1410 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1411 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1412 i = strlen(buffer);
1413 ok(10 == i, "expected 10 chars\n");
1414 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1415 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1416
1417 /* try inserting more text at end */
1418 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1419 ok(0 == i, "WM_CHAR wasn't processed\n");
1420 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1421 i = strlen(buffer);
1422 ok(10 == i, "expected 10 chars, got %i\n", i);
1423 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1424 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1425
1426 /* try inserting text at beginning */
1427 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
1428 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1429 ok(0 == i, "WM_CHAR wasn't processed\n");
1430 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1431 i = strlen(buffer);
1432 ok(10 == i, "expected 10 chars, got %i\n", i);
1433 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1434 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1435
1436 /* WM_CHAR is limited */
1437 textlimit = 1;
1438 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1439 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1440 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1441 ok(0 == i, "WM_CHAR wasn't processed\n");
1442 i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1443 ok(0 == i, "WM_CHAR wasn't processed\n");
1444 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1445 i = strlen(buffer);
1446 ok(1 == i, "expected 1 chars, got %i instead\n", i);
1447
1448 DestroyWindow(hwndRichEdit);
1449 }
1450
1451 static void test_EM_GETLIMITTEXT(void)
1452 {
1453 int i;
1454 HWND hwndRichEdit = new_richedit(NULL);
1455
1456 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1457 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1458
1459 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1460 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1461 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1462
1463 DestroyWindow(hwndRichEdit);
1464 }
1465
1466 static void test_WM_SETFONT(void)
1467 {
1468 /* There is no invalid input or error conditions for this function.
1469 * NULL wParam and lParam just fall back to their default values
1470 * It should be noted that even if you use a gibberish name for your fonts
1471 * here, it will still work because the name is stored. They will display as
1472 * System, but will report their name to be whatever they were created as */
1473
1474 HWND hwndRichEdit = new_richedit(NULL);
1475 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1476 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1477 FF_DONTCARE, "Marlett");
1478 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1479 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1480 FF_DONTCARE, "MS Sans Serif");
1481 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1482 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1483 FF_DONTCARE, "Courier");
1484 LOGFONTA sentLogFont;
1485 CHARFORMAT2A returnedCF2A;
1486
1487 returnedCF2A.cbSize = sizeof(returnedCF2A);
1488
1489 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1490 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1491 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1492
1493 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1494 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1495 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1496 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1497
1498 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1499 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1500 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1501 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1502 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1503 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1504
1505 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1506 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1507 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1508 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1509 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1510 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1511
1512 /* This last test is special since we send in NULL. We clear the variables
1513 * and just compare to "System" instead of the sent in font name. */
1514 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1515 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1516 returnedCF2A.cbSize = sizeof(returnedCF2A);
1517
1518 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1519 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1520 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1521 ok (!strcmp("System",returnedCF2A.szFaceName),
1522 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1523
1524 DestroyWindow(hwndRichEdit);
1525 }
1526
1527
1528 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1529 LPBYTE pbBuff,
1530 LONG cb,
1531 LONG *pcb)
1532 {
1533 const char** str = (const char**)dwCookie;
1534 int size = strlen(*str);
1535 if(size > 3) /* let's make it peice-meal for fun */
1536 size = 3;
1537 *pcb = cb;
1538 if (*pcb > size) {
1539 *pcb = size;
1540 }
1541 if (*pcb > 0) {
1542 memcpy(pbBuff, *str, *pcb);
1543 *str += *pcb;
1544 }
1545 return 0;
1546 }
1547
1548 static void test_EM_GETMODIFY(void)
1549 {
1550 HWND hwndRichEdit = new_richedit(NULL);
1551 LRESULT result;
1552 SETTEXTEX setText;
1553 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1554 'S', 'o', 'm', 'e',
1555 'T', 'e', 'x', 't', 0};
1556 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1557 'S', 'o', 'm', 'e',
1558 'O', 't', 'h', 'e', 'r',
1559 'T', 'e', 'x', 't', 0};
1560 const char* streamText = "hello world";
1561 CHARFORMAT2 cf2;
1562 PARAFORMAT2 pf2;
1563 EDITSTREAM es;
1564
1565 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1566 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1567 FF_DONTCARE, "Courier");
1568
1569 setText.codepage = 1200; /* no constant for unicode */
1570 setText.flags = ST_KEEPUNDO;
1571
1572
1573 /* modify flag shouldn't be set when richedit is first created */
1574 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1575 ok (result == 0,
1576 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1577
1578 /* setting modify flag should actually set it */
1579 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1580 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1581 ok (result != 0,
1582 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1583
1584 /* clearing modify flag should actually clear it */
1585 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1586 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1587 ok (result == 0,
1588 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1589
1590 /* setting font doesn't change modify flag */
1591 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1592 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1593 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1594 ok (result == 0,
1595 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1596
1597 /* setting text should set modify flag */
1598 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1599 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1600 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1601 ok (result != 0,
1602 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1603
1604 /* undo previous text doesn't reset modify flag */
1605 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1606 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1607 ok (result != 0,
1608 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1609
1610 /* set text with no flag to keep undo stack should not set modify flag */
1611 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1612 setText.flags = 0;
1613 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1614 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1615 ok (result == 0,
1616 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1617
1618 /* WM_SETTEXT doesn't modify */
1619 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1620 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1621 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1622 ok (result == 0,
1623 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1624
1625 /* clear the text */
1626 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1627 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1628 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1629 ok (result == 0,
1630 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1631
1632 /* replace text */
1633 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1634 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1635 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1636 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1637 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1638 ok (result != 0,
1639 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1640
1641 /* copy/paste text 1 */
1642 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1643 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1644 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1645 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1646 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1647 ok (result != 0,
1648 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1649
1650 /* copy/paste text 2 */
1651 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1652 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1653 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1654 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1655 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1656 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1657 ok (result != 0,
1658 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1659
1660 /* press char */
1661 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1662 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1663 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1664 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1665 ok (result != 0,
1666 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1667
1668 /* press del */
1669 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1670 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1671 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
1672 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1673 ok (result != 0,
1674 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1675
1676 /* set char format */
1677 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1678 cf2.cbSize = sizeof(CHARFORMAT2);
1679 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1680 (LPARAM) &cf2);
1681 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1682 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1683 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1684 result = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1685 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
1686 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1687 ok (result != 0,
1688 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1689
1690 /* set para format */
1691 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1692 pf2.cbSize = sizeof(PARAFORMAT2);
1693 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1694 (LPARAM) &pf2);
1695 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1696 pf2.wAlignment = PFA_RIGHT;
1697 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1698 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1699 ok (result == 0,
1700 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1701
1702 /* EM_STREAM */
1703 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1704 es.dwCookie = (DWORD_PTR)&streamText;
1705 es.dwError = 0;
1706 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1707 SendMessage(hwndRichEdit, EM_STREAMIN,
1708 (WPARAM)(SF_TEXT), (LPARAM)&es);
1709 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1710 ok (result != 0,
1711 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1712
1713 DestroyWindow(hwndRichEdit);
1714 }
1715
1716 struct exsetsel_s {
1717 long min;
1718 long max;
1719 long expected_retval;
1720 int expected_getsel_start;
1721 int expected_getsel_end;
1722 int _exsetsel_todo_wine;
1723 int _getsel_todo_wine;
1724 };
1725
1726 const struct exsetsel_s exsetsel_tests[] = {
1727 /* sanity tests */
1728 {5, 10, 10, 5, 10, 0, 0},
1729 {15, 17, 17, 15, 17, 0, 0},
1730 /* test cpMax > strlen() */
1731 {0, 100, 18, 0, 18, 0, 1},
1732 /* test cpMin == cpMax */
1733 {5, 5, 5, 5, 5, 0, 0},
1734 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1735 {-1, 0, 5, 5, 5, 0, 0},
1736 {-1, 17, 5, 5, 5, 0, 0},
1737 {-1, 18, 5, 5, 5, 0, 0},
1738 /* test cpMin < 0 && cpMax < 0 */
1739 {-1, -1, 17, 17, 17, 0, 0},
1740 {-4, -5, 17, 17, 17, 0, 0},
1741 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1742 {0, -1, 18, 0, 18, 0, 1},
1743 {17, -5, 18, 17, 18, 0, 1},
1744 {18, -3, 17, 17, 17, 0, 0},
1745 /* test if cpMin > cpMax */
1746 {15, 19, 18, 15, 18, 0, 1},
1747 {19, 15, 18, 15, 18, 0, 1}
1748 };
1749
1750 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1751 CHARRANGE cr;
1752 long result;
1753 int start, end;
1754
1755 cr.cpMin = setsel->min;
1756 cr.cpMax = setsel->max;
1757 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1758
1759 if (setsel->_exsetsel_todo_wine) {
1760 todo_wine {
1761 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1762 }
1763 } else {
1764 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1765 }
1766
1767 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1768
1769 if (setsel->_getsel_todo_wine) {
1770 todo_wine {
1771 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);
1772 }
1773 } else {
1774 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);
1775 }
1776 }
1777
1778 static void test_EM_EXSETSEL(void)
1779 {
1780 HWND hwndRichEdit = new_richedit(NULL);
1781 int i;
1782 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1783
1784 /* sending some text to the window */
1785 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1786 /* 01234567890123456*/
1787 /* 10 */
1788
1789 for (i = 0; i < num_tests; i++) {
1790 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1791 }
1792
1793 DestroyWindow(hwndRichEdit);
1794 }
1795
1796 static void test_EM_REPLACESEL(void)
1797 {
1798 HWND hwndRichEdit = new_richedit(NULL);
1799 char buffer[1024] = {0};
1800 int r;
1801 GETTEXTEX getText;
1802 CHARRANGE cr;
1803
1804 /* sending some text to the window */
1805 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1806 /* 01234567890123456*/
1807 /* 10 */
1808
1809 /* FIXME add more tests */
1810 SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
1811 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
1812 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
1813 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1814 r = strcmp(buffer, "testing");
1815 ok(0 == r, "expected %d, got %d\n", 0, r);
1816
1817 DestroyWindow(hwndRichEdit);
1818
1819 hwndRichEdit = new_richedit(NULL);
1820
1821 /* Test behavior with carriage returns and newlines */
1822 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1823 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1");
1824 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
1825 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1826 r = strcmp(buffer, "RichEdit1");
1827 ok(0 == r, "expected %d, got %d\n", 0, r);
1828 getText.cb = 1024;
1829 getText.codepage = CP_ACP;
1830 getText.flags = GT_DEFAULT;
1831 getText.lpDefaultChar = NULL;
1832 getText.lpUsedDefChar = NULL;
1833 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1834 ok(strcmp(buffer, "RichEdit1") == 0,
1835 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
1836
1837 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1838 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r");
1839 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
1840 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1841 r = strcmp(buffer, "RichEdit1\r\n");
1842 ok(0 == r, "expected %d, got %d\n", 0, r);
1843 getText.cb = 1024;
1844 getText.codepage = CP_ACP;
1845 getText.flags = GT_DEFAULT;
1846 getText.lpDefaultChar = NULL;
1847 getText.lpUsedDefChar = NULL;
1848 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1849 ok(strcmp(buffer, "RichEdit1\r") == 0,
1850 "EM_GETTEXTEX returned incorrect string\n");
1851
1852 /* Win98's riched20 and WinXP's riched20 disagree on what to return from
1853 EM_REPLACESEL. The general rule seems to be that Win98's riched20
1854 returns the number of characters *inserted* into the control (after
1855 required conversions), but WinXP's riched20 returns the number of
1856 characters interpreted from the original lParam. Wine's builtin riched20
1857 implements the WinXP behavior.
1858 */
1859 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1860 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r\n");
1861 ok(11 == r /* WinXP */ || 10 == r /* Win98 */,
1862 "EM_REPLACESEL returned %d, expected 11 or 10\n", r);
1863
1864 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1865 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1866 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
1867 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
1868
1869 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1870 r = strcmp(buffer, "RichEdit1\r\n");
1871 ok(0 == r, "expected %d, got %d\n", 0, r);
1872 getText.cb = 1024;
1873 getText.codepage = CP_ACP;
1874 getText.flags = GT_DEFAULT;
1875 getText.lpDefaultChar = NULL;
1876 getText.lpUsedDefChar = NULL;
1877 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1878 ok(strcmp(buffer, "RichEdit1\r") == 0,
1879 "EM_GETTEXTEX returned incorrect string\n");
1880
1881 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1882 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1883 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
1884 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
1885
1886 /* The following tests show that richedit should handle the special \r\r\n
1887 sequence by turning it into a single space on insertion. However,
1888 EM_REPLACESEL on WinXP returns the number of characters in the original
1889 string.
1890 */
1891
1892 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1893 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r");
1894 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
1895 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1896 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1897 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
1898 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
1899
1900 /* Test the actual string */
1901 getText.cb = 1024;
1902 getText.codepage = CP_ACP;
1903 getText.flags = GT_DEFAULT;
1904 getText.lpDefaultChar = NULL;
1905 getText.lpUsedDefChar = NULL;
1906 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1907 ok(strcmp(buffer, "\r\r") == 0,
1908 "EM_GETTEXTEX returned incorrect string\n");
1909
1910 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1911 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n");
1912 ok(3 == r /* WinXP */ || 1 == r /* Win98 */,
1913 "EM_REPLACESEL returned %d, expected 3 or 1\n", r);
1914 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1915 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1916 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
1917 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
1918
1919 /* Test the actual string */
1920 getText.cb = 1024;
1921 getText.codepage = CP_ACP;
1922 getText.flags = GT_DEFAULT;
1923 getText.lpDefaultChar = NULL;
1924 getText.lpUsedDefChar = NULL;
1925 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1926 ok(strcmp(buffer, " ") == 0,
1927 "EM_GETTEXTEX returned incorrect string\n");
1928
1929 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1930 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r");
1931 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
1932 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
1933 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1934 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1935 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
1936 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
1937
1938 /* Test the actual string */
1939 getText.cb = 1024;
1940 getText.codepage = CP_ACP;
1941 getText.flags = GT_DEFAULT;
1942 getText.lpDefaultChar = NULL;
1943 getText.lpUsedDefChar = NULL;
1944 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1945 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
1946 "EM_GETTEXTEX returned incorrect string\n");
1947
1948 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1949 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n");
1950 ok(5 == r /* WinXP */ || 2 == r /* Win98 */,
1951 "EM_REPLACESEL returned %d, expected 5 or 2\n", r);
1952 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1953 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1954 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
1955 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
1956
1957 /* Test the actual string */
1958 getText.cb = 1024;
1959 getText.codepage = CP_ACP;
1960 getText.flags = GT_DEFAULT;
1961 getText.lpDefaultChar = NULL;
1962 getText.lpUsedDefChar = NULL;
1963 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1964 ok(strcmp(buffer, " \r") == 0,
1965 "EM_GETTEXTEX returned incorrect string\n");
1966
1967 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1968 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r");
1969 ok(5 == r /* WinXP */ || 3 == r /* Win98 */,
1970 "EM_REPLACESEL returned %d, expected 5 or 3\n", r);
1971 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1972 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1973 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
1974 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
1975
1976 /* Test the actual string */
1977 getText.cb = 1024;
1978 getText.codepage = CP_ACP;
1979 getText.flags = GT_DEFAULT;
1980 getText.lpDefaultChar = NULL;
1981 getText.lpUsedDefChar = NULL;
1982 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1983 ok(strcmp(buffer, " \r\r") == 0,
1984 "EM_GETTEXTEX returned incorrect string\n");
1985
1986 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1987 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r");
1988 ok(6 == r /* WinXP */ || 5 == r /* Win98 */,
1989 "EM_REPLACESEL returned %d, expected 6 or 5\n", r);
1990 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1991 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1992 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
1993 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
1994
1995 /* Test the actual string */
1996 getText.cb = 1024;
1997 getText.codepage = CP_ACP;
1998 getText.flags = GT_DEFAULT;
1999 getText.lpDefaultChar = NULL;
2000 getText.lpUsedDefChar = NULL;
2001 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2002 ok(strcmp(buffer, "\rX\r\r\r") == 0,
2003 "EM_GETTEXTEX returned incorrect string\n");
2004
2005 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2006 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n");
2007 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
2008 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2009 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2010 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2011 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2012
2013 /* Test the actual string */
2014 getText.cb = 1024;
2015 getText.codepage = CP_ACP;
2016 getText.flags = GT_DEFAULT;
2017 getText.lpDefaultChar = NULL;
2018 getText.lpUsedDefChar = NULL;
2019 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2020 ok(strcmp(buffer, "\r\r") == 0,
2021 "EM_GETTEXTEX returned incorrect string\n");
2022
2023 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2024 r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n");
2025 ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
2026 "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
2027 r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2028 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2029 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
2030 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
2031
2032 /* Test the actual string */
2033 getText.cb = 1024;
2034 getText.codepage = CP_ACP;
2035 getText.flags = GT_DEFAULT;
2036 getText.lpDefaultChar = NULL;
2037 getText.lpUsedDefChar = NULL;
2038 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2039 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
2040 "EM_GETTEXTEX returned incorrect string\n");
2041
2042 DestroyWindow(hwndRichEdit);
2043 }
2044
2045 static void test_WM_PASTE(void)
2046 {
2047 MSG msg;
2048 int result;
2049 char buffer[1024] = {0};
2050 char key_info[][3] =
2051 {
2052 /* VirtualKey, ScanCode, WM_CHAR code */
2053 {'C', 0x2e, 3}, /* Ctrl-C */
2054 {'X', 0x2d, 24}, /* Ctrl-X */
2055 {'V', 0x2f, 22}, /* Ctrl-V */
2056 {'Z', 0x2c, 26}, /* Ctrl-Z */
2057 {'Y', 0x15, 25}, /* Ctrl-Y */
2058 };
2059 const char* text1 = "testing paste\r";
2060 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
2061 const char* text1_after = "testing paste\r\n";
2062 const char* text2 = "testing paste\r\rtesting paste";
2063 const char* text2_after = "testing paste\r\n\r\ntesting paste";
2064 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
2065 HWND hwndRichEdit = new_richedit(NULL);
2066
2067 /* Native riched20 won't obey WM_CHAR messages or WM_KEYDOWN/WM_KEYUP
2068 messages, probably because it inspects the keyboard state itself.
2069 Therefore, native requires this in order to obey Ctrl-<key> keystrokes.
2070 */
2071 #define SEND_CTRL_KEY(hwnd, k) \
2072 keybd_event(VK_CONTROL, 0x1d, 0, 0);\
2073 keybd_event(k[0], k[1], 0, 0);\
2074 keybd_event(k[0], k[1], KEYEVENTF_KEYUP, 0);\
2075 keybd_event(VK_CONTROL, 0x1d, KEYEVENTF_KEYUP, 0); \
2076 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
2077 TranslateMessage(&msg); \
2078 DispatchMessage(&msg); \
2079 }
2080
2081 #define SEND_CTRL_C(hwnd) SEND_CTRL_KEY(hwnd, key_info[0])
2082 #define SEND_CTRL_X(hwnd) SEND_CTRL_KEY(hwnd, key_info[1])
2083 #define SEND_CTRL_V(hwnd) SEND_CTRL_KEY(hwnd, key_info[2])
2084 #define SEND_CTRL_Z(hwnd) SEND_CTRL_KEY(hwnd, key_info[3])
2085 #define SEND_CTRL_Y(hwnd) SEND_CTRL_KEY(hwnd, key_info[4])
2086
2087 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
2088 SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
2089
2090 SEND_CTRL_C(hwndRichEdit) /* Copy */
2091 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2092 SEND_CTRL_V(hwndRichEdit) /* Paste */
2093 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2094 /* Pasted text should be visible at this step */
2095 result = strcmp(text1_step1, buffer);
2096 ok(result == 0,
2097 "test paste: strcmp = %i\n", result);
2098 SEND_CTRL_Z(hwndRichEdit) /* Undo */
2099 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2100 /* Text should be the same as before (except for \r -> \r\n conversion) */
2101 result = strcmp(text1_after, buffer);
2102 ok(result == 0,
2103 "test paste: strcmp = %i\n", result);
2104
2105 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
2106 SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
2107 SEND_CTRL_C(hwndRichEdit) /* Copy */
2108 SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2109 SEND_CTRL_V(hwndRichEdit) /* Paste */
2110 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2111 /* Pasted text should be visible at this step */
2112 result = strcmp(text3, buffer);
2113 ok(result == 0,
2114 "test paste: strcmp = %i\n", result);
2115 SEND_CTRL_Z(hwndRichEdit) /* Undo */
2116 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2117 /* Text should be the same as before (except for \r -> \r\n conversion) */
2118 result = strcmp(text2_after, buffer);
2119 ok(result == 0,
2120 "test paste: strcmp = %i\n", result);
2121 SEND_CTRL_Y(hwndRichEdit) /* Redo */
2122 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2123 /* Text should revert to post-paste state */
2124 result = strcmp(buffer,text3);
2125 ok(result == 0,
2126 "test paste: strcmp = %i\n", result);
2127
2128 DestroyWindow(hwndRichEdit);
2129 }
2130
2131 static void test_EM_FORMATRANGE(void)
2132 {
2133 int r;
2134 FORMATRANGE fr;
2135 HDC hdc;
2136 HWND hwndRichEdit = new_richedit(NULL);
2137
2138 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
2139
2140 hdc = GetDC(hwndRichEdit);
2141 ok(hdc != NULL, "Could not get HDC\n");
2142
2143 fr.hdc = fr.hdcTarget = hdc;
2144 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
2145 fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
2146 fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
2147 fr.chrg.cpMin = 0;
2148 fr.chrg.cpMax = 20;
2149
2150 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2151 todo_wine {
2152 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2153 }
2154
2155 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2156 todo_wine {
2157 ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
2158 }
2159
2160 fr.chrg.cpMin = 0;
2161 fr.chrg.cpMax = 10;
2162
2163 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2164 todo_wine {
2165 ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
2166 }
2167
2168 r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2169 todo_wine {
2170 ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2171 }
2172
2173 DestroyWindow(hwndRichEdit);
2174 }
2175
2176 static int nCallbackCount = 0;
2177
2178 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
2179 LONG cb, LONG* pcb)
2180 {
2181 const char text[] = {'t','e','s','t'};
2182
2183 if (sizeof(text) <= cb)
2184 {
2185 if ((int)dwCookie != nCallbackCount)
2186 {
2187 *pcb = 0;
2188 return 0;
2189 }
2190
2191 memcpy (pbBuff, text, sizeof(text));
2192 *pcb = sizeof(text);
2193
2194 nCallbackCount++;
2195
2196 return 0;
2197 }
2198 else
2199 return 1; /* indicates callback failed */
2200 }
2201
2202 static void test_EM_StreamIn_Undo(void)
2203 {
2204 /* The purpose of this test is to determine when a EM_StreamIn should be
2205 * undoable. This is important because WM_PASTE currently uses StreamIn and
2206 * pasting should always be undoable but streaming isn't always.
2207 *
2208 * cases to test:
2209 * StreamIn plain text without SFF_SELECTION.
2210 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
2211 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
2212 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
2213 * Feel free to add tests for other text modes or StreamIn things.
2214 */
2215
2216
2217 HWND hwndRichEdit = new_richedit(NULL);
2218 LRESULT result;
2219 EDITSTREAM es;
2220 char buffer[1024] = {0};
2221 const char randomtext[] = "Some text";
2222
2223 es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
2224
2225 /* StreamIn, no SFF_SELECTION */
2226 es.dwCookie = nCallbackCount;
2227 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2228 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2229 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2230 SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
2231 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2232 result = strcmp (buffer,"test");
2233 ok (result == 0,
2234 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
2235
2236 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2237 ok (result == FALSE,
2238 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
2239
2240 /* StreamIn, SFF_SELECTION, but nothing selected */
2241 es.dwCookie = nCallbackCount;
2242 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2243 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2244 SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2245 SendMessage(hwndRichEdit, EM_STREAMIN,
2246 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2247 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2248 result = strcmp (buffer,"testSome text");
2249 ok (result == 0,
2250 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2251
2252 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2253 ok (result == TRUE,
2254 "EM_STREAMIN with SFF_SELECTION but no selection set "
2255 "should create an undo\n");
2256
2257 /* StreamIn, SFF_SELECTION, with a selection */
2258 es.dwCookie = nCallbackCount;
2259 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2260 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2261 SendMessage(hwndRichEdit, EM_SETSEL,4,5);
2262 SendMessage(hwndRichEdit, EM_STREAMIN,
2263 (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2264 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2265 result = strcmp (buffer,"Sometesttext");
2266 ok (result == 0,
2267 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2268
2269 result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2270 ok (result == TRUE,
2271 "EM_STREAMIN with SFF_SELECTION and selection set "
2272 "should create an undo\n");
2273
2274 }
2275
2276 static BOOL is_em_settextex_supported(HWND hwnd)
2277 {
2278 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
2279 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
2280 }
2281
2282 static void test_unicode_conversions(void)
2283 {
2284 static const WCHAR tW[] = {'t',0};
2285 static const WCHAR teW[] = {'t','e',0};
2286 static const WCHAR textW[] = {'t','e','s','t',0};
2287 static const char textA[] = "test";
2288 char bufA[64];
2289 WCHAR bufW[64];
2290 HWND hwnd;
2291 int is_win9x, em_settextex_supported, ret;
2292
2293 is_win9x = GetVersion() & 0x80000000;
2294
2295 #define set_textA(hwnd, wm_set_text, txt) \
2296 do { \
2297 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
2298 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2299 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2300 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2301 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
2302 } while(0)
2303 #define expect_textA(hwnd, wm_get_text, txt) \
2304 do { \
2305 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2306 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2307 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2308 memset(bufA, 0xAA, sizeof(bufA)); \
2309 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2310 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2311 ret = lstrcmpA(bufA, txt); \
2312 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
2313 } while(0)
2314
2315 #define set_textW(hwnd, wm_set_text, txt) \
2316 do { \
2317 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
2318 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2319 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2320 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2321 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
2322 } while(0)
2323 #define expect_textW(hwnd, wm_get_text, txt) \
2324 do { \
2325 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
2326 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2327 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2328 memset(bufW, 0xAA, sizeof(bufW)); \
2329 if (is_win9x) \
2330 { \
2331 assert(wm_get_text == EM_GETTEXTEX); \
2332 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2333 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2334 } \
2335 else \
2336 { \
2337 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2338 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
2339 } \
2340 ret = lstrcmpW(bufW, txt); \
2341 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
2342 } while(0)
2343 #define expect_empty(hwnd, wm_get_text) \
2344 do { \
2345 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2346 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2347 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2348 memset(bufA, 0xAA, sizeof(bufA)); \
2349 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2350 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
2351 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
2352 } while(0)
2353
2354 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2355 0, 0, 200, 60, 0, 0, 0, 0);
2356 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2357
2358 ret = IsWindowUnicode(hwnd);
2359 if (is_win9x)
2360 ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
2361 else
2362 ok(ret, "RichEdit20W should be unicode under NT\n");
2363
2364 /* EM_SETTEXTEX is supported starting from version 3.0 */
2365 em_settextex_supported = is_em_settextex_supported(hwnd);
2366 trace("EM_SETTEXTEX is %ssupported on this platform\n",
2367 em_settextex_supported ? "" : "NOT ");
2368
2369 expect_empty(hwnd, WM_GETTEXT);
2370 expect_empty(hwnd, EM_GETTEXTEX);
2371
2372 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
2373 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2374 expect_textA(hwnd, WM_GETTEXT, "t");
2375 expect_textA(hwnd, EM_GETTEXTEX, "t");
2376 expect_textW(hwnd, EM_GETTEXTEX, tW);
2377
2378 ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
2379 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2380 expect_textA(hwnd, WM_GETTEXT, "te");
2381 expect_textA(hwnd, EM_GETTEXTEX, "te");
2382 expect_textW(hwnd, EM_GETTEXTEX, teW);
2383
2384 set_textA(hwnd, WM_SETTEXT, NULL);
2385 expect_empty(hwnd, WM_GETTEXT);
2386 expect_empty(hwnd, EM_GETTEXTEX);
2387
2388 if (is_win9x)
2389 set_textA(hwnd, WM_SETTEXT, textW);
2390 else
2391 set_textA(hwnd, WM_SETTEXT, textA);
2392 expect_textA(hwnd, WM_GETTEXT, textA);
2393 expect_textA(hwnd, EM_GETTEXTEX, textA);
2394 expect_textW(hwnd, EM_GETTEXTEX, textW);
2395
2396 if (em_settextex_supported)
2397 {
2398 set_textA(hwnd, EM_SETTEXTEX, textA);
2399 expect_textA(hwnd, WM_GETTEXT, textA);
2400 expect_textA(hwnd, EM_GETTEXTEX, textA);
2401 expect_textW(hwnd, EM_GETTEXTEX, textW);
2402 }
2403
2404 if (!is_win9x)
2405 {
2406 set_textW(hwnd, WM_SETTEXT, textW);
2407 expect_textW(hwnd, WM_GETTEXT, textW);
2408 expect_textA(hwnd, WM_GETTEXT, textA);
2409 expect_textW(hwnd, EM_GETTEXTEX, textW);
2410 expect_textA(hwnd, EM_GETTEXTEX, textA);
2411
2412 if (em_settextex_supported)
2413 {
2414 set_textW(hwnd, EM_SETTEXTEX, textW);
2415 expect_textW(hwnd, WM_GETTEXT, textW);
2416 expect_textA(hwnd, WM_GETTEXT, textA);
2417 expect_textW(hwnd, EM_GETTEXTEX, textW);
2418 expect_textA(hwnd, EM_GETTEXTEX, textA);
2419 }
2420 }
2421 DestroyWindow(hwnd);
2422
2423 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
2424 0, 0, 200, 60, 0, 0, 0, 0);
2425 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2426
2427 ret = IsWindowUnicode(hwnd);
2428 ok(!ret, "RichEdit20A should NOT be unicode\n");
2429
2430 set_textA(hwnd, WM_SETTEXT, textA);
2431 expect_textA(hwnd, WM_GETTEXT, textA);
2432 expect_textA(hwnd, EM_GETTEXTEX, textA);
2433 expect_textW(hwnd, EM_GETTEXTEX, textW);
2434
2435 if (em_settextex_supported)
2436 {
2437 set_textA(hwnd, EM_SETTEXTEX, textA);
2438 expect_textA(hwnd, WM_GETTEXT, textA);
2439 expect_textA(hwnd, EM_GETTEXTEX, textA);
2440 expect_textW(hwnd, EM_GETTEXTEX, textW);
2441 }
2442
2443 if (!is_win9x)
2444 {
2445 set_textW(hwnd, WM_SETTEXT, textW);
2446 expect_textW(hwnd, WM_GETTEXT, textW);
2447 expect_textA(hwnd, WM_GETTEXT, textA);
2448 expect_textW(hwnd, EM_GETTEXTEX, textW);
2449 expect_textA(hwnd, EM_GETTEXTEX, textA);
2450
2451 if (em_settextex_supported)
2452 {
2453 set_textW(hwnd, EM_SETTEXTEX, textW);
2454 expect_textW(hwnd, WM_GETTEXT, textW);
2455 expect_textA(hwnd, WM_GETTEXT, textA);
2456 expect_textW(hwnd, EM_GETTEXTEX, textW);
2457 expect_textA(hwnd, EM_GETTEXTEX, textA);
2458 }
2459 }
2460 DestroyWindow(hwnd);
2461 }
2462
2463 static void test_WM_CHAR(void)
2464 {
2465 HWND hwnd;
2466 int ret;
2467 const char * char_list = "abc\rabc\r";
2468 const char * expected_content_single = "abcabc";
2469 const char * expected_content_multi = "abc\r\nabc\r\n";
2470 char buffer[64] = {0};
2471 const char * p;
2472
2473 /* single-line control must IGNORE carriage returns */
2474 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2475 0, 0, 200, 60, 0, 0, 0, 0);
2476 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2477
2478 p = char_list;
2479 while (*p != '\0') {
2480 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2481 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2482 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2483 SendMessageA(hwnd, WM_KEYUP, *p, 1);
2484 p++;
2485 }
2486
2487 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2488 ret = strcmp(buffer, expected_content_single);
2489 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2490
2491 DestroyWindow(hwnd);
2492
2493 /* multi-line control inserts CR normally */
2494 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
2495 0, 0, 200, 60, 0, 0, 0, 0);
2496 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2497
2498 p = char_list;
2499 while (*p != '\0') {
2500 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2501 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2502 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2503 SendMessageA(hwnd, WM_KEYUP, *p, 1);
2504 p++;
2505 }
2506
2507 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2508 ret = strcmp(buffer, expected_content_multi);
2509 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2510
2511 DestroyWindow(hwnd);
2512 }
2513
2514 static void test_EM_GETTEXTLENGTHEX(void)
2515 {
2516 HWND hwnd;
2517 GETTEXTLENGTHEX gtl;
2518 int ret;
2519 const char * base_string = "base string";
2520 const char * test_string = "a\nb\n\n\r\n";
2521 const char * test_string_after = "a";
2522 const char * test_string_2 = "a\rtest\rstring";
2523 char buffer[64] = {0};
2524
2525 /* single line */
2526 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2527 0, 0, 200, 60, 0, 0, 0, 0);
2528 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2529
2530 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2531 gtl.codepage = CP_ACP;
2532 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2533 ok(ret == 0, "ret %d\n",ret);
2534
2535 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2536 gtl.codepage = CP_ACP;
2537 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2538 ok(ret == 0, "ret %d\n",ret);
2539
2540 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2541
2542 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2543 gtl.codepage = CP_ACP;
2544 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2545 ok(ret == strlen(base_string), "ret %d\n",ret);
2546
2547 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2548 gtl.codepage = CP_ACP;
2549 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2550 ok(ret == strlen(base_string), "ret %d\n",ret);
2551
2552 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2553
2554 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2555 gtl.codepage = CP_ACP;
2556 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2557 ok(ret == 1, "ret %d\n",ret);
2558
2559 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2560 gtl.codepage = CP_ACP;
2561 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2562 ok(ret == 1, "ret %d\n",ret);
2563
2564 SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2565 ret = strcmp(buffer, test_string_after);
2566 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2567
2568 DestroyWindow(hwnd);
2569
2570 /* multi line */
2571 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
2572 0, 0, 200, 60, 0, 0, 0, 0);
2573 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2574
2575 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2576 gtl.codepage = CP_ACP;
2577 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2578 ok(ret == 0, "ret %d\n",ret);
2579
2580 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2581 gtl.codepage = CP_ACP;
2582 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2583 ok(ret == 0, "ret %d\n",ret);
2584
2585 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2586
2587 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2588 gtl.codepage = CP_ACP;
2589 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2590 ok(ret == strlen(base_string), "ret %d\n",ret);
2591
2592 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2593 gtl.codepage = CP_ACP;
2594 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2595 ok(ret == strlen(base_string), "ret %d\n",ret);
2596
2597 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string_2);
2598
2599 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2600 gtl.codepage = CP_ACP;
2601 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2602 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
2603
2604 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2605 gtl.codepage = CP_ACP;
2606 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2607 ok(ret == strlen(test_string_2), "ret %d\n",ret);
2608
2609 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2610
2611 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2612 gtl.codepage = CP_ACP;
2613 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2614 ok(ret == 10, "ret %d\n",ret);
2615
2616 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2617 gtl.codepage = CP_ACP;
2618 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2619 ok(ret == 6, "ret %d\n",ret);
2620
2621 DestroyWindow(hwnd);
2622 }
2623
2624
2625 /* globals that parent and child access when checking event masks & notifications */
2626 static HWND eventMaskEditHwnd = 0;
2627 static int queriedEventMask;
2628 static int watchForEventMask = 0;
2629
2630 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
2631 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2632 {
2633 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
2634 {
2635 queriedEventMask = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2636 }
2637 return DefWindowProcA(hwnd, message, wParam, lParam);
2638 }
2639
2640 /* test event masks in combination with WM_COMMAND */
2641 static void test_eventMask(void)
2642 {
2643 HWND parent;
2644 int ret;
2645 WNDCLASSA cls;
2646 const char text[] = "foo bar\n";
2647 int eventMask;
2648
2649 /* register class to capture WM_COMMAND */
2650 cls.style = 0;
2651 cls.lpfnWndProc = ParentMsgCheckProcA;
2652 cls.cbClsExtra = 0;
2653 cls.cbWndExtra = 0;
2654 cls.hInstance = GetModuleHandleA(0);
2655 cls.hIcon = 0;
2656 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2657 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2658 cls.lpszMenuName = NULL;
2659 cls.lpszClassName = "EventMaskParentClass";
2660 if(!RegisterClassA(&cls)) assert(0);
2661
2662 parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
2663 0, 0, 200, 60, NULL, NULL, NULL, NULL);
2664 ok (parent != 0, "Failed to create parent window\n");
2665
2666 eventMaskEditHwnd = new_richedit(parent);
2667 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
2668
2669 eventMask = ENM_CHANGE | ENM_UPDATE;
2670 ret = SendMessage(eventMaskEditHwnd, EM_SETEVENTMASK, 0, (LPARAM) eventMask);
2671 ok(ret == ENM_NONE, "wrong event mask\n");
2672 ret = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2673 ok(ret == eventMask, "failed to set event mask\n");
2674
2675 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
2676 queriedEventMask = 0; /* initialize to something other than we expect */
2677 watchForEventMask = EN_CHANGE;
2678 ret = SendMessage(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM) text);
2679 ok(ret == TRUE, "failed to set text\n");
2680 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
2681 notification in response to WM_SETTEXT */
2682 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
2683 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
2684
2685 }
2686
2687
2688 START_TEST( editor )
2689 {
2690 MSG msg;
2691 time_t end;
2692
2693 /* Must explicitly LoadLibrary(). The test has no references to functions in
2694 * RICHED20.DLL, so the linker doesn't actually link to it. */
2695 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
2696 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
2697
2698 test_WM_CHAR();
2699 test_EM_FINDTEXT();
2700 test_EM_GETLINE();
2701 test_EM_SCROLLCARET();
2702 test_EM_SCROLL();
2703 test_WM_SETTEXT();
2704 test_EM_SETCHARFORMAT();
2705 test_EM_SETTEXTMODE();
2706 test_TM_PLAINTEXT();
2707 test_EM_SETOPTIONS();
2708 test_WM_GETTEXT();
2709 test_EM_AUTOURLDETECT();
2710 test_EM_SETUNDOLIMIT();
2711 test_ES_PASSWORD();
2712 test_EM_SETTEXTEX();
2713 test_EM_LIMITTEXT();
2714 test_EM_EXLIMITTEXT();
2715 test_EM_GETLIMITTEXT();
2716 test_WM_SETFONT();
2717 test_EM_GETMODIFY();
2718 test_EM_EXSETSEL();
2719 test_WM_PASTE();
2720 test_EM_StreamIn_Undo();
2721 test_EM_FORMATRANGE();
2722 test_unicode_conversions();
2723 test_EM_GETTEXTLENGTHEX();
2724 test_EM_REPLACESEL();
2725 test_eventMask();
2726
2727 /* Set the environment variable WINETEST_RICHED20 to keep windows
2728 * responsive and open for 30 seconds. This is useful for debugging.
2729 *
2730 * The message pump uses PeekMessage() to empty the queue and then sleeps for
2731 * 50ms before retrying the queue. */
2732 end = time(NULL) + 30;
2733 if (getenv( "WINETEST_RICHED20" )) {
2734 while (time(NULL) < end) {
2735 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
2736 TranslateMessage(&msg);
2737 DispatchMessage(&msg);
2738 } else {
2739 Sleep(50);
2740 }
2741 }
2742 }
2743
2744 OleFlushClipboard();
2745 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());
2746 }