2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include <wine/test.h>
35 static HMODULE hmoduleRichEdit
;
37 static HWND
new_window(LPCTSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
39 hwnd
= CreateWindow(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
40 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
41 hmoduleRichEdit
, NULL
);
42 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
46 static HWND
new_richedit(HWND parent
) {
47 return new_window(RICHEDIT_CLASS
, ES_MULTILINE
, parent
);
50 static const char haystack
[] = "WINEWine wineWine wine WineWine";
63 struct find_s find_tests
[] = {
64 /* Find in empty text */
65 {0, -1, "foo", FR_DOWN
, -1, 0},
66 {0, -1, "foo", 0, -1, 0},
67 {0, -1, "", FR_DOWN
, -1, 0},
68 {20, 5, "foo", FR_DOWN
, -1, 0},
69 {5, 20, "foo", FR_DOWN
, -1, 0}
72 struct find_s find_tests2
[] = {
74 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1, 0},
75 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1, 0},
77 /* Subsequent finds */
78 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4, 0},
79 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13, 0},
80 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
81 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
84 {19, 20, "Wine", FR_MATCHCASE
, 13, 0},
85 {10, 20, "Wine", FR_MATCHCASE
, 4, 0},
86 {20, 10, "Wine", FR_MATCHCASE
, 13, 0},
88 /* Case-insensitive */
89 {1, 31, "wInE", FR_DOWN
, 4, 0},
90 {1, 31, "Wine", FR_DOWN
, 4, 0},
92 /* High-to-low ranges */
93 {20, 5, "Wine", FR_DOWN
, -1, 0},
94 {2, 1, "Wine", FR_DOWN
, -1, 0},
95 {30, 29, "Wine", FR_DOWN
, -1, 0},
96 {20, 5, "Wine", 0, 13, 0},
99 {5, 10, "", FR_DOWN
, -1, 0},
100 {10, 5, "", FR_DOWN
, -1, 0},
101 {0, -1, "", FR_DOWN
, -1, 0},
102 {10, 5, "", 0, -1, 0},
104 /* Whole-word search */
105 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18, 0},
106 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1, 0},
107 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18, 0},
108 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0, 0},
109 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23, 0},
110 {11, -1, "winewine", FR_WHOLEWORD
, 0, 0},
111 {31, -1, "winewine", FR_WHOLEWORD
, 23, 0},
114 {5, 200, "XXX", FR_DOWN
, -1, 0},
115 {-20, 20, "Wine", FR_DOWN
, -1, 0},
116 {-20, 20, "Wine", FR_DOWN
, -1, 0},
117 {-15, -20, "Wine", FR_DOWN
, -1, 0},
118 {1<<12, 1<<13, "Wine", FR_DOWN
, -1, 0},
120 /* Check the case noted in bug 4479 where matches at end aren't recognized */
121 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
122 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
123 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
124 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
125 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
127 /* The backwards case of bug 4479; bounds look right
128 * Fails because backward find is wrong */
129 {19, 20, "WINE", FR_MATCHCASE
, 0, 0},
130 {0, 20, "WINE", FR_MATCHCASE
, -1, 0}
133 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
) {
136 memset(&ft
, 0, sizeof(ft
));
137 ft
.chrg
.cpMin
= f
->start
;
138 ft
.chrg
.cpMax
= f
->end
;
139 ft
.lpstrText
= f
->needle
;
140 findloc
= SendMessage(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
) &ft
);
141 ok(findloc
== f
->expected_loc
,
142 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
143 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
146 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
150 memset(&ft
, 0, sizeof(ft
));
151 ft
.chrg
.cpMin
= f
->start
;
152 ft
.chrg
.cpMax
= f
->end
;
153 ft
.lpstrText
= f
->needle
;
154 findloc
= SendMessage(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
) &ft
);
155 ok(findloc
== f
->expected_loc
,
156 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
157 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
158 ok(ft
.chrgText
.cpMin
== f
->expected_loc
,
159 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
160 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMin
);
161 ok(ft
.chrgText
.cpMax
== ((f
->expected_loc
== -1) ? -1
162 : f
->expected_loc
+ strlen(f
->needle
)),
163 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d\n",
164 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMax
);
167 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
172 for (i
= 0; i
< num_tests
; i
++) {
173 if (find
[i
]._todo_wine
) {
175 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
176 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
179 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
180 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
185 static void test_EM_FINDTEXT(void)
187 HWND hwndRichEdit
= new_richedit(NULL
);
189 /* Empty rich edit control */
190 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
191 sizeof(find_tests
)/sizeof(struct find_s
));
193 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) haystack
);
196 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
197 sizeof(find_tests2
)/sizeof(struct find_s
));
199 DestroyWindow(hwndRichEdit
);
202 static const struct getline_s
{
207 {0, 10, "foo bar\r"},
212 /* Buffer smaller than line length */
218 static void test_EM_GETLINE(void)
221 HWND hwndRichEdit
= new_richedit(NULL
);
222 static const int nBuf
= 1024;
223 char dest
[1024], origdest
[1024];
224 const char text
[] = "foo bar\n"
228 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
230 memset(origdest
, 0xBB, nBuf
);
231 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
234 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
235 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
) + 1);
236 memset(dest
, 0xBB, nBuf
);
237 *(WORD
*) dest
= gl
[i
].buffer_len
;
239 /* EM_GETLINE appends a "\r\0" to the end of the line
240 * nCopied counts up to and including the '\r' */
241 nCopied
= SendMessage(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
) dest
);
242 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
244 /* two special cases since a parameter is passed via dest */
245 if (gl
[i
].buffer_len
== 0)
246 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
248 else if (gl
[i
].buffer_len
== 1)
249 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
250 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
253 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
254 "%d: expected_bytes_written=%d\n", i
, expected_bytes_written
);
255 ok(!strncmp(dest
+ expected_bytes_written
, origdest
256 + expected_bytes_written
, nBuf
- expected_bytes_written
),
257 "%d: expected_bytes_written=%d\n", i
, expected_bytes_written
);
261 DestroyWindow(hwndRichEdit
);
264 static int get_scroll_pos_y(HWND hwnd
)
267 SendMessage(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
) &p
);
268 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
272 static void move_cursor(HWND hwnd
, long charindex
)
275 cr
.cpMax
= charindex
;
276 cr
.cpMin
= charindex
;
277 SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
280 static void line_scroll(HWND hwnd
, int amount
)
282 SendMessage(hwnd
, EM_LINESCROLL
, 0, amount
);
285 static void test_EM_SCROLLCARET(void)
288 HWND hwndRichEdit
= new_richedit(NULL
);
289 const char text
[] = "aa\n"
290 "this is a long line of text that should be longer than the "
299 /* Can't verify this */
300 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
302 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
304 /* Caret above visible window */
305 line_scroll(hwndRichEdit
, 3);
306 prevY
= get_scroll_pos_y(hwndRichEdit
);
307 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
308 curY
= get_scroll_pos_y(hwndRichEdit
);
309 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
311 /* Caret below visible window */
312 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
313 line_scroll(hwndRichEdit
, -3);
314 prevY
= get_scroll_pos_y(hwndRichEdit
);
315 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
316 curY
= get_scroll_pos_y(hwndRichEdit
);
317 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
319 /* Caret in visible window */
320 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
321 prevY
= get_scroll_pos_y(hwndRichEdit
);
322 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
323 curY
= get_scroll_pos_y(hwndRichEdit
);
324 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
326 /* Caret still in visible window */
327 line_scroll(hwndRichEdit
, -1);
328 prevY
= get_scroll_pos_y(hwndRichEdit
);
329 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
330 curY
= get_scroll_pos_y(hwndRichEdit
);
331 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
333 DestroyWindow(hwndRichEdit
);
336 static void test_EM_SETTEXTMODE(void)
338 HWND hwndRichEdit
= new_richedit(NULL
);
339 CHARFORMAT2 cf2
, cf2test
;
343 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
344 /*Insert text into the control*/
346 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
348 /*Attempt to change the control to plain text mode*/
349 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
, 0);
350 ok(rc
!= 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc
);
352 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
353 If rich text is pasted, it should have the same formatting as the rest
354 of the text in the control*/
357 *NOTE: If the default text was already italicized, the test will simply
358 reverse; in other words, it will copy a regular "wine" into a plain
359 text window that uses an italicized format*/
360 cf2
.cbSize
= sizeof(CHARFORMAT2
);
361 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
364 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
365 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
367 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
368 however, SCF_ALL has been implemented*/
369 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
370 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
372 /*Select the string "wine"*/
375 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
377 /*Copy the italicized "wine" to the clipboard*/
378 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
380 /*Reset the formatting to default*/
381 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
382 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
384 /*Clear the text in the control*/
385 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
387 /*Switch to Plain Text Mode*/
388 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
, 0);
389 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
391 /*Input "wine" again in normal format*/
392 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
394 /*Paste the italicized "wine" into the control*/
395 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
397 /*Select a character from the first "wine" string*/
400 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
402 /*Retrieve its formatting*/
403 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
406 /*Select a character from the second "wine" string*/
409 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
411 /*Retrieve its formatting*/
412 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
413 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
416 /*Compare the two formattings*/
417 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
418 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
419 cf2
.dwEffects
, cf2test
.dwEffects
);
420 /*Test TM_RICHTEXT by: switching back to Rich Text mode
421 printing "wine" in the current format(normal)
422 pasting "wine" from the clipboard(italicized)
423 comparing the two formats(should differ)*/
425 /*Attempt to switch with text in control*/
426 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
427 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
430 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
432 /*Switch into Rich Text mode*/
433 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
434 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
436 /*Print "wine" in normal formatting into the control*/
437 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
439 /*Paste italicized "wine" into the control*/
440 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
442 /*Select text from the first "wine" string*/
445 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
447 /*Retrieve its formatting*/
448 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
451 /*Select text from the second "wine" string*/
454 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
456 /*Retrieve its formatting*/
457 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
460 /*Test that the two formattings are not the same*/
461 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
462 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
463 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
465 DestroyWindow(hwndRichEdit
);
468 static void test_TM_PLAINTEXT(void)
470 /*Tests plain text properties*/
472 HWND hwndRichEdit
= new_richedit(NULL
);
473 CHARFORMAT2 cf2
, cf2test
;
476 /*Switch to plain text mode*/
478 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
479 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
481 /*Fill control with text*/
483 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "Is Wine an emulator? No it's not");
485 /*Select some text and bold it*/
489 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
490 cf2
.cbSize
= sizeof(CHARFORMAT2
);
491 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
494 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
495 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
497 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
499 /*Get the formatting of those characters*/
501 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
503 /*Get the formatting of some other characters*/
504 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
507 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
508 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2test
);
510 /*Test that they are the same as plain text allows only one formatting*/
512 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
513 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
514 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
516 /*Fill the control with a "wine" string, which when inserted will be bold*/
518 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
520 /*Copy the bolded "wine" string*/
524 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
525 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
527 /*Swap back to rich text*/
529 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
530 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
532 /*Set the default formatting to bold italics*/
534 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
, (LPARAM
) &cf2
);
535 cf2
.dwMask
|= CFM_ITALIC
;
536 cf2
.dwEffects
^= CFE_ITALIC
;
537 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
539 /*Set the text in the control to "wine", which will be bold and italicized*/
541 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
543 /*Paste the plain text "wine" string, which should take the insert
544 formatting, which at the moment is bold italics*/
546 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
548 /*Select the first "wine" string and retrieve its formatting*/
552 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
553 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
555 /*Select the second "wine" string and retrieve its formatting*/
559 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
560 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2test
);
562 /*Compare the two formattings. They should be the same.*/
564 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
565 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
566 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
567 DestroyWindow(hwndRichEdit
);
570 static void test_WM_GETTEXT(void)
572 HWND hwndRichEdit
= new_richedit(NULL
);
573 static const char text
[] = "Hello. My name is RichEdit!";
574 char buffer
[1024] = {0};
577 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
578 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
579 result
= strcmp(buffer
,text
);
581 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
582 DestroyWindow(hwndRichEdit
);
585 /* FIXME: need to test unimplemented options and robustly test wparam */
586 static void test_EM_SETOPTIONS(void)
588 HWND hwndRichEdit
= new_richedit(NULL
);
589 static const char text
[] = "Hello. My name is RichEdit!";
590 char buffer
[1024] = {0};
592 /* NEGATIVE TESTING - NO OPTIONS SET */
593 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
594 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
596 /* testing no readonly by sending 'a' to the control*/
597 SetFocus(hwndRichEdit
);
598 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
599 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
601 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
602 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
604 /* READONLY - sending 'a' to the control */
605 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
606 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
607 SetFocus(hwndRichEdit
);
608 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
609 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
610 ok(buffer
[0]==text
[0],
611 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
613 DestroyWindow(hwndRichEdit
);
616 static void check_CFE_LINK_rcvd(HWND hwnd
, int is_url
)
618 CHARFORMAT2W text_format
;
619 int link_present
= 0;
620 text_format
.cbSize
= sizeof(text_format
);
621 SendMessage(hwnd
, EM_SETSEL
, 0, 0);
622 SendMessage(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &text_format
);
623 link_present
= text_format
.dwEffects
& CFE_LINK
;
625 { /* control text is url; should get CFE_LINK */
626 ok(0 != link_present
, "URL Case: CFE_LINK not set.\n");
630 ok(0 == link_present
, "Non-URL Case: CFE_LINK set.\n");
634 static HWND
new_static_wnd(HWND parent
) {
635 return new_window("Static", 0, parent
);
638 static void test_EM_AUTOURLDETECT(void)
645 {"http://www.winehq.org", 1},
646 {"http//winehq.org", 0},
647 {"ww.winehq.org", 0},
648 {"www.winehq.org", 1},
649 {"ftp://192.168.1.1", 1},
650 {"ftp//192.168.1.1", 0},
651 {"mailto:your@email.com", 1},
652 {"prospero:prosperoserver", 1},
654 {"news:newserver", 1},
655 {"wais:waisserver", 1}
660 HWND hwndRichEdit
, parent
;
662 parent
= new_static_wnd(NULL
);
663 hwndRichEdit
= new_richedit(parent
);
664 /* Try and pass EM_AUTOURLDETECT some test wParam values */
665 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
666 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
667 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
668 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
669 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
670 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
671 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
672 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
673 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
674 /* for each url, check the text to see if CFE_LINK effect is present */
675 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
676 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
677 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
678 SendMessage(hwndRichEdit
, WM_CHAR
, 0, 0);
679 check_CFE_LINK_rcvd(hwndRichEdit
, 0);
680 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
681 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
682 SendMessage(hwndRichEdit
, WM_CHAR
, 0, 0);
683 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
);
685 DestroyWindow(hwndRichEdit
);
686 DestroyWindow(parent
);
689 static void test_EM_SCROLL(void)
692 int r
; /* return value */
693 int expr
; /* expected return value */
694 HWND hwndRichEdit
= new_richedit(NULL
);
695 int y_before
, y_after
; /* units of lines of text */
697 /* test a richedit box containing a single line of text */
698 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a");/* one line of text */
700 for (i
= 0; i
< 4; i
++) {
701 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
703 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
704 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
705 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
706 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
707 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
708 "(i == %d)\n", y_after
, i
);
712 * test a richedit box that will scroll. There are two general
713 * cases: the case without any long lines and the case with a long
716 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
718 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a\nb\nc\nd\ne");
720 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
721 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
722 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
723 "LONG LINE \nb\nc\nd\ne");
724 for (j
= 0; j
< 12; j
++) /* reset scrol position to top */
725 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
727 /* get first visible line */
728 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
729 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
731 /* get new current first visible line */
732 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
734 ok(((r
& 0xffffff00) == 0x00010000) &&
735 ((r
& 0x000000ff) != 0x00000000),
736 "EM_SCROLL page down didn't scroll by a small positive number of "
737 "lines (r == 0x%08x)\n", r
);
738 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
739 "(line %d scrolled to line %d\n", y_before
, y_after
);
743 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
744 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
745 ok(((r
& 0xffffff00) == 0x0001ff00),
746 "EM_SCROLL page up didn't scroll by a small negative number of lines "
747 "(r == 0x%08x)\n", r
);
748 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
749 "%d scrolled to line %d\n", y_before
, y_after
);
753 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
755 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
757 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
758 "(r == 0x%08x)\n", r
);
759 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
760 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
764 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
766 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
768 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
769 "(r == 0x%08x)\n", r
);
770 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
771 "line (%d scrolled to %d)\n", y_before
, y_after
);
775 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
776 SB_LINEUP
, 0); /* lineup beyond top */
778 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
781 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
782 ok(y_before
== y_after
,
783 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
787 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
788 SB_PAGEUP
, 0);/*page up beyond top */
790 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
793 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
794 ok(y_before
== y_after
,
795 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
797 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
798 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
799 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
800 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
801 SB_PAGEDOWN
, 0); /* page down beyond bot */
802 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
805 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
806 ok(y_before
== y_after
,
807 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
810 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
811 SendMessage(hwndRichEdit
, EM_SCROLL
,
812 SB_LINEDOWN
, 0); /* line down beyond bot */
813 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
816 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
817 ok(y_before
== y_after
,
818 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
821 DestroyWindow(hwndRichEdit
);
824 static void test_EM_SETUNDOLIMIT(void)
826 /* cases we test for:
827 * default behaviour - limiting at 100 undo's
828 * undo disabled - setting a limit of 0
829 * undo limited - undo limit set to some to some number, like 2
830 * bad input - sending a negative number should default to 100 undo's */
832 HWND hwndRichEdit
= new_richedit(NULL
);
837 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
840 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
841 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
842 also, multiple pastes don't combine like WM_CHAR would */
843 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
845 /* first case - check the default */
846 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
847 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
848 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
849 for (i
=0; i
<100; i
++) /* Undo 100 of them */
850 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
851 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
852 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
854 /* second case - cannot undo */
855 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
856 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
857 SendMessage(hwndRichEdit
,
858 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
859 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
860 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
862 /* third case - set it to an arbitrary number */
863 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
864 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
865 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
866 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
867 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
868 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
869 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0,0),
870 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
871 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
872 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
873 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
874 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
875 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
876 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
878 /* fourth case - setting negative numbers should default to 100 undos */
879 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
880 result
= SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
882 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
884 DestroyWindow(hwndRichEdit
);
887 static void test_ES_PASSWORD(void)
889 /* This isn't hugely testable, so we're just going to run it through its paces */
891 HWND hwndRichEdit
= new_richedit(NULL
);
894 /* First, check the default of a regular control */
895 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
897 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
899 /* Now, set it to something normal */
900 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
901 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
903 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
905 /* Now, set it to something odd */
906 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
907 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
909 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
910 DestroyWindow(hwndRichEdit
);
913 static void test_EM_SETTEXTEX(void)
915 HWND hwndRichEdit
= new_richedit(NULL
);
918 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
920 'T', 'e', 'x', 't', 0};
921 #define MAX_BUF_LEN 1024
922 WCHAR buf
[MAX_BUF_LEN
];
926 setText
.codepage
= 1200; /* no constant for unicode */
927 getText
.codepage
= 1200; /* no constant for unicode */
928 getText
.cb
= MAX_BUF_LEN
;
929 getText
.flags
= GT_DEFAULT
;
932 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
933 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
934 ok(lstrcmpW(buf
, TestItem1
) == 0,
935 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
937 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
938 (WPARAM
)&setText
, (LPARAM
) NULL
);
939 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
942 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
943 ok(lstrlenW(buf
) == 0,
944 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
946 /* put some text back */
948 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
949 /* select some text */
952 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
953 /* replace current selection */
954 setText
.flags
= ST_SELECTION
;
955 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
956 (WPARAM
)&setText
, (LPARAM
) NULL
);
958 "EM_SETTEXTEX with NULL lParam to replace selection"
959 " with no text should return 0. Got %i\n",
962 /* put some text back */
964 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
965 /* select some text */
968 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
969 /* replace current selection */
970 setText
.flags
= ST_SELECTION
;
971 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
972 (WPARAM
)&setText
, (LPARAM
) TestItem1
);
974 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
975 ok(result
== lstrlenW(TestItem1
),
976 "EM_SETTEXTEX with NULL lParam to replace selection"
977 " with no text should return 0. Got %i\n",
979 ok(lstrlenW(buf
) == 22,
980 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
983 DestroyWindow(hwndRichEdit
);
986 static void test_EM_LIMITTEXT(void)
990 HWND hwndRichEdit
= new_richedit(NULL
);
992 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
993 * about setting the length to -1 for multiline edit controls doesn't happen.
996 /* Don't check default gettextlimit case. That's done in other tests */
998 /* Set textlimit to 100 */
999 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
1000 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1002 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
1004 /* Set textlimit to 0 */
1005 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
1006 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1008 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
1010 /* Set textlimit to -1 */
1011 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
1012 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1014 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
1016 /* Set textlimit to -2 */
1017 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
1018 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1020 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
1022 DestroyWindow (hwndRichEdit
);
1026 static void test_EM_EXLIMITTEXT(void)
1028 int i
, selBegin
, selEnd
, len1
, len2
;
1030 char text
[1024 + 1];
1031 char buffer
[1024 + 1];
1032 int textlimit
= 0; /* multiple of 100 */
1033 HWND hwndRichEdit
= new_richedit(NULL
);
1035 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1036 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
1039 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1040 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1042 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
1045 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1046 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1048 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
1050 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
1051 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1052 /* default for WParam = 0 */
1053 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
1055 textlimit
= sizeof(text
)-1;
1056 memset(text
, 'W', textlimit
);
1057 text
[sizeof(text
)-1] = 0;
1058 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1059 /* maxed out text */
1060 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1062 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
1063 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1064 len1
= selEnd
- selBegin
;
1066 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
1067 SendMessage(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
1068 SendMessage(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
1069 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1070 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1071 len2
= selEnd
- selBegin
;
1074 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1077 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
1078 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1079 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1);
1080 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1081 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1082 len1
= selEnd
- selBegin
;
1085 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1088 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
1089 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1090 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
1091 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1092 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1093 len2
= selEnd
- selBegin
;
1096 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1099 /* set text up to the limit, select all the text, then add a char */
1101 memset(text
, 'W', textlimit
);
1102 text
[textlimit
] = 0;
1103 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1104 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1105 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1106 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1107 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1108 result
= strcmp(buffer
, "A");
1109 ok(0 == result
, "got string = \"%s\"\n", buffer
);
1111 DestroyWindow(hwndRichEdit
);
1114 static void test_EM_GETLIMITTEXT(void)
1117 HWND hwndRichEdit
= new_richedit(NULL
);
1119 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1120 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
1122 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
1123 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1124 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
1126 DestroyWindow(hwndRichEdit
);
1129 static void test_WM_SETFONT(void)
1131 /* There is no invalid input or error conditions for this function.
1132 * NULL wParam and lParam just fall back to their default values
1133 * It should be noted that even if you use a gibberish name for your fonts
1134 * here, it will still work because the name is stored. They will display as
1135 * System, but will report their name to be whatever they were created as */
1137 HWND hwndRichEdit
= new_richedit(NULL
);
1138 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1139 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1140 FF_DONTCARE
, "Marlett");
1141 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1142 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1143 FF_DONTCARE
, "MS Sans Serif");
1144 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1145 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1146 FF_DONTCARE
, "Courier");
1147 LOGFONTA sentLogFont
;
1148 CHARFORMAT2A returnedCF2A
;
1150 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
1152 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
1153 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1154 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1156 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
1157 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1158 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1159 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1161 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1162 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1163 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
1164 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1165 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1166 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1168 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1169 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1170 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
1171 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1172 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1173 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1175 /* This last test is special since we send in NULL. We clear the variables
1176 * and just compare to "System" instead of the sent in font name. */
1177 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
1178 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
1179 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
1181 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)NULL
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1182 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1183 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
1184 ok (!strcmp("System",returnedCF2A
.szFaceName
),
1185 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
1187 DestroyWindow(hwndRichEdit
);
1191 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
1196 const char** str
= (const char**)dwCookie
;
1197 int size
= strlen(*str
);
1198 if(size
> 3) /* let's make it peice-meal for fun */
1205 memcpy(pbBuff
, *str
, *pcb
);
1211 static void test_EM_GETMODIFY(void)
1213 HWND hwndRichEdit
= new_richedit(NULL
);
1216 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
1218 'T', 'e', 'x', 't', 0};
1219 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
1221 'O', 't', 'h', 'e', 'r',
1222 'T', 'e', 'x', 't', 0};
1223 const char* streamText
= "hello world";
1228 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1229 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1230 FF_DONTCARE
, "Courier");
1232 setText
.codepage
= 1200; /* no constant for unicode */
1233 setText
.flags
= ST_KEEPUNDO
;
1236 /* modify flag shouldn't be set when richedit is first created */
1237 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1239 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1241 /* setting modify flag should actually set it */
1242 SendMessage(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
1243 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1245 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1247 /* clearing modify flag should actually clear it */
1248 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1249 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1251 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1253 /* setting font doesn't change modify flag */
1254 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1255 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1256 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1258 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1260 /* setting text should set modify flag */
1261 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1262 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1263 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1265 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1267 /* undo previous text doesn't reset modify flag */
1268 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
1269 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1271 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1273 /* set text with no flag to keep undo stack should not set modify flag */
1274 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1276 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1277 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1279 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1281 /* WM_SETTEXT doesn't modify */
1282 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1283 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
1284 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1287 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1290 /* clear the text */
1291 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1292 SendMessage(hwndRichEdit
, WM_CLEAR
, 0, 0);
1293 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1295 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1298 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1299 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1300 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1301 SendMessage(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
1302 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1304 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1306 /* copy/paste text 1 */
1307 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1308 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1309 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1310 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1311 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1313 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1315 /* copy/paste text 2 */
1316 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1317 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1318 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1319 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 3);
1320 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1321 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1323 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1326 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1327 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 1);
1328 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1329 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1331 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1334 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1335 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1336 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
1337 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1339 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1341 /* set char format */
1342 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1343 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1344 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
1346 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1347 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1348 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
1349 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1351 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1353 /* set para format */
1354 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1355 pf2
.cbSize
= sizeof(PARAFORMAT2
);
1356 SendMessage(hwndRichEdit
, EM_GETPARAFORMAT
, 0,
1358 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
1359 pf2
.wAlignment
= PFA_RIGHT
;
1360 SendMessage(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
) &pf2
);
1361 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1363 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1366 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1367 es
.dwCookie
= (DWORD_PTR
)&streamText
;
1369 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
1370 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1371 (WPARAM
)(SF_TEXT
), (LPARAM
)&es
);
1372 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1374 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1376 DestroyWindow(hwndRichEdit
);
1382 long expected_retval
;
1383 int expected_getsel_start
;
1384 int expected_getsel_end
;
1385 int _exsetsel_todo_wine
;
1386 int _getsel_todo_wine
;
1389 const struct exsetsel_s exsetsel_tests
[] = {
1391 {5, 10, 10, 5, 10, 0, 0},
1392 {15, 17, 17, 15, 17, 0, 0},
1393 /* test cpMax > strlen() */
1394 {0, 100, 18, 0, 18, 0, 1},
1395 /* test cpMin == cpMax */
1396 {5, 5, 5, 5, 5, 0, 0},
1397 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1398 {-1, 0, 5, 5, 5, 0, 0},
1399 {-1, 17, 5, 5, 5, 0, 0},
1400 {-1, 18, 5, 5, 5, 0, 0},
1401 /* test cpMin < 0 && cpMax < 0 */
1402 {-1, -1, 17, 17, 17, 0, 0},
1403 {-4, -5, 17, 17, 17, 0, 0},
1404 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1405 {0, -1, 18, 0, 18, 0, 1},
1406 {17, -5, 18, 17, 18, 0, 1},
1407 {18, -3, 17, 17, 17, 0, 0},
1408 /* test if cpMin > cpMax */
1409 {15, 19, 18, 15, 18, 0, 1},
1410 {19, 15, 18, 15, 18, 0, 1}
1413 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
1418 cr
.cpMin
= setsel
->min
;
1419 cr
.cpMax
= setsel
->max
;
1420 result
= SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1422 if (setsel
->_exsetsel_todo_wine
) {
1424 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1427 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1430 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
) &start
, (LPARAM
) &end
);
1432 if (setsel
->_getsel_todo_wine
) {
1434 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
1437 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
1441 static void test_EM_EXSETSEL(void)
1443 HWND hwndRichEdit
= new_richedit(NULL
);
1445 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
1447 /* sending some text to the window */
1448 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "testing selection");
1449 /* 01234567890123456*/
1452 for (i
= 0; i
< num_tests
; i
++) {
1453 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
1456 DestroyWindow(hwndRichEdit
);
1459 static void test_WM_PASTE(void)
1462 char buffer
[1024] = {0};
1463 const char* text1
= "testing paste\r";
1464 const char* text2
= "testing paste\r\rtesting paste";
1465 const char* text3
= "testing paste\rpaste\rtesting paste";
1466 HWND hwndRichEdit
= new_richedit(NULL
);
1468 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text1
);
1469 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 14);
1470 SendMessage(hwndRichEdit
, WM_CHAR
, 3, 0); /* ctrl-c */
1471 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
1472 SendMessage(hwndRichEdit
, WM_CHAR
, 22, 0); /* ctrl-v */
1473 SendMessage(hwndRichEdit
, WM_CHAR
, 26, 0); /* ctrl-z */
1474 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1475 result
= strcmp(text1
, buffer
);
1477 "test paste: strcmp = %i\n", result
);
1479 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text2
);
1480 SendMessage(hwndRichEdit
, EM_SETSEL
, 8, 13);
1481 SendMessage(hwndRichEdit
, WM_CHAR
, 3, 0); /* ctrl-c */
1482 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
1483 SendMessage(hwndRichEdit
, WM_CHAR
, 22, 0); /* ctrl-v */
1484 SendMessage(hwndRichEdit
, WM_CHAR
, 26, 0); /* ctrl-z */
1485 SendMessage(hwndRichEdit
, WM_CHAR
, 25, 0); /* ctrl-y */
1486 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1487 result
= strcmp(buffer
,text3
);
1489 "test paste: strcmp = %i\n", result
);
1491 DestroyWindow(hwndRichEdit
);
1494 static int nCallbackCount
= 0;
1496 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
1499 const char text
[] = {'t','e','s','t'};
1501 if (sizeof(text
) <= cb
)
1503 if ((int)dwCookie
!= nCallbackCount
)
1509 memcpy (pbBuff
, text
, sizeof(text
));
1510 *pcb
= sizeof(text
);
1517 return 1; /* indicates callback failed */
1520 static void test_EM_StreamIn_Undo(void)
1522 /* The purpose of this test is to determine when a EM_StreamIn should be
1523 * undoable. This is important because WM_PASTE currently uses StreamIn and
1524 * pasting should always be undoable but streaming isn't always.
1527 * StreamIn plain text without SFF_SELECTION.
1528 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
1529 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
1530 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
1531 * Feel free to add tests for other text modes or StreamIn things.
1535 HWND hwndRichEdit
= new_richedit(NULL
);
1538 char buffer
[1024] = {0};
1539 const char randomtext
[] = "Some text";
1541 es
.pfnCallback
= (EDITSTREAMCALLBACK
) EditStreamCallback
;
1543 /* StreamIn, no SFF_SELECTION */
1544 es
.dwCookie
= nCallbackCount
;
1545 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1546 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1547 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
1548 SendMessage(hwndRichEdit
, EM_STREAMIN
, (WPARAM
)SF_TEXT
, (LPARAM
)&es
);
1549 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1550 result
= strcmp (buffer
,"test");
1552 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
1554 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1555 ok (result
== FALSE
,
1556 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
1558 /* StreamIn, SFF_SELECTION, but nothing selected */
1559 es
.dwCookie
= nCallbackCount
;
1560 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1561 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1562 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
1563 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1564 (WPARAM
)(SF_TEXT
|SFF_SELECTION
), (LPARAM
)&es
);
1565 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1566 result
= strcmp (buffer
,"testSome text");
1568 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
1570 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1572 "EM_STREAMIN with SFF_SELECTION but no selection set "
1573 "should create an undo\n");
1575 /* StreamIn, SFF_SELECTION, with a selection */
1576 es
.dwCookie
= nCallbackCount
;
1577 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1578 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1579 SendMessage(hwndRichEdit
, EM_SETSEL
,4,5);
1580 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1581 (WPARAM
)(SF_TEXT
|SFF_SELECTION
), (LPARAM
)&es
);
1582 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1583 result
= strcmp (buffer
,"Sometesttext");
1585 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
1587 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1589 "EM_STREAMIN with SFF_SELECTION and selection set "
1590 "should create an undo\n");
1594 static BOOL
is_em_settextex_supported(HWND hwnd
)
1596 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
1597 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
1600 static void test_unicode_conversions(void)
1602 static const WCHAR tW
[] = {'t',0};
1603 static const WCHAR teW
[] = {'t','e',0};
1604 static const WCHAR textW
[] = {'t','e','s','t',0};
1605 static const char textA
[] = "test";
1609 int is_win9x
, em_settextex_supported
, ret
;
1611 is_win9x
= GetVersion() & 0x80000000;
1613 #define set_textA(hwnd, wm_set_text, txt) \
1615 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
1616 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1617 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1618 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1619 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
1621 #define expect_textA(hwnd, wm_get_text, txt) \
1623 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1624 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1625 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1626 memset(bufA, 0xAA, sizeof(bufA)); \
1627 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1628 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1629 ret = lstrcmpA(bufA, txt); \
1630 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
1633 #define set_textW(hwnd, wm_set_text, txt) \
1635 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
1636 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1637 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1638 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1639 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
1641 #define expect_textW(hwnd, wm_get_text, txt) \
1643 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
1644 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1645 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1646 memset(bufW, 0xAA, sizeof(bufW)); \
1649 assert(wm_get_text == EM_GETTEXTEX); \
1650 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1651 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1655 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1656 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
1658 ret = lstrcmpW(bufW, txt); \
1659 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
1661 #define expect_empty(hwnd, wm_get_text) \
1663 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1664 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1665 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1666 memset(bufA, 0xAA, sizeof(bufA)); \
1667 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1668 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
1669 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
1672 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
1673 0, 0, 200, 60, 0, 0, 0, 0);
1674 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
1676 ret
= IsWindowUnicode(hwnd
);
1678 ok(!ret
, "RichEdit20W should NOT be unicode under Win9x\n");
1680 ok(ret
, "RichEdit20W should be unicode under NT\n");
1682 /* EM_SETTEXTEX is supported starting from version 3.0 */
1683 em_settextex_supported
= is_em_settextex_supported(hwnd
);
1684 trace("EM_SETTEXTEX is %ssupported on this platform\n",
1685 em_settextex_supported
? "" : "NOT ");
1687 expect_empty(hwnd
, WM_GETTEXT
);
1688 expect_empty(hwnd
, EM_GETTEXTEX
);
1690 ret
= SendMessageA(hwnd
, WM_CHAR
, (WPARAM
)textW
[0], 0);
1691 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
1692 expect_textA(hwnd
, WM_GETTEXT
, "t");
1693 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
1694 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
1696 ret
= SendMessageA(hwnd
, WM_CHAR
, (WPARAM
)textA
[1], 0);
1697 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
1698 expect_textA(hwnd
, WM_GETTEXT
, "te");
1699 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
1700 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
1702 set_textA(hwnd
, WM_SETTEXT
, NULL
);
1703 expect_empty(hwnd
, WM_GETTEXT
);
1704 expect_empty(hwnd
, EM_GETTEXTEX
);
1707 set_textA(hwnd
, WM_SETTEXT
, textW
);
1709 set_textA(hwnd
, WM_SETTEXT
, textA
);
1710 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1711 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1712 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1714 if (em_settextex_supported
)
1716 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
1717 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1718 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1719 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1724 set_textW(hwnd
, WM_SETTEXT
, textW
);
1725 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1726 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1727 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1728 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1730 if (em_settextex_supported
)
1732 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
1733 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1734 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1735 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1736 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1739 DestroyWindow(hwnd
);
1741 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
1742 0, 0, 200, 60, 0, 0, 0, 0);
1743 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
1745 ret
= IsWindowUnicode(hwnd
);
1746 ok(!ret
, "RichEdit20A should NOT be unicode\n");
1748 set_textA(hwnd
, WM_SETTEXT
, textA
);
1749 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1750 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1751 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1753 if (em_settextex_supported
)
1755 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
1756 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1757 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1758 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1763 set_textW(hwnd
, WM_SETTEXT
, textW
);
1764 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1765 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1766 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1767 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1769 if (em_settextex_supported
)
1771 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
1772 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1773 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1774 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1775 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1778 DestroyWindow(hwnd
);
1781 START_TEST( editor
)
1786 /* Must explicitly LoadLibrary(). The test has no references to functions in
1787 * RICHED20.DLL, so the linker doesn't actually link to it. */
1788 hmoduleRichEdit
= LoadLibrary("RICHED20.DLL");
1789 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
1793 test_EM_SCROLLCARET();
1795 test_EM_SETTEXTMODE();
1796 test_TM_PLAINTEXT();
1797 test_EM_SETOPTIONS();
1799 test_EM_AUTOURLDETECT();
1800 test_EM_SETUNDOLIMIT();
1802 test_EM_SETTEXTEX();
1803 test_EM_LIMITTEXT();
1804 test_EM_EXLIMITTEXT();
1805 test_EM_GETLIMITTEXT();
1807 test_EM_GETMODIFY();
1810 test_EM_StreamIn_Undo();
1811 test_unicode_conversions();
1813 /* Set the environment variable WINETEST_RICHED20 to keep windows
1814 * responsive and open for 30 seconds. This is useful for debugging.
1816 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1817 * 50ms before retrying the queue. */
1818 end
= time(NULL
) + 30;
1819 if (getenv( "WINETEST_RICHED20" )) {
1820 while (time(NULL
) < end
) {
1821 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
1822 TranslateMessage(&msg
);
1823 DispatchMessage(&msg
);
1830 OleFlushClipboard();
1831 ok(FreeLibrary(hmoduleRichEdit
) != 0, "error: %d\n", (int) GetLastError());