2 * Unit test suite for rich edit control 1.0
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
7 * Copyright 2007 Alex VillacĂs Lasso
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include <wine/test.h>
37 static HMODULE hmoduleRichEdit
;
38 static BOOL is_lang_japanese
;
40 static HWND
new_window(LPCSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
42 hwnd
= CreateWindowA(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
43 |WS_VISIBLE
, 0, 0, 500, 60, parent
, NULL
,
44 hmoduleRichEdit
, NULL
);
45 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
49 static HWND
new_richedit(HWND parent
) {
50 return new_window(RICHEDIT_CLASS10A
, ES_MULTILINE
, parent
);
53 static BOOL
is_rtl(void) {
56 return (GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT
, LOCALE_FONTSIGNATURE
,
57 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
58 (sig
.lsUsb
[3] & 0x08000000) != 0);
61 static void test_WM_SETTEXT(void)
69 { "TestSomeText", 1, 1},
70 { "TestSomeText\r", 1, 1},
71 { "TestSomeText\rSomeMoreText\r", 2, 1, 1}, /* NT4 and below */
72 { "TestSomeText\n\nTestSomeText", 3, 3},
73 { "TestSomeText\r\r\nTestSomeText", 2, 2},
74 { "TestSomeText\r\r\n\rTestSomeText", 3, 2, 2}, /* NT4 and below */
75 { "TestSomeText\r\n\r\r\n\rTestSomeText", 4, 3, 3}, /* NT4 and below */
76 { "TestSomeText\r\n", 2, 2},
77 { "TestSomeText\r\nSomeMoreText\r\n", 3, 3},
78 { "TestSomeText\r\n\r\nTestSomeText", 3, 3},
79 { "TestSomeText TestSomeText", 1, 1},
80 { "TestSomeText \r\nTestSomeText", 2, 2},
81 { "TestSomeText\r\n \r\nTestSomeText", 3, 3},
82 { "TestSomeText\n", 2, 2},
83 { "TestSomeText\r\r\r", 3, 1, 1}, /* NT4 and below */
84 { "TestSomeText\r\r\rSomeMoreText", 4, 1, 1} /* NT4 and below */
86 HWND hwndRichEdit
= new_richedit(NULL
);
90 /* This test attempts to show that WM_SETTEXT on a riched32 control does not
91 * attempt to modify the text that is pasted into the control, and should
92 * return it as is. In particular, \r\r\n is NOT converted, unlike riched20.
94 * For riched32, the rules for breaking lines seem to be the following:
95 * - \r\n is one line break. This is the normal case.
96 * - \r{0,2}\n is one line break. In particular, \n by itself is a line break.
97 * - \r{0,N-1}\r\r\n is N line breaks.
98 * - \n{1,N} are that many line breaks.
99 * - \r with text or other characters (except \n) past it, is a line break. That
100 * is, a run of \r{N} without a terminating \n is considered N line breaks
101 * - \r at the end of the text is NOT a line break. This differs from riched20,
102 * where \r at the end of the text is a proper line break.
103 * However, on RTL language versions, \r is simply skipped and never used
104 * for line breaking (only \n adds a line break)
107 for (i
= 0; i
< ARRAY_SIZE(testitems
); i
++) {
109 char buf
[1024] = {0};
112 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testitems
[i
].itemtext
);
113 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
114 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
115 ok (result
== lstrlenA(buf
),
116 "[%d] WM_GETTEXT returned %ld instead of expected %u\n",
117 i
, result
, lstrlenA(buf
));
118 result
= strcmp(testitems
[i
].itemtext
, buf
);
120 "[%d] WM_SETTEXT round trip: strcmp = %ld\n", i
, result
);
121 result
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
122 ok (result
== (rtl
? testitems
[i
].lines_rtl
: testitems
[i
].lines
) ||
123 broken(testitems
[i
].lines_broken
&& result
== testitems
[i
].lines_broken
),
124 "[%d] EM_GETLINECOUNT returned %ld, expected %d\n", i
, result
, testitems
[i
].lines
);
127 DestroyWindow(hwndRichEdit
);
130 static void test_WM_GETTEXTLENGTH(void)
132 HWND hwndRichEdit
= new_richedit(NULL
);
133 static const char text1
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
134 static const char text2
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
135 static const char text3
[] = "abcdef\x8e\xf0";
138 /* Test for WM_GETTEXTLENGTH */
139 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
140 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
141 ok(result
== lstrlenA(text1
),
142 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
143 result
, lstrlenA(text1
));
145 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
146 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
147 ok(result
== lstrlenA(text2
),
148 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
149 result
, lstrlenA(text2
));
151 /* Test with multibyte character */
152 if (!is_lang_japanese
)
153 skip("Skip multibyte character tests on non-Japanese platform\n");
156 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text3
);
157 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
158 todo_wine
ok(result
== 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result
);
161 DestroyWindow(hwndRichEdit
);
164 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
169 const char** str
= (const char**)dwCookie
;
170 int size
= strlen(*str
);
176 memcpy(pbBuff
, *str
, *pcb
);
183 static void test_EM_STREAMIN(void)
185 HWND hwndRichEdit
= new_richedit(NULL
);
188 char buffer
[1024] = {0};
190 const char * streamText0
= "{\\rtf1 TestSomeText}";
191 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
192 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
194 const char * streamText1
=
195 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
196 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
199 /* This should be accepted in richedit 1.0 emulation. See bug #8326 */
200 const char * streamText2
=
201 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
202 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
203 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
204 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
205 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
206 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
207 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
209 const char * streamText3
= "RichEdit1";
211 /* Minimal test without \par at the end */
212 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
214 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
215 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
216 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
218 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
220 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
221 result
= strcmp (buffer
,"TestSomeText");
223 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
224 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
226 /* Native richedit 2.0 ignores last \par */
227 es
.dwCookie
= (DWORD_PTR
)&streamText0a
;
229 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
230 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
231 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
233 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
235 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
236 result
= strcmp (buffer
,"TestSomeText");
238 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
239 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
241 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
242 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
244 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
245 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
246 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
248 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
250 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
251 result
= strcmp (buffer
,"TestSomeText\r\n");
253 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
254 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
256 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
258 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
259 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
260 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
262 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
264 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
265 result
= strcmp (buffer
,"TestSomeText");
267 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
268 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
271 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
273 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
274 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
276 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
279 "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result
);
281 result
= strcmp (buffer
,"RichEdit1");
284 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
286 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
288 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
290 SendMessageA(hwndRichEdit
, EM_STREAMIN
,
291 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
293 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
295 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
297 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
298 ok(es
.dwError
== -16, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, -16);
300 DestroyWindow(hwndRichEdit
);
303 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
308 char** str
= (char**)dwCookie
;
311 memcpy(*str
, pbBuff
, *pcb
);
317 static void test_EM_STREAMOUT(void)
319 HWND hwndRichEdit
= new_richedit(NULL
);
322 char buf
[1024] = {0};
325 const char * TestItem1
= "TestSomeText";
326 const char * TestItem2
= "TestSomeText\r";
327 const char * TestItem3
= "TestSomeText\r\n";
329 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem1
);
331 es
.dwCookie
= (DWORD_PTR
)&p
;
333 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
334 memset(buf
, 0, sizeof(buf
));
335 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
336 (WPARAM
)(SF_TEXT
), (LPARAM
)&es
);
338 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
339 ok(strcmp(buf
, TestItem1
) == 0,
340 "streamed text different, got %s\n", buf
);
342 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
344 es
.dwCookie
= (DWORD_PTR
)&p
;
346 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
347 memset(buf
, 0, sizeof(buf
));
348 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
349 (WPARAM
)(SF_TEXT
), (LPARAM
)&es
);
352 ok(r
== 13, "streamed text length is %d, expecting 13\n", r
);
353 ok(strcmp(buf
, TestItem2
) == 0,
354 "streamed text different, got %s\n", buf
);
356 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem3
);
358 es
.dwCookie
= (DWORD_PTR
)&p
;
360 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
361 memset(buf
, 0, sizeof(buf
));
362 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
363 (WPARAM
)(SF_TEXT
), (LPARAM
)&es
);
365 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
366 ok(strcmp(buf
, TestItem3
) == 0,
367 "streamed text different, got %s\n", buf
);
369 DestroyWindow(hwndRichEdit
);
372 static const struct getline_s
{
376 const char *broken_text
;
378 {0, 10, "foo bar\r\n", "foo bar\r\n"},
379 {1, 10, "\r", "\r\r\r\n"},
380 {2, 10, "\r\r\n", "bar\n"},
381 {3, 10, "bar\n", "\r\n"},
384 /* Buffer smaller than line length */
390 static void test_EM_GETLINE(void)
393 HWND hwndRichEdit
= new_richedit(NULL
);
394 static const int nBuf
= 1024;
395 char dest
[1024], origdest
[1024];
397 const char text
[] = "foo bar\r\n"
401 BOOL broken_os
= FALSE
;
404 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
405 linecount
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
409 win_skip("Win9x, WinME and NT4 handle '\\r only' differently\n");
412 memset(origdest
, 0xBB, nBuf
);
413 for (i
= 0; i
< ARRAY_SIZE(gl
); i
++)
415 int nCopied
, expected_nCopied
, expected_bytes_written
;
418 if (gl
[i
].line
>= linecount
)
419 continue; /* Win9x, WinME and NT4 */
421 if (broken_os
&& gl
[i
].broken_text
)
422 /* Win9x, WinME and NT4 */
423 strcpy(gl_text
, gl
[i
].broken_text
);
425 strcpy(gl_text
, gl
[i
].text
);
427 expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl_text
));
428 /* Cater for the fact that Win9x, WinME and NT4 don't append the '\0' */
429 expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl_text
) + (broken_os
? 0 : 1));
431 memset(dest
, 0xBB, nBuf
);
432 *(WORD
*) dest
= gl
[i
].buffer_len
;
434 /* EM_GETLINE appends a "\r\0" to the end of the line
435 * nCopied counts up to and including the '\r' */
436 nCopied
= SendMessageA(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
)dest
);
437 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
439 /* two special cases since a parameter is passed via dest */
440 if (gl
[i
].buffer_len
== 0)
441 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
443 else if (gl
[i
].buffer_len
== 1)
444 ok(dest
[0] == gl_text
[0] && !dest
[1] &&
445 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
448 ok(!strncmp(dest
, gl_text
, expected_bytes_written
),
449 "%d: expected_bytes_written=%d\n", i
, expected_bytes_written
);
450 if (! rtl
|| expected_bytes_written
== gl
[i
].buffer_len
)
451 ok(!strncmp(dest
+ expected_bytes_written
, origdest
452 + expected_bytes_written
, nBuf
- expected_bytes_written
),
453 "%d: expected_bytes_written=%d\n", i
, expected_bytes_written
);
455 ok(dest
[expected_bytes_written
] == 0 &&
456 !strncmp(dest
+ expected_bytes_written
+ 1, origdest
457 + expected_bytes_written
+ 1, nBuf
- (expected_bytes_written
+ 1)),
458 "%d: expected_bytes_written=%d\n", i
, expected_bytes_written
);
462 DestroyWindow(hwndRichEdit
);
465 static void test_EM_LINELENGTH(void)
467 HWND hwndRichEdit
= new_richedit(NULL
);
477 int offset_test
[16][2] = {
478 {0, 9}, /* Line 1: |richedit1\r */
479 {5, 9}, /* Line 1: riche|dit1\r */
480 {10, 9}, /* Line 2: |richedit1\n */
481 {15, 9}, /* Line 2: riche|dit1\n */
482 {20, 9}, /* Line 3: |richedit1\r\n */
483 {25, 9}, /* Line 3: riche|dit1\r\n */
484 {30, 9}, /* Line 3: richedit1\r|\n */
485 {31, 5}, /* Line 4: |short\r */
486 {42, 9}, /* Line 5: riche|dit1\r */
487 {46, 9}, /* Line 5: richedit1|\r */
488 {47, 0}, /* Line 6: |\r */
489 {48, 0}, /* Line 7: |\r */
490 {49, 0}, /* Line 8: |\r\r\n */
491 {50, 0}, /* Line 8: \r|\r\n */
492 {51, 0}, /* Line 8: \r\r|\n */
493 {52, 0}, /* Line 9: \r\r\n| */
498 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
500 result
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
502 win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n");
505 ok(result
== 9, "Incorrect line count of %ld\n", result
);
507 for (i
= 0; i
< ARRAY_SIZE(offset_test
); i
++) {
508 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
509 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
510 offset_test
[i
][0], result
, offset_test
[i
][1]);
513 /* Test with multibyte character */
514 if (!is_lang_japanese
)
515 skip("Skip multibyte character tests on non-Japanese platform\n");
522 static int offset_test1
[3][3] = {
523 {0, 4}, /* Line 1: |wine\n */
524 {5, 10, 1}, /* Line 2: |richedit\x8e\xf0\n */
525 {16, 4}, /* Line 3: |wine */
527 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
528 for (i
= 0; i
< ARRAY_SIZE(offset_test1
); i
++) {
529 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test1
[i
][0], 0);
530 todo_wine_if (offset_test1
[i
][2])
531 ok(result
== offset_test1
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
532 offset_test1
[i
][0], result
, offset_test1
[i
][1]);
536 DestroyWindow(hwndRichEdit
);
539 static void test_EM_GETTEXTRANGE(void)
541 HWND hwndRichEdit
= new_richedit(NULL
);
542 const char * text1
= "foo bar\r\nfoo bar";
543 const char * text3
= "foo bar\rfoo bar";
544 const char * expect1
= "bar\r\nfoo";
545 const char * expect2
= "\nfoo";
546 const char * expect3
= "bar\rfoo";
547 char buffer
[1024] = {0};
549 TEXTRANGEA textRange
;
551 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
553 textRange
.lpstrText
= buffer
;
554 textRange
.chrg
.cpMin
= 4;
555 textRange
.chrg
.cpMax
= 12;
556 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
557 ok(result
== 8, "EM_GETTEXTRANGE returned %ld\n", result
);
558 ok(!strcmp(expect1
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
560 textRange
.lpstrText
= buffer
;
561 textRange
.chrg
.cpMin
= 8;
562 textRange
.chrg
.cpMax
= 12;
563 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
564 ok(result
== 4, "EM_GETTEXTRANGE returned %ld\n", result
);
565 ok(!strcmp(expect2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
567 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text3
);
569 textRange
.lpstrText
= buffer
;
570 textRange
.chrg
.cpMin
= 4;
571 textRange
.chrg
.cpMax
= 11;
572 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
573 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
575 ok(!strcmp(expect3
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
577 /* Test with multibyte character */
578 if (!is_lang_japanese
)
579 skip("Skip multibyte character tests on non-Japanese platform\n");
582 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
583 textRange
.chrg
.cpMin
= 4;
584 textRange
.chrg
.cpMax
= 8;
585 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
586 ok(result
== 4, "EM_GETTEXTRANGE returned %ld\n", result
);
587 ok(!strcmp("ef\x8e\xf0", buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
590 DestroyWindow(hwndRichEdit
);
593 static void test_EM_GETSELTEXT(void)
595 HWND hwndRichEdit
= new_richedit(NULL
);
596 const char * text1
= "foo bar\r\nfoo bar";
597 const char * text2
= "foo bar\rfoo bar";
598 const char * expect1
= "bar\r\nfoo";
599 const char * expect2
= "bar\rfoo";
600 char buffer
[1024] = {0};
603 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
605 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 12);
606 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
607 ok(result
== 8, "EM_GETSELTEXT returned %ld\n", result
);
608 ok(!strcmp(expect1
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
610 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
612 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
613 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
614 ok(result
== 7, "EM_GETSELTEXT returned %ld\n", result
);
615 ok(!strcmp(expect2
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
617 /* Test with multibyte character */
618 if (!is_lang_japanese
)
619 skip("Skip multibyte character tests on non-Japanese platform\n");
622 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
623 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
624 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
625 ok(result
== 4, "EM_GETSELTEXT returned %ld\n", result
);
626 ok(!strcmp("ef\x8e\xf0", buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
629 DestroyWindow(hwndRichEdit
);
632 static const char haystack
[] = "WINEWine wineWine wine WineWine";
635 static const char haystack2
[] = "first\r\r\nsecond";
646 static struct find_s find_tests
[] = {
647 /* Find in empty text */
648 {0, -1, "foo", FR_DOWN
, -1},
649 {0, -1, "foo", 0, -1},
650 {0, -1, "", FR_DOWN
, -1},
651 {20, 5, "foo", FR_DOWN
, -1},
652 {5, 20, "foo", FR_DOWN
, -1}
655 static struct find_s find_tests2
[] = {
657 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1},
658 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1},
660 /* Subsequent finds */
661 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4},
662 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13},
663 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
664 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
667 {19, 20, "Wine", FR_MATCHCASE
, -1},
668 {10, 20, "Wine", FR_MATCHCASE
, 13},
669 {20, 10, "Wine", FR_MATCHCASE
, -1},
671 /* Case-insensitive */
672 {1, 31, "wInE", FR_DOWN
, 4},
673 {1, 31, "Wine", FR_DOWN
, 4},
675 /* High-to-low ranges */
676 {20, 5, "Wine", FR_DOWN
, -1},
677 {2, 1, "Wine", FR_DOWN
, -1},
678 {30, 29, "Wine", FR_DOWN
, -1},
679 {20, 5, "Wine", 0, /*13*/ -1},
682 {5, 10, "", FR_DOWN
, -1},
683 {10, 5, "", FR_DOWN
, -1},
684 {0, -1, "", FR_DOWN
, -1},
687 /* Whole-word search */
688 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
689 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1},
690 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
691 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0},
692 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23},
693 {11, -1, "winewine", FR_WHOLEWORD
, 23},
694 {31, -1, "winewine", FR_WHOLEWORD
, -1},
697 {5, 200, "XXX", FR_DOWN
, -1},
698 {-20, 20, "Wine", FR_DOWN
, -1},
699 {-20, 20, "Wine", FR_DOWN
, -1},
700 {-15, -20, "Wine", FR_DOWN
, -1},
701 {1<<12, 1<<13, "Wine", FR_DOWN
, -1},
703 /* Check the case noted in bug 4479 where matches at end aren't recognized */
704 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
705 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
706 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
707 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
708 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
710 /* The backwards case of bug 4479; bounds look right
711 * Fails because backward find is wrong */
712 {19, 20, "WINE", FR_MATCHCASE
, -1},
713 {0, 20, "WINE", FR_MATCHCASE
, 0},
715 {0, -1, "wineWine wine", FR_DOWN
, 0},
716 {0, -1, "wineWine wine", 0, 0},
717 {0, -1, "INEW", 0, 1},
718 {0, 31, "INEW", 0, 1},
719 {4, -1, "INEW", 0, 10},
722 static struct find_s find_tests3
[] = {
723 /* Searching for end of line characters */
724 {0, -1, "t\r\r\ns", FR_DOWN
| FR_MATCHCASE
, 4},
725 {6, -1, "\r\n", FR_DOWN
| FR_MATCHCASE
, 6},
726 {7, -1, "\n", FR_DOWN
| FR_MATCHCASE
, 7},
729 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
) {
732 memset(&ft
, 0, sizeof(ft
));
733 ft
.chrg
.cpMin
= f
->start
;
734 ft
.chrg
.cpMax
= f
->end
;
735 ft
.lpstrText
= f
->needle
;
736 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&ft
);
737 ok(findloc
== f
->expected_loc
,
738 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
739 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
742 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
746 int expected_end_loc
;
748 memset(&ft
, 0, sizeof(ft
));
749 ft
.chrg
.cpMin
= f
->start
;
750 ft
.chrg
.cpMax
= f
->end
;
751 ft
.lpstrText
= f
->needle
;
752 ft
.chrgText
.cpMax
= 0xdeadbeef;
753 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&ft
);
754 ok(findloc
== f
->expected_loc
,
755 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
756 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
757 ok(ft
.chrgText
.cpMin
== f
->expected_loc
,
758 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n",
759 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMin
, f
->expected_loc
);
760 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
761 : f
->expected_loc
+ strlen(f
->needle
));
762 ok(ft
.chrgText
.cpMax
== expected_end_loc
||
763 broken(ft
.chrgText
.cpMin
== -1 && ft
.chrgText
.cpMax
== 0xdeadbeef), /* Win9x, WinME and NT4 */
764 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
765 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMax
, expected_end_loc
);
768 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
773 for (i
= 0; i
< num_tests
; i
++) {
774 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
775 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
779 static void test_EM_FINDTEXT(void)
781 HWND hwndRichEdit
= new_richedit(NULL
);
783 /* Empty rich edit control */
784 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
, ARRAY_SIZE(find_tests
));
786 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack
);
789 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
, ARRAY_SIZE(find_tests2
));
791 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack2
);
793 /* Haystack text 2 (with EOL characters) */
794 run_tests_EM_FINDTEXT(hwndRichEdit
, "3", find_tests3
, ARRAY_SIZE(find_tests3
));
796 DestroyWindow(hwndRichEdit
);
799 static void test_EM_POSFROMCHAR(void)
801 HWND hwndRichEdit
= new_richedit(NULL
);
805 unsigned int height
= 0;
807 int xpos_rtl_adjusted
= 0;
808 static const char text
[] = "aa\n"
809 "this is a long line of text that should be longer than the "
818 /* Fill the control to lines to ensure that most of them are offscreen */
819 for (i
= 0; i
< 50; i
++)
821 /* Do not modify the string; it is exactly 16 characters long. */
822 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
823 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCD\r\n");
827 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
828 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
829 Richedit 3.0 accepts either of the above API conventions.
832 /* Testing Richedit 1.0 API format */
834 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
835 Since all lines are identical and drawn with the same font,
836 they should have the same height... right?
838 for (i
= 0; i
< 50; i
++)
840 /* All the lines are 16 characters long */
841 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, i
* 16);
842 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
845 ok(pl
.y
== 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl
.y
);
847 broken(pl
.x
== 0), /* Win9x, WinME and NT4 */
848 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl
.x
);
850 xpos_rtl_adjusted
= xpos
+ (is_rtl() ? 7 : 0);
854 ok(pl
.y
> 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", pl
.y
);
855 ok(pl
.x
== xpos
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos
);
860 ok(pl
.y
== i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl
.y
, i
* height
);
861 ok(pl
.x
== xpos
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos
);
865 /* Testing position at end of text */
866 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 50 * 16);
867 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
868 ok(pl
.y
== 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl
.y
, 50 * height
);
869 ok(pl
.x
== xpos
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos
);
871 /* Testing position way past end of text */
872 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 55 * 16);
873 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
874 ok(pl
.y
== 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl
.y
, 50 * height
);
876 ok(pl
.x
== xpos_rtl_adjusted
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos_rtl_adjusted
);
879 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
880 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
881 for (i
= 0; i
< 50; i
++)
883 /* All the lines are 16 characters long */
884 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, i
* 16);
885 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
886 ok(pl
.y
== (i
- 1) * height
,
887 "EM_POSFROMCHAR reports y=%d, expected %d\n",
888 pl
.y
, (i
- 1) * height
);
889 ok(pl
.x
== xpos
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos
);
892 /* Testing position at end of text */
893 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 50 * 16);
894 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
895 ok(pl
.y
== (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl
.y
, (50 - 1) * height
);
896 ok(pl
.x
== xpos
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos
);
898 /* Testing position way past end of text */
899 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 55 * 16);
900 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
901 ok(pl
.y
== (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl
.y
, (50 - 1) * height
);
902 ok(pl
.x
== xpos_rtl_adjusted
, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl
.x
, xpos_rtl_adjusted
);
904 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
905 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
906 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
908 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 0);
909 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
910 ok(pl
.y
== 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl
.y
);
912 broken(pl
.x
== 0), /* Win9x, WinME and NT4 */
913 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl
.x
);
916 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
917 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pl
, 0);
918 ok(result
== 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result
);
919 ok(pl
.y
== 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl
.y
);
921 /* Fails on builtin because horizontal scrollbar is not being shown */
923 broken(pl
.x
== xpos
), /* Win9x, WinME and NT4 */
924 "EM_POSFROMCHAR reports x=%d, expected value less than %d\n", pl
.x
, xpos
);
926 DestroyWindow(hwndRichEdit
);
929 static void test_word_wrap(void)
932 POINTL point
= {0, 60}; /* This point must be below the first line */
933 const char *text
= "Must be long enough to test line wrapping";
934 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
935 int res
, pos
, lines
, prevlines
, reflines
[3];
937 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
938 * when specified on window creation and set later. */
939 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
, dwCommonStyle
,
940 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
941 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
942 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
943 ok(res
, "WM_SETTEXT failed.\n");
944 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
945 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
946 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
947 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
949 SetWindowLongA(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
950 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
951 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
954 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
955 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
956 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
958 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
959 ok(res
, "WM_SETTEXT failed.\n");
960 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
961 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
962 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
963 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
965 SetWindowLongA(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
966 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
967 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
970 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
971 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
972 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
973 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
974 ok(res
, "WM_SETTEXT failed.\n");
975 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
977 broken(pos
== lstrlenA(text
)), /* Win9x, WinME and NT4 */
978 "pos=%d indicating word wrap when none is expected.\n", pos
);
979 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
980 ok(lines
== 1, "Line was not expected to wrap (lines=%d).\n", lines
);
982 SetWindowLongA(hwnd
, GWL_STYLE
, dwCommonStyle
);
983 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
985 broken(pos
== lstrlenA(text
)), /* Win9x, WinME and NT4 */
986 "pos=%d indicating word wrap when none is expected.\n", pos
);
987 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
988 ok(lines
== 1, "Line was not expected to wrap (lines=%d).\n", lines
);
991 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
,
992 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
993 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
994 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
995 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
996 ok(res
, "WM_SETTEXT failed.\n");
997 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
999 broken(pos
== lstrlenA(text
)), /* Win9x, WinME and NT4 */
1000 "pos=%d indicating word wrap when none is expected.\n", pos
);
1001 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1002 ok(lines
== 1, "Line was not expected to wrap (lines=%d).\n", lines
);
1004 SetWindowLongA(hwnd
, GWL_STYLE
, dwCommonStyle
);
1005 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
1007 broken(pos
== lstrlenA(text
)), /* Win9x, WinME and NT4 */
1008 "pos=%d indicating word wrap when none is expected.\n", pos
);
1009 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1010 ok(lines
== 1, "Line was not expected to wrap (lines=%d).\n", lines
);
1012 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
1013 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
1014 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
1015 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
1017 broken(pos
== lstrlenA(text
)), /* Win9x, WinME and NT4 */
1018 "pos=%d indicating word wrap when none is expected.\n", pos
);
1019 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1020 ok(lines
== 1, "Line was not expected to wrap (lines=%d).\n", lines
);
1022 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
1023 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
1024 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
1025 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
1026 DestroyWindow(hwnd
);
1028 /* First lets see if the text would wrap normally (needed for reference) */
1029 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
, dwCommonStyle
,
1030 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1031 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
1032 ok(IsWindowVisible(hwnd
), "Window should be visible.\n");
1033 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
1034 ok(res
, "EM_REPLACESEL failed.\n");
1035 /* Should have wrapped */
1036 reflines
[0] = SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1037 ok(reflines
[0] > 1, "Line was expected to wrap (%d lines).\n", reflines
[0]);
1038 /* Resize the window to fit the line */
1039 MoveWindow(hwnd
, 0, 0, 600, 80, TRUE
);
1040 /* Text should not be wrapped */
1041 reflines
[1] = SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1042 ok(reflines
[1] == 1, "Line wasn't expected to wrap (%d lines).\n", reflines
[1]);
1043 /* Resize the window again to make sure the line wraps again */
1044 MoveWindow(hwnd
, 0, 0, 10, 80, TRUE
);
1045 reflines
[2] = SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1046 ok(reflines
[2] > 1, "Line was expected to wrap (%d lines).\n", reflines
[2]);
1047 DestroyWindow(hwnd
);
1049 /* Same test with redraw disabled */
1050 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
, dwCommonStyle
,
1051 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1052 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
1053 ok(IsWindowVisible(hwnd
), "Window should be visible.\n");
1054 /* Redraw is disabled by making the window invisible. */
1055 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
1056 ok(!IsWindowVisible(hwnd
), "Window shouldn't be visible.\n");
1057 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
1058 ok(res
, "EM_REPLACESEL failed.\n");
1059 /* Should have wrapped */
1060 prevlines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1061 ok(prevlines
== reflines
[0],
1062 "Line was expected to wrap (%d lines).\n", prevlines
);
1063 /* Resize the window to fit the line, no change to the number of lines */
1064 MoveWindow(hwnd
, 0, 0, 600, 80, TRUE
);
1065 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1067 ok(lines
== prevlines
||
1068 broken(lines
== reflines
[1]), /* Win98, WinME and NT4 */
1069 "Expected no change in the number of lines\n");
1070 /* Resize the window again to make sure the line wraps again */
1071 MoveWindow(hwnd
, 0, 0, 10, 80, TRUE
);
1072 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
1074 ok(lines
== prevlines
||
1075 broken(lines
== reflines
[2]), /* Win98, WinME and NT4 */
1076 "Expected no change in the number of lines\n");
1077 DestroyWindow(hwnd
);
1080 static void test_EM_GETOPTIONS(void)
1085 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
,
1087 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1088 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
1089 ok(options
== 0, "Incorrect options %x\n", options
);
1090 DestroyWindow(hwnd
);
1092 hwnd
= CreateWindowA(RICHEDIT_CLASS10A
, NULL
,
1093 WS_POPUP
|WS_VSCROLL
|WS_HSCROLL
,
1094 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1095 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
1096 ok(options
== ECO_AUTOVSCROLL
||
1097 broken(options
== 0), /* Win9x, WinME and NT4 */
1098 "Incorrect initial options %x\n", options
);
1099 DestroyWindow(hwnd
);
1102 static void test_autoscroll(void)
1107 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
1108 * auto vertical/horizontal scrolling options. */
1109 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS10A
, NULL
,
1110 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
1111 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1112 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS10A
, (int) GetLastError());
1113 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
1114 ok(ret
& ECO_AUTOVSCROLL
||
1115 broken(!(ret
& ECO_AUTOVSCROLL
)), /* Win9x, WinME and NT4 */
1116 "ECO_AUTOVSCROLL isn't set.\n");
1117 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
1118 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
1120 ok(ret
& ES_AUTOVSCROLL
||
1121 broken(!(ret
& ES_AUTOVSCROLL
)), /* Win9x, WinMe and NT4 */
1122 "ES_AUTOVSCROLL isn't set.\n");
1123 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
1124 DestroyWindow(hwnd
);
1126 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS10A
, NULL
,
1127 WS_POPUP
|ES_MULTILINE
,
1128 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
1129 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS10A
, (int) GetLastError());
1130 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
1131 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
1132 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
1133 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
1134 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
1135 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
1136 DestroyWindow(hwnd
);
1139 static void simulate_typing_characters(HWND hwnd
, const char* szChars
)
1143 while (*szChars
!= '\0') {
1144 SendMessageA(hwnd
, WM_KEYDOWN
, *szChars
, 1);
1145 ret
= SendMessageA(hwnd
, WM_CHAR
, *szChars
, 1);
1146 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *szChars
, ret
);
1147 SendMessageA(hwnd
, WM_KEYUP
, *szChars
, 1);
1152 static void format_test_result(char *target
, const char *src
)
1155 for (i
= 0; i
< strlen(src
); i
++)
1156 sprintf(target
+ 2*i
, "%02x", src
[i
] & 0xFF);
1161 * This test attempts to show the effect of enter on a richedit
1162 * control v1.0 inserts CRLF whereas for higher versions it only
1163 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
1164 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
1165 * does for higher. The same test is cloned in riched32 and riched20.
1166 * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions
1168 static void test_enter(void)
1170 static const struct {
1171 const char *initialtext
;
1173 const char *expectedtext
;
1174 } testenteritems
[] = {
1175 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n"},
1176 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n"},
1177 { "aa\rabbb\r\n", 7, "aa\rabbb\r\n\r\n"},
1178 { "aa\rabbb\r\n", 3, "aa\r\r\nabbb\r\n"},
1179 { "aa\rabbb\r\n", 2, "aa\r\n\rabbb\r\n"}
1182 char expectedbuf
[1024];
1183 char resultbuf
[1024];
1184 HWND hwndRichEdit
= new_richedit(NULL
);
1186 char buf
[1024] = {0};
1187 GETTEXTEX getText
= {sizeof(buf
)};
1189 const char *expected
;
1191 for (i
= 0; i
< ARRAY_SIZE(testenteritems
); i
++)
1193 /* Set the text to the initial text */
1194 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
1195 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
1198 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
1199 simulate_typing_characters(hwndRichEdit
, "\r");
1201 /* 1. Retrieve with WM_GETTEXT */
1203 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
1204 expected
= testenteritems
[i
].expectedtext
;
1206 format_test_result(resultbuf
, buf
);
1207 format_test_result(expectedbuf
, expected
);
1209 result
= strcmp(expected
, buf
);
1211 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
1212 i
, resultbuf
, expectedbuf
);
1214 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
1215 getText
.flags
= GT_DEFAULT
;
1216 getText
.codepage
= CP_ACP
;
1218 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
1219 expected
= testenteritems
[i
].expectedtext
;
1221 format_test_result(resultbuf
, buf
);
1222 format_test_result(expectedbuf
, expected
);
1224 result
= strcmp(expected
, buf
);
1225 ok (result
== 0 || broken(buf
[0]==0x00 /* WinNT4 */),
1226 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
1227 i
, resultbuf
, expectedbuf
);
1229 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
1230 getText
.flags
= GT_USECRLF
;
1231 getText
.codepage
= CP_ACP
;
1233 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
1234 expected
= testenteritems
[i
].expectedtext
;
1236 format_test_result(resultbuf
, buf
);
1237 format_test_result(expectedbuf
, expected
);
1239 result
= strcmp(expected
, buf
);
1240 ok (result
== 0 || broken(buf
[0]==0x00 /* WinNT4 */),
1241 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
1242 i
, resultbuf
, expectedbuf
);
1245 /* Show that WM_CHAR is handled differently from WM_KEYDOWN */
1246 getText
.flags
= GT_DEFAULT
;
1247 getText
.codepage
= CP_ACP
;
1249 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1250 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
1251 SendMessageW(hwndRichEdit
, WM_CHAR
, 'T', 0);
1252 SendMessageW(hwndRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0);
1254 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
1255 ok(result
== 1, "Got %d\n", (int)result
);
1256 format_test_result(resultbuf
, buf
);
1257 format_test_result(expectedbuf
, "T");
1258 result
= strcmp(resultbuf
, expectedbuf
);
1259 ok (result
== 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i
, resultbuf
, expectedbuf
);
1261 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1262 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
1263 SendMessageW(hwndRichEdit
, WM_CHAR
, 'T', 0);
1264 SendMessageW(hwndRichEdit
, WM_CHAR
, '\r', 0);
1266 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
1267 ok(result
== 3, "Got %ld\n", result
);
1268 format_test_result(resultbuf
, buf
);
1269 format_test_result(expectedbuf
, "T\r\n");
1270 result
= strcmp(resultbuf
, expectedbuf
);
1271 ok (result
== 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i
, resultbuf
, expectedbuf
);
1273 DestroyWindow(hwndRichEdit
);
1279 LRESULT expected_retval
;
1280 int expected_getsel_start
;
1281 int expected_getsel_end
;
1286 static const struct exsetsel_s exsetsel_tests
[] = {
1288 {5, 10, 10, 5, 10, 0, 0 },
1289 {15, 17, 17, 15, 17, 0, 0 },
1290 /* test cpMax > strlen() */
1291 {0, 100, 19, 0, 19, 1, 0 },
1292 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
1293 {-1, 1, 17, 17, 17, 1, 0 },
1294 /* test cpMin == cpMax */
1295 {5, 5, 5, 5, 5, 0, 0 },
1296 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1297 {-1, 0, 5, 5, 5, 0, 0 },
1298 {-1, 17, 5, 5, 5, 0, 0 },
1299 {-1, 18, 5, 5, 5, 0, 0 },
1300 /* test cpMin < 0 && cpMax < 0 */
1301 {-1, -1, 17, 17, 17, 0, 0 },
1302 {-4, -5, 17, 17, 17, 0, 0 },
1303 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
1304 {0, -1, 19, 0, 19, 1, 0 },
1305 {17, -5, 19, 17, 19, 1, 0 },
1306 {18, -3, 19, 17, 19, 1, 1 },
1307 /* test if cpMin > cpMax */
1308 {15, 19, 19, 15, 19, 1, 0 },
1309 {19, 15, 19, 15, 19, 1, 0 },
1310 /* cpMin == strlen() && cpMax > cpMin */
1311 {17, 18, 17, 17, 17, 1, 1 },
1312 {17, 50, 19, 17, 19, 1, 0 },
1315 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
1320 cr
.cpMin
= setsel
->min
;
1321 cr
.cpMax
= setsel
->max
;
1322 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1324 todo_wine_if (setsel
->result_todo
)
1325 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1327 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
1329 todo_wine_if (setsel
->sel_todo
)
1330 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
,
1331 "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
1332 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
1335 static void test_EM_EXSETSEL(void)
1337 HWND hwndRichEdit
= new_richedit(NULL
);
1339 const int num_tests
= ARRAY_SIZE(exsetsel_tests
);
1341 /* sending some text to the window */
1342 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
1343 /* 01234567890123456 */
1345 for (i
= 0; i
< num_tests
; i
++) {
1346 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
1349 if (!is_lang_japanese
)
1350 skip("Skip multibyte character tests on non-Japanese platform\n");
1355 #define MAX_BUF_LEN 1024
1356 char bufA
[MAX_BUF_LEN
] = {0};
1358 /* Test with multibyte character */
1359 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1360 /* 012345 6 7 8901 */
1361 cr
.cpMin
= 4; cr
.cpMax
= 8;
1362 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1363 todo_wine
ok(result
== 7, "EM_EXSETSEL return %ld expected 7\n", result
);
1364 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(bufA
), (LPARAM
)bufA
);
1365 ok(!strcmp(bufA
, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1366 SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
1367 ok(cr
.cpMin
== 4, "Selection start incorrectly: %d expected 4\n", cr
.cpMin
);
1368 ok(cr
.cpMax
== 8, "Selection end incorrectly: %d expected 8\n", cr
.cpMax
);
1371 DestroyWindow(hwndRichEdit
);
1374 static void check_EM_SETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
1378 result
= SendMessageA(hwnd
, EM_SETSEL
, setsel
->min
, setsel
->max
);
1380 todo_wine_if (setsel
->result_todo
)
1381 ok(result
== setsel
->expected_retval
, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
1383 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
1385 todo_wine_if (setsel
->sel_todo
)
1386 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
,
1387 "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
1388 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
1391 static void test_EM_SETSEL(void)
1393 char buffA
[32] = {0};
1394 HWND hwndRichEdit
= new_richedit(NULL
);
1396 const int num_tests
= ARRAY_SIZE(exsetsel_tests
);
1398 /* sending some text to the window */
1399 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
1400 /* 01234567890123456 */
1402 for (i
= 0; i
< num_tests
; i
++) {
1403 check_EM_SETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
1406 SendMessageA(hwndRichEdit
, EM_SETSEL
, 17, 18);
1408 SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffA
);
1409 ok(buffA
[0] == 0, "selection text %s\n", buffA
);
1411 if (!is_lang_japanese
)
1412 skip("Skip multibyte character tests on non-Japanese platform\n");
1415 int sel_start
, sel_end
;
1418 /* Test with multibyte character */
1419 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1420 /* 012345 6 7 8901 */
1421 result
= SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
1422 todo_wine
ok(result
== 7, "EM_SETSEL return %ld expected 7\n", result
);
1423 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(buffA
), (LPARAM
)buffA
);
1424 ok(!strcmp(buffA
, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1425 result
= SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
1426 ok(sel_start
== 4, "Selection start incorrectly: %d expected 4\n", sel_start
);
1427 ok(sel_end
== 8, "Selection end incorrectly: %d expected 8\n", sel_end
);
1430 DestroyWindow(hwndRichEdit
);
1433 START_TEST( editor
)
1439 /* Must explicitly LoadLibrary(). The test has no references to functions in
1440 * RICHED32.DLL, so the linker doesn't actually link to it. */
1441 hmoduleRichEdit
= LoadLibraryA("riched32.dll");
1442 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
1443 is_lang_japanese
= (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_JAPANESE
);
1446 test_EM_GETTEXTRANGE();
1447 test_EM_GETSELTEXT();
1448 test_WM_GETTEXTLENGTH();
1450 test_EM_STREAMOUT();
1452 test_EM_LINELENGTH();
1454 test_EM_POSFROMCHAR();
1456 test_EM_GETOPTIONS();
1462 /* Set the environment variable WINETEST_RICHED32 to keep windows
1463 * responsive and open for 30 seconds. This is useful for debugging.
1465 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1466 * 50ms before retrying the queue. */
1467 end
= time(NULL
) + 30;
1468 if (getenv( "WINETEST_RICHED32" )) {
1469 while (time(NULL
) < end
) {
1470 if (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
1471 TranslateMessage(&msg
);
1472 DispatchMessageA(&msg
);
1479 OleFlushClipboard();
1480 ret
= FreeLibrary(hmoduleRichEdit
);
1481 ok(ret
, "error: %u\n", GetLastError());