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 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
370 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
371 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
373 /*Select the string "wine"*/
376 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
378 /*Copy the italicized "wine" to the clipboard*/
379 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
381 /*Reset the formatting to default*/
382 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
383 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
384 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
386 /*Clear the text in the control*/
387 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
389 /*Switch to Plain Text Mode*/
390 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
, 0);
391 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
393 /*Input "wine" again in normal format*/
394 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
396 /*Paste the italicized "wine" into the control*/
397 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
399 /*Select a character from the first "wine" string*/
402 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
404 /*Retrieve its formatting*/
405 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
408 /*Select a character from the second "wine" string*/
411 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
413 /*Retrieve its formatting*/
414 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
415 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
418 /*Compare the two formattings*/
419 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
420 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
421 cf2
.dwEffects
, cf2test
.dwEffects
);
422 /*Test TM_RICHTEXT by: switching back to Rich Text mode
423 printing "wine" in the current format(normal)
424 pasting "wine" from the clipboard(italicized)
425 comparing the two formats(should differ)*/
427 /*Attempt to switch with text in control*/
428 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
429 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
432 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
434 /*Switch into Rich Text mode*/
435 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
436 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
438 /*Print "wine" in normal formatting into the control*/
439 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
441 /*Paste italicized "wine" into the control*/
442 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
444 /*Select text from the first "wine" string*/
447 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
449 /*Retrieve its formatting*/
450 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
453 /*Select text from the second "wine" string*/
456 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
458 /*Retrieve its formatting*/
459 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
462 /*Test that the two formattings are not the same*/
463 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
464 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
465 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
467 DestroyWindow(hwndRichEdit
);
470 static void test_TM_PLAINTEXT(void)
472 /*Tests plain text properties*/
474 HWND hwndRichEdit
= new_richedit(NULL
);
475 CHARFORMAT2 cf2
, cf2test
;
479 /*Switch to plain text mode*/
481 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
482 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
484 /*Fill control with text*/
486 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "Is Wine an emulator? No it's not");
488 /*Select some text and bold it*/
492 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
493 cf2
.cbSize
= sizeof(CHARFORMAT2
);
494 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
497 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
498 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
500 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
502 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
505 /*Get the formatting of those characters*/
507 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
509 /*Get the formatting of some other characters*/
510 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
513 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
514 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2test
);
516 /*Test that they are the same as plain text allows only one formatting*/
518 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
519 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
520 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
522 /*Fill the control with a "wine" string, which when inserted will be bold*/
524 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
526 /*Copy the bolded "wine" string*/
530 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
531 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
533 /*Swap back to rich text*/
535 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
536 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
538 /*Set the default formatting to bold italics*/
540 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
, (LPARAM
) &cf2
);
541 cf2
.dwMask
|= CFM_ITALIC
;
542 cf2
.dwEffects
^= CFE_ITALIC
;
543 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
544 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
546 /*Set the text in the control to "wine", which will be bold and italicized*/
548 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
550 /*Paste the plain text "wine" string, which should take the insert
551 formatting, which at the moment is bold italics*/
553 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
555 /*Select the first "wine" string and retrieve its formatting*/
559 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
560 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2
);
562 /*Select the second "wine" string and retrieve its formatting*/
566 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
567 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
, (LPARAM
) &cf2test
);
569 /*Compare the two formattings. They should be the same.*/
571 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
572 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
573 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
574 DestroyWindow(hwndRichEdit
);
577 static void test_WM_GETTEXT(void)
579 HWND hwndRichEdit
= new_richedit(NULL
);
580 static const char text
[] = "Hello. My name is RichEdit!";
581 char buffer
[1024] = {0};
584 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
585 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
586 result
= strcmp(buffer
,text
);
588 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
589 DestroyWindow(hwndRichEdit
);
592 /* FIXME: need to test unimplemented options and robustly test wparam */
593 static void test_EM_SETOPTIONS(void)
595 HWND hwndRichEdit
= new_richedit(NULL
);
596 static const char text
[] = "Hello. My name is RichEdit!";
597 char buffer
[1024] = {0};
599 /* NEGATIVE TESTING - NO OPTIONS SET */
600 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
601 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
603 /* testing no readonly by sending 'a' to the control*/
604 SetFocus(hwndRichEdit
);
605 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
606 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
608 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
609 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
611 /* READONLY - sending 'a' to the control */
612 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
613 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
614 SetFocus(hwndRichEdit
);
615 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
616 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
617 ok(buffer
[0]==text
[0],
618 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
620 DestroyWindow(hwndRichEdit
);
623 static void check_CFE_LINK_rcvd(HWND hwnd
, int is_url
)
625 CHARFORMAT2W text_format
;
626 int link_present
= 0;
627 text_format
.cbSize
= sizeof(text_format
);
628 SendMessage(hwnd
, EM_SETSEL
, 0, 0);
629 SendMessage(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &text_format
);
630 link_present
= text_format
.dwEffects
& CFE_LINK
;
632 { /* control text is url; should get CFE_LINK */
633 ok(0 != link_present
, "URL Case: CFE_LINK not set.\n");
637 ok(0 == link_present
, "Non-URL Case: CFE_LINK set.\n");
641 static HWND
new_static_wnd(HWND parent
) {
642 return new_window("Static", 0, parent
);
645 static void test_EM_AUTOURLDETECT(void)
652 {"http://www.winehq.org", 1},
653 {"http//winehq.org", 0},
654 {"ww.winehq.org", 0},
655 {"www.winehq.org", 1},
656 {"ftp://192.168.1.1", 1},
657 {"ftp//192.168.1.1", 0},
658 {"mailto:your@email.com", 1},
659 {"prospero:prosperoserver", 1},
661 {"news:newserver", 1},
662 {"wais:waisserver", 1}
667 HWND hwndRichEdit
, parent
;
669 parent
= new_static_wnd(NULL
);
670 hwndRichEdit
= new_richedit(parent
);
671 /* Try and pass EM_AUTOURLDETECT some test wParam values */
672 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
673 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
674 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
675 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
676 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
677 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
678 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
679 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
680 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
681 /* for each url, check the text to see if CFE_LINK effect is present */
682 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
683 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
684 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
685 SendMessage(hwndRichEdit
, WM_CHAR
, 0, 0);
686 check_CFE_LINK_rcvd(hwndRichEdit
, 0);
687 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
688 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
689 SendMessage(hwndRichEdit
, WM_CHAR
, 0, 0);
690 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
);
692 DestroyWindow(hwndRichEdit
);
693 DestroyWindow(parent
);
696 static void test_EM_SCROLL(void)
699 int r
; /* return value */
700 int expr
; /* expected return value */
701 HWND hwndRichEdit
= new_richedit(NULL
);
702 int y_before
, y_after
; /* units of lines of text */
704 /* test a richedit box containing a single line of text */
705 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a");/* one line of text */
707 for (i
= 0; i
< 4; i
++) {
708 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
710 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
711 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
712 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
713 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
714 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
715 "(i == %d)\n", y_after
, i
);
719 * test a richedit box that will scroll. There are two general
720 * cases: the case without any long lines and the case with a long
723 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
725 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a\nb\nc\nd\ne");
727 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
728 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
729 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
730 "LONG LINE \nb\nc\nd\ne");
731 for (j
= 0; j
< 12; j
++) /* reset scrol position to top */
732 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
734 /* get first visible line */
735 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
736 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
738 /* get new current first visible line */
739 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
741 ok(((r
& 0xffffff00) == 0x00010000) &&
742 ((r
& 0x000000ff) != 0x00000000),
743 "EM_SCROLL page down didn't scroll by a small positive number of "
744 "lines (r == 0x%08x)\n", r
);
745 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
746 "(line %d scrolled to line %d\n", y_before
, y_after
);
750 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
751 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
752 ok(((r
& 0xffffff00) == 0x0001ff00),
753 "EM_SCROLL page up didn't scroll by a small negative number of lines "
754 "(r == 0x%08x)\n", r
);
755 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
756 "%d scrolled to line %d\n", y_before
, y_after
);
760 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
762 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
764 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
765 "(r == 0x%08x)\n", r
);
766 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
767 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
771 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
773 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
775 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
776 "(r == 0x%08x)\n", r
);
777 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
778 "line (%d scrolled to %d)\n", y_before
, y_after
);
782 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
783 SB_LINEUP
, 0); /* lineup beyond top */
785 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
788 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
789 ok(y_before
== y_after
,
790 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
794 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
795 SB_PAGEUP
, 0);/*page up beyond top */
797 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
800 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
801 ok(y_before
== y_after
,
802 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
804 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
805 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
806 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
807 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
808 SB_PAGEDOWN
, 0); /* page down beyond bot */
809 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
812 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
813 ok(y_before
== y_after
,
814 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
817 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
818 SendMessage(hwndRichEdit
, EM_SCROLL
,
819 SB_LINEDOWN
, 0); /* line down beyond bot */
820 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
823 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
824 ok(y_before
== y_after
,
825 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
828 DestroyWindow(hwndRichEdit
);
831 static void test_EM_SETUNDOLIMIT(void)
833 /* cases we test for:
834 * default behaviour - limiting at 100 undo's
835 * undo disabled - setting a limit of 0
836 * undo limited - undo limit set to some to some number, like 2
837 * bad input - sending a negative number should default to 100 undo's */
839 HWND hwndRichEdit
= new_richedit(NULL
);
844 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
847 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
848 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
849 also, multiple pastes don't combine like WM_CHAR would */
850 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
852 /* first case - check the default */
853 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
854 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
855 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
856 for (i
=0; i
<100; i
++) /* Undo 100 of them */
857 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
858 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
859 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
861 /* second case - cannot undo */
862 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
863 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
864 SendMessage(hwndRichEdit
,
865 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
866 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
867 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
869 /* third case - set it to an arbitrary number */
870 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
871 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
872 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
873 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
874 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
875 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
876 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0,0),
877 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
878 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
879 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
880 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
881 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
882 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
883 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
885 /* fourth case - setting negative numbers should default to 100 undos */
886 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
887 result
= SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
889 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
891 DestroyWindow(hwndRichEdit
);
894 static void test_ES_PASSWORD(void)
896 /* This isn't hugely testable, so we're just going to run it through its paces */
898 HWND hwndRichEdit
= new_richedit(NULL
);
901 /* First, check the default of a regular control */
902 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
904 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
906 /* Now, set it to something normal */
907 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
908 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
910 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
912 /* Now, set it to something odd */
913 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
914 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
916 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
917 DestroyWindow(hwndRichEdit
);
920 static void test_WM_SETTEXT()
922 HWND hwndRichEdit
= new_richedit(NULL
);
923 const char * TestItem1
= "TestSomeText";
924 const char * TestItem2
= "TestSomeText\r";
925 const char * TestItem2_after
= "TestSomeText\r\n";
926 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
927 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
928 char buf
[1024] = {0};
931 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
932 any solitary \r to be converted to \r\n on return. Properly paired
933 \r\n are not affected.
936 result
= SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem1
);
937 ok (result
== 1, "WM_SETTEXT returned %ld instead of 1\n", result
);
938 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buf
);
939 ok (result
== strlen(buf
),
940 "WM_GETTEXT returned %ld instead of expected %u\n",
941 result
, strlen(buf
));
942 result
= strcmp(TestItem1
, buf
);
944 "WM_SETTEXT round trip: strcmp = %ld\n", result
);
946 result
= SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem2
);
947 ok (result
== 1, "WM_SETTEXT returned %ld instead of 1\n", result
);
948 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buf
);
949 ok (result
== strlen(buf
),
950 "WM_GETTEXT returned %ld instead of expected %u\n",
951 result
, strlen(buf
));
952 result
= strcmp(TestItem2_after
, buf
);
954 "WM_SETTEXT round trip: strcmp = %ld\n", result
);
956 result
= SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem3
);
957 ok (result
== 1, "WM_SETTEXT returned %ld instead of 1\n", result
);
958 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buf
);
959 ok (result
== strlen(buf
),
960 "WM_GETTEXT returned %ld instead of expected %u\n",
961 result
, strlen(buf
));
962 result
= strcmp(TestItem3_after
, buf
);
964 "WM_SETTEXT round trip: strcmp = %ld\n", result
);
966 result
= SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem3_after
);
967 ok (result
== 1, "WM_SETTEXT returned %ld instead of 1\n", result
);
968 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buf
);
969 ok (result
== strlen(buf
),
970 "WM_GETTEXT returned %ld instead of expected %u\n",
971 result
, strlen(buf
));
972 result
= strcmp(TestItem3_after
, buf
);
974 "WM_SETTEXT round trip: strcmp = %ld\n", result
);
976 DestroyWindow(hwndRichEdit
);
979 static void test_EM_SETTEXTEX(void)
981 HWND hwndRichEdit
= new_richedit(NULL
);
984 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
986 'T', 'e', 'x', 't', 0};
987 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
991 const char * TestItem2_after
= "TestSomeText\r\n";
992 #define MAX_BUF_LEN 1024
993 WCHAR buf
[MAX_BUF_LEN
];
997 setText
.codepage
= 1200; /* no constant for unicode */
998 getText
.codepage
= 1200; /* no constant for unicode */
999 getText
.cb
= MAX_BUF_LEN
;
1000 getText
.flags
= GT_DEFAULT
;
1003 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
1004 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
1005 ok(lstrcmpW(buf
, TestItem1
) == 0,
1006 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1008 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
1009 convert \r to \r\n on return
1011 setText
.codepage
= 1200; /* no constant for unicode */
1012 getText
.codepage
= 1200; /* no constant for unicode */
1013 getText
.cb
= MAX_BUF_LEN
;
1014 getText
.flags
= GT_DEFAULT
;
1017 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem2
);
1018 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
1019 ok(lstrcmpW(buf
, TestItem2
) == 0,
1020 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1022 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
1023 SendMessage(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
1024 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
1025 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
1027 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
1028 (WPARAM
)&setText
, (LPARAM
) NULL
);
1029 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
1032 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
1033 ok(lstrlenW(buf
) == 0,
1034 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
1036 /* put some text back */
1038 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
1039 /* select some text */
1042 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1043 /* replace current selection */
1044 setText
.flags
= ST_SELECTION
;
1045 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
1046 (WPARAM
)&setText
, (LPARAM
) NULL
);
1048 "EM_SETTEXTEX with NULL lParam to replace selection"
1049 " with no text should return 0. Got %i\n",
1052 /* put some text back */
1054 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
1055 /* select some text */
1058 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1059 /* replace current selection */
1060 setText
.flags
= ST_SELECTION
;
1061 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
1062 (WPARAM
)&setText
, (LPARAM
) TestItem1
);
1064 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
1065 ok(result
== lstrlenW(TestItem1
),
1066 "EM_SETTEXTEX with NULL lParam to replace selection"
1067 " with no text should return 0. Got %i\n",
1069 ok(lstrlenW(buf
) == 22,
1070 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
1073 DestroyWindow(hwndRichEdit
);
1076 static void test_EM_LIMITTEXT(void)
1080 HWND hwndRichEdit
= new_richedit(NULL
);
1082 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
1083 * about setting the length to -1 for multiline edit controls doesn't happen.
1086 /* Don't check default gettextlimit case. That's done in other tests */
1088 /* Set textlimit to 100 */
1089 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
1090 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1092 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
1094 /* Set textlimit to 0 */
1095 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
1096 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1098 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
1100 /* Set textlimit to -1 */
1101 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
1102 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1104 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
1106 /* Set textlimit to -2 */
1107 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
1108 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1110 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
1112 DestroyWindow (hwndRichEdit
);
1116 static void test_EM_EXLIMITTEXT(void)
1118 int i
, selBegin
, selEnd
, len1
, len2
;
1120 char text
[1024 + 1];
1121 char buffer
[1024 + 1];
1122 int textlimit
= 0; /* multiple of 100 */
1123 HWND hwndRichEdit
= new_richedit(NULL
);
1125 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1126 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
1129 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1130 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1132 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
1135 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1136 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1138 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
1140 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
1141 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1142 /* default for WParam = 0 */
1143 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
1145 textlimit
= sizeof(text
)-1;
1146 memset(text
, 'W', textlimit
);
1147 text
[sizeof(text
)-1] = 0;
1148 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1149 /* maxed out text */
1150 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1152 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
1153 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1154 len1
= selEnd
- selBegin
;
1156 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
1157 SendMessage(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
1158 SendMessage(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
1159 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1160 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1161 len2
= selEnd
- selBegin
;
1164 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1167 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
1168 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1169 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1);
1170 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1171 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1172 len1
= selEnd
- selBegin
;
1175 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1178 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
1179 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1180 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
1181 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1182 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
1183 len2
= selEnd
- selBegin
;
1186 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1189 /* set text up to the limit, select all the text, then add a char */
1191 memset(text
, 'W', textlimit
);
1192 text
[textlimit
] = 0;
1193 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1194 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1195 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
1196 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
1197 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1198 result
= strcmp(buffer
, "A");
1199 ok(0 == result
, "got string = \"%s\"\n", buffer
);
1201 /* WM_SETTEXT not limited */
1203 memset(text
, 'W', textlimit
);
1204 text
[textlimit
] = 0;
1205 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
1206 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1207 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1209 ok(10 == i
, "expected 10 chars\n");
1210 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1211 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
1213 /* try inserting more text at end */
1214 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1215 ok(0 == i
, "WM_CHAR wasn't processed");
1216 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1218 ok(10 == i
, "expected 10 chars, got %i\n", i
);
1219 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1220 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
1222 /* try inserting text at beginning */
1223 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 0);
1224 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1225 ok(0 == i
, "WM_CHAR wasn't processed");
1226 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1228 ok(10 == i
, "expected 10 chars, got %i\n", i
);
1229 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1230 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
1232 /* WM_CHAR is limited */
1234 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
1235 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
1236 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1237 ok(0 == i
, "WM_CHAR wasn't processed");
1238 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1239 ok(0 == i
, "WM_CHAR wasn't processed");
1240 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1242 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
1244 DestroyWindow(hwndRichEdit
);
1247 static void test_EM_GETLIMITTEXT(void)
1250 HWND hwndRichEdit
= new_richedit(NULL
);
1252 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1253 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
1255 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
1256 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
1257 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
1259 DestroyWindow(hwndRichEdit
);
1262 static void test_WM_SETFONT(void)
1264 /* There is no invalid input or error conditions for this function.
1265 * NULL wParam and lParam just fall back to their default values
1266 * It should be noted that even if you use a gibberish name for your fonts
1267 * here, it will still work because the name is stored. They will display as
1268 * System, but will report their name to be whatever they were created as */
1270 HWND hwndRichEdit
= new_richedit(NULL
);
1271 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1272 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1273 FF_DONTCARE
, "Marlett");
1274 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1275 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1276 FF_DONTCARE
, "MS Sans Serif");
1277 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1278 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1279 FF_DONTCARE
, "Courier");
1280 LOGFONTA sentLogFont
;
1281 CHARFORMAT2A returnedCF2A
;
1283 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
1285 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
1286 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1287 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1289 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
1290 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1291 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1292 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1294 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1295 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1296 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
1297 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1298 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1299 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1301 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1302 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1303 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
1304 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
1305 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1306 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
1308 /* This last test is special since we send in NULL. We clear the variables
1309 * and just compare to "System" instead of the sent in font name. */
1310 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
1311 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
1312 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
1314 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)NULL
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1315 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
1316 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
1317 ok (!strcmp("System",returnedCF2A
.szFaceName
),
1318 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
1320 DestroyWindow(hwndRichEdit
);
1324 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
1329 const char** str
= (const char**)dwCookie
;
1330 int size
= strlen(*str
);
1331 if(size
> 3) /* let's make it peice-meal for fun */
1338 memcpy(pbBuff
, *str
, *pcb
);
1344 static void test_EM_GETMODIFY(void)
1346 HWND hwndRichEdit
= new_richedit(NULL
);
1349 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
1351 'T', 'e', 'x', 't', 0};
1352 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
1354 'O', 't', 'h', 'e', 'r',
1355 'T', 'e', 'x', 't', 0};
1356 const char* streamText
= "hello world";
1361 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
1362 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
1363 FF_DONTCARE
, "Courier");
1365 setText
.codepage
= 1200; /* no constant for unicode */
1366 setText
.flags
= ST_KEEPUNDO
;
1369 /* modify flag shouldn't be set when richedit is first created */
1370 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1372 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1374 /* setting modify flag should actually set it */
1375 SendMessage(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
1376 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1378 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1380 /* clearing modify flag should actually clear it */
1381 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1382 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1384 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1386 /* setting font doesn't change modify flag */
1387 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1388 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
,(LPARAM
) MAKELONG((WORD
) TRUE
, 0));
1389 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1391 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1393 /* setting text should set modify flag */
1394 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1395 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1396 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1398 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1400 /* undo previous text doesn't reset modify flag */
1401 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
1402 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1404 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1406 /* set text with no flag to keep undo stack should not set modify flag */
1407 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1409 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1410 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1412 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1414 /* WM_SETTEXT doesn't modify */
1415 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1416 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
1417 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1420 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1423 /* clear the text */
1424 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1425 SendMessage(hwndRichEdit
, WM_CLEAR
, 0, 0);
1426 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1428 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1431 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1432 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
1433 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1434 SendMessage(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
1435 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1437 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1439 /* copy/paste text 1 */
1440 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1441 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1442 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1443 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1444 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1446 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1448 /* copy/paste text 2 */
1449 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1450 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
1451 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1452 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 3);
1453 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1454 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1456 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1459 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1460 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 1);
1461 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1462 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1464 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1467 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
1468 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1469 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
1470 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1472 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1474 /* set char format */
1475 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1476 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1477 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
1479 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1480 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1481 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
1482 result
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
1483 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
1484 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1486 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1488 /* set para format */
1489 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1490 pf2
.cbSize
= sizeof(PARAFORMAT2
);
1491 SendMessage(hwndRichEdit
, EM_GETPARAFORMAT
, 0,
1493 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
1494 pf2
.wAlignment
= PFA_RIGHT
;
1495 SendMessage(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
) &pf2
);
1496 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1498 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1501 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
1502 es
.dwCookie
= (DWORD_PTR
)&streamText
;
1504 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
1505 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1506 (WPARAM
)(SF_TEXT
), (LPARAM
)&es
);
1507 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1509 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1511 DestroyWindow(hwndRichEdit
);
1517 long expected_retval
;
1518 int expected_getsel_start
;
1519 int expected_getsel_end
;
1520 int _exsetsel_todo_wine
;
1521 int _getsel_todo_wine
;
1524 const struct exsetsel_s exsetsel_tests
[] = {
1526 {5, 10, 10, 5, 10, 0, 0},
1527 {15, 17, 17, 15, 17, 0, 0},
1528 /* test cpMax > strlen() */
1529 {0, 100, 18, 0, 18, 0, 1},
1530 /* test cpMin == cpMax */
1531 {5, 5, 5, 5, 5, 0, 0},
1532 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1533 {-1, 0, 5, 5, 5, 0, 0},
1534 {-1, 17, 5, 5, 5, 0, 0},
1535 {-1, 18, 5, 5, 5, 0, 0},
1536 /* test cpMin < 0 && cpMax < 0 */
1537 {-1, -1, 17, 17, 17, 0, 0},
1538 {-4, -5, 17, 17, 17, 0, 0},
1539 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1540 {0, -1, 18, 0, 18, 0, 1},
1541 {17, -5, 18, 17, 18, 0, 1},
1542 {18, -3, 17, 17, 17, 0, 0},
1543 /* test if cpMin > cpMax */
1544 {15, 19, 18, 15, 18, 0, 1},
1545 {19, 15, 18, 15, 18, 0, 1}
1548 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
1553 cr
.cpMin
= setsel
->min
;
1554 cr
.cpMax
= setsel
->max
;
1555 result
= SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1557 if (setsel
->_exsetsel_todo_wine
) {
1559 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1562 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1565 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
) &start
, (LPARAM
) &end
);
1567 if (setsel
->_getsel_todo_wine
) {
1569 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
);
1572 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
);
1576 static void test_EM_EXSETSEL(void)
1578 HWND hwndRichEdit
= new_richedit(NULL
);
1580 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
1582 /* sending some text to the window */
1583 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "testing selection");
1584 /* 01234567890123456*/
1587 for (i
= 0; i
< num_tests
; i
++) {
1588 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
1591 DestroyWindow(hwndRichEdit
);
1594 static void test_EM_REPLACESEL(void)
1596 HWND hwndRichEdit
= new_richedit(NULL
);
1597 char buffer
[1024] = {0};
1600 /* sending some text to the window */
1601 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "testing selection");
1602 /* 01234567890123456*/
1605 /* FIXME add more tests */
1606 SendMessage(hwndRichEdit
, EM_SETSEL
, 7, 17);
1607 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) NULL
);
1608 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1609 r
= strcmp(buffer
, "testing");
1610 ok(0 == r
, "expected %d, got %d\n", 0, r
);
1612 DestroyWindow(hwndRichEdit
);
1615 static void test_WM_PASTE(void)
1618 char buffer
[1024] = {0};
1619 const char* text1
= "testing paste\r";
1620 const char* text1_after
= "testing paste\r\n";
1621 const char* text2
= "testing paste\r\rtesting paste";
1622 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
1623 HWND hwndRichEdit
= new_richedit(NULL
);
1625 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text1
);
1626 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 14);
1627 SendMessage(hwndRichEdit
, WM_CHAR
, 3, 0); /* ctrl-c */
1628 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
1629 SendMessage(hwndRichEdit
, WM_CHAR
, 22, 0); /* ctrl-v */
1630 SendMessage(hwndRichEdit
, WM_CHAR
, 26, 0); /* ctrl-z */
1631 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1632 result
= strcmp(text1_after
, buffer
);
1634 "test paste: strcmp = %i\n", result
);
1636 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text2
);
1637 SendMessage(hwndRichEdit
, EM_SETSEL
, 8, 13);
1638 SendMessage(hwndRichEdit
, WM_CHAR
, 3, 0); /* ctrl-c */
1639 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
1640 SendMessage(hwndRichEdit
, WM_CHAR
, 22, 0); /* ctrl-v */
1641 SendMessage(hwndRichEdit
, WM_CHAR
, 26, 0); /* ctrl-z */
1642 SendMessage(hwndRichEdit
, WM_CHAR
, 25, 0); /* ctrl-y */
1643 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1644 result
= strcmp(buffer
,text3
);
1646 "test paste: strcmp = %i\n", result
);
1648 DestroyWindow(hwndRichEdit
);
1651 static void test_EM_FORMATRANGE(void)
1656 HWND hwndRichEdit
= new_richedit(NULL
);
1658 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) haystack
);
1660 hdc
= GetDC(hwndRichEdit
);
1661 ok(hdc
!= NULL
, "Could not get HDC\n");
1663 fr
.hdc
= fr
.hdcTarget
= hdc
;
1664 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
1665 fr
.rc
.right
= fr
.rcPage
.right
= GetDeviceCaps(hdc
, HORZRES
);
1666 fr
.rc
.bottom
= fr
.rcPage
.bottom
= GetDeviceCaps(hdc
, VERTRES
);
1670 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) NULL
);
1672 ok(r
== 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r
);
1675 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) &fr
);
1677 ok(r
== 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r
);
1683 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) &fr
);
1685 ok(r
== 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r
);
1688 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) NULL
);
1690 ok(r
== 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r
);
1693 DestroyWindow(hwndRichEdit
);
1696 static int nCallbackCount
= 0;
1698 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
1701 const char text
[] = {'t','e','s','t'};
1703 if (sizeof(text
) <= cb
)
1705 if ((int)dwCookie
!= nCallbackCount
)
1711 memcpy (pbBuff
, text
, sizeof(text
));
1712 *pcb
= sizeof(text
);
1719 return 1; /* indicates callback failed */
1722 static void test_EM_StreamIn_Undo(void)
1724 /* The purpose of this test is to determine when a EM_StreamIn should be
1725 * undoable. This is important because WM_PASTE currently uses StreamIn and
1726 * pasting should always be undoable but streaming isn't always.
1729 * StreamIn plain text without SFF_SELECTION.
1730 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
1731 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
1732 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
1733 * Feel free to add tests for other text modes or StreamIn things.
1737 HWND hwndRichEdit
= new_richedit(NULL
);
1740 char buffer
[1024] = {0};
1741 const char randomtext
[] = "Some text";
1743 es
.pfnCallback
= (EDITSTREAMCALLBACK
) EditStreamCallback
;
1745 /* StreamIn, no SFF_SELECTION */
1746 es
.dwCookie
= nCallbackCount
;
1747 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1748 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1749 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
1750 SendMessage(hwndRichEdit
, EM_STREAMIN
, (WPARAM
)SF_TEXT
, (LPARAM
)&es
);
1751 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1752 result
= strcmp (buffer
,"test");
1754 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
1756 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1757 ok (result
== FALSE
,
1758 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
1760 /* StreamIn, SFF_SELECTION, but nothing selected */
1761 es
.dwCookie
= nCallbackCount
;
1762 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1763 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1764 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
1765 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1766 (WPARAM
)(SF_TEXT
|SFF_SELECTION
), (LPARAM
)&es
);
1767 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1768 result
= strcmp (buffer
,"testSome text");
1770 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
1772 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1774 "EM_STREAMIN with SFF_SELECTION but no selection set "
1775 "should create an undo\n");
1777 /* StreamIn, SFF_SELECTION, with a selection */
1778 es
.dwCookie
= nCallbackCount
;
1779 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
1780 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
1781 SendMessage(hwndRichEdit
, EM_SETSEL
,4,5);
1782 SendMessage(hwndRichEdit
, EM_STREAMIN
,
1783 (WPARAM
)(SF_TEXT
|SFF_SELECTION
), (LPARAM
)&es
);
1784 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1785 result
= strcmp (buffer
,"Sometesttext");
1787 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
1789 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
1791 "EM_STREAMIN with SFF_SELECTION and selection set "
1792 "should create an undo\n");
1796 static BOOL
is_em_settextex_supported(HWND hwnd
)
1798 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
1799 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
1802 static void test_unicode_conversions(void)
1804 static const WCHAR tW
[] = {'t',0};
1805 static const WCHAR teW
[] = {'t','e',0};
1806 static const WCHAR textW
[] = {'t','e','s','t',0};
1807 static const char textA
[] = "test";
1811 int is_win9x
, em_settextex_supported
, ret
;
1813 is_win9x
= GetVersion() & 0x80000000;
1815 #define set_textA(hwnd, wm_set_text, txt) \
1817 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
1818 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1819 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1820 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1821 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
1823 #define expect_textA(hwnd, wm_get_text, txt) \
1825 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1826 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1827 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1828 memset(bufA, 0xAA, sizeof(bufA)); \
1829 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1830 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1831 ret = lstrcmpA(bufA, txt); \
1832 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
1835 #define set_textW(hwnd, wm_set_text, txt) \
1837 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
1838 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
1839 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
1840 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
1841 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
1843 #define expect_textW(hwnd, wm_get_text, txt) \
1845 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
1846 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1847 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1848 memset(bufW, 0xAA, sizeof(bufW)); \
1851 assert(wm_get_text == EM_GETTEXTEX); \
1852 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1853 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
1857 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
1858 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
1860 ret = lstrcmpW(bufW, txt); \
1861 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
1863 #define expect_empty(hwnd, wm_get_text) \
1865 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
1866 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
1867 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
1868 memset(bufA, 0xAA, sizeof(bufA)); \
1869 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
1870 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
1871 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
1874 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
1875 0, 0, 200, 60, 0, 0, 0, 0);
1876 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
1878 ret
= IsWindowUnicode(hwnd
);
1880 ok(!ret
, "RichEdit20W should NOT be unicode under Win9x\n");
1882 ok(ret
, "RichEdit20W should be unicode under NT\n");
1884 /* EM_SETTEXTEX is supported starting from version 3.0 */
1885 em_settextex_supported
= is_em_settextex_supported(hwnd
);
1886 trace("EM_SETTEXTEX is %ssupported on this platform\n",
1887 em_settextex_supported
? "" : "NOT ");
1889 expect_empty(hwnd
, WM_GETTEXT
);
1890 expect_empty(hwnd
, EM_GETTEXTEX
);
1892 ret
= SendMessageA(hwnd
, WM_CHAR
, (WPARAM
)textW
[0], 0);
1893 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
1894 expect_textA(hwnd
, WM_GETTEXT
, "t");
1895 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
1896 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
1898 ret
= SendMessageA(hwnd
, WM_CHAR
, (WPARAM
)textA
[1], 0);
1899 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
1900 expect_textA(hwnd
, WM_GETTEXT
, "te");
1901 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
1902 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
1904 set_textA(hwnd
, WM_SETTEXT
, NULL
);
1905 expect_empty(hwnd
, WM_GETTEXT
);
1906 expect_empty(hwnd
, EM_GETTEXTEX
);
1909 set_textA(hwnd
, WM_SETTEXT
, textW
);
1911 set_textA(hwnd
, WM_SETTEXT
, textA
);
1912 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1913 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1914 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1916 if (em_settextex_supported
)
1918 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
1919 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1920 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1921 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1926 set_textW(hwnd
, WM_SETTEXT
, textW
);
1927 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1928 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1929 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1930 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1932 if (em_settextex_supported
)
1934 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
1935 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1936 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1937 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1938 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1941 DestroyWindow(hwnd
);
1943 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
1944 0, 0, 200, 60, 0, 0, 0, 0);
1945 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
1947 ret
= IsWindowUnicode(hwnd
);
1948 ok(!ret
, "RichEdit20A should NOT be unicode\n");
1950 set_textA(hwnd
, WM_SETTEXT
, textA
);
1951 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1952 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1953 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1955 if (em_settextex_supported
)
1957 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
1958 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1959 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1960 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1965 set_textW(hwnd
, WM_SETTEXT
, textW
);
1966 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1967 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1968 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1969 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1971 if (em_settextex_supported
)
1973 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
1974 expect_textW(hwnd
, WM_GETTEXT
, textW
);
1975 expect_textA(hwnd
, WM_GETTEXT
, textA
);
1976 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
1977 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
1980 DestroyWindow(hwnd
);
1984 static void test_EM_GETTEXTLENGTHEX(void)
1987 GETTEXTLENGTHEX gtl
;
1991 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
1992 0, 0, 200, 60, 0, 0, 0, 0);
1993 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
1995 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
1996 gtl
.codepage
= CP_ACP
;
1997 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
1998 ok(ret
== 0, "ret %d\n",ret
);
2000 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
2001 gtl
.codepage
= CP_ACP
;
2002 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2003 ok(ret
== 0, "ret %d\n",ret
);
2005 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) "a\nb\n\n\r\n");
2007 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
2008 gtl
.codepage
= CP_ACP
;
2009 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2010 todo_wine
ok(ret
== 1, "ret %d\n",ret
);
2012 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
2013 gtl
.codepage
= CP_ACP
;
2014 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2015 todo_wine
ok(ret
== 1, "ret %d\n",ret
);
2017 DestroyWindow(hwnd
);
2020 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
2021 0, 0, 200, 60, 0, 0, 0, 0);
2022 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
2024 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
2025 gtl
.codepage
= CP_ACP
;
2026 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2027 todo_wine
ok(ret
== 0, "ret %d\n",ret
);
2029 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
2030 gtl
.codepage
= CP_ACP
;
2031 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2032 ok(ret
== 0, "ret %d\n",ret
);
2034 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) "a\nb\n\n\r\n");
2036 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
2037 gtl
.codepage
= CP_ACP
;
2038 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2039 todo_wine
ok(ret
== 10, "ret %d\n",ret
);
2041 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
2042 gtl
.codepage
= CP_ACP
;
2043 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
2044 ok(ret
== 6, "ret %d\n",ret
);
2046 DestroyWindow(hwnd
);
2050 /* globals that parent and child access when checking event masks & notifications */
2051 static HWND eventMaskEditHwnd
= 0;
2052 static int queriedEventMask
;
2053 static int watchForEventMask
= 0;
2055 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
2056 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2058 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
2060 queriedEventMask
= SendMessage(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
2062 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2065 /* test event masks in combination with WM_COMMAND */
2066 static void test_eventMask(void)
2071 const char text
[] = "foo bar\n";
2074 /* register class to capture WM_COMMAND */
2076 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
2079 cls
.hInstance
= GetModuleHandleA(0);
2081 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
2082 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
2083 cls
.lpszMenuName
= NULL
;
2084 cls
.lpszClassName
= "EventMaskParentClass";
2085 if(!RegisterClassA(&cls
)) assert(0);
2087 parent
= CreateWindow(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
2088 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
2089 ok (parent
!= 0, "Failed to create parent window\n");
2091 eventMaskEditHwnd
= new_richedit(parent
);
2092 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
2094 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
2095 ret
= SendMessage(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, (LPARAM
) eventMask
);
2096 ok(ret
== ENM_NONE
, "wrong event mask\n");
2097 ret
= SendMessage(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
2098 ok(ret
== eventMask
, "failed to set event mask\n");
2100 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
2101 queriedEventMask
= 0; /* initialize to something other than we expect */
2102 watchForEventMask
= EN_CHANGE
;
2103 ret
= SendMessage(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
2104 ok(ret
== TRUE
, "failed to set text\n");
2105 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
2106 notification in response to WM_SETTEXT */
2107 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
2108 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
2113 START_TEST( editor
)
2118 /* Must explicitly LoadLibrary(). The test has no references to functions in
2119 * RICHED20.DLL, so the linker doesn't actually link to it. */
2120 hmoduleRichEdit
= LoadLibrary("RICHED20.DLL");
2121 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
2125 test_EM_SCROLLCARET();
2128 test_EM_SETTEXTMODE();
2129 test_TM_PLAINTEXT();
2130 test_EM_SETOPTIONS();
2132 test_EM_AUTOURLDETECT();
2133 test_EM_SETUNDOLIMIT();
2135 test_EM_SETTEXTEX();
2136 test_EM_LIMITTEXT();
2137 test_EM_EXLIMITTEXT();
2138 test_EM_GETLIMITTEXT();
2140 test_EM_GETMODIFY();
2143 test_EM_StreamIn_Undo();
2144 test_EM_FORMATRANGE();
2145 test_unicode_conversions();
2146 test_EM_GETTEXTLENGTHEX();
2147 test_EM_REPLACESEL();
2150 /* Set the environment variable WINETEST_RICHED20 to keep windows
2151 * responsive and open for 30 seconds. This is useful for debugging.
2153 * The message pump uses PeekMessage() to empty the queue and then sleeps for
2154 * 50ms before retrying the queue. */
2155 end
= time(NULL
) + 30;
2156 if (getenv( "WINETEST_RICHED20" )) {
2157 while (time(NULL
) < end
) {
2158 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
2159 TranslateMessage(&msg
);
2160 DispatchMessage(&msg
);
2167 OleFlushClipboard();
2168 ok(FreeLibrary(hmoduleRichEdit
) != 0, "error: %d\n", (int) GetLastError());