riched32/tests: Test WM_GETTEXTLENGTH with multibyte character.
[wine.git] / dlls / riched32 / tests / editor.c
blobc29934833da75ba8296f3106b68191c3ecbbcfa5
1 /*
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
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <windef.h>
27 #include <winbase.h>
28 #include <wingdi.h>
29 #include <winuser.h>
30 #include <winnls.h>
31 #include <ole2.h>
32 #include <commdlg.h>
33 #include <richedit.h>
34 #include <time.h>
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) {
41 HWND hwnd;
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());
46 return hwnd;
49 static HWND new_richedit(HWND parent) {
50 return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent);
53 static BOOL is_rtl(void) {
54 LOCALESIGNATURE sig;
56 return (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE,
57 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
58 (sig.lsUsb[3] & 0x08000000) != 0);
61 static void test_WM_SETTEXT(void)
63 static const struct {
64 const char *itemtext;
65 DWORD lines;
66 DWORD lines_rtl;
67 DWORD lines_broken;
68 } testitems[] = {
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);
87 int i;
88 BOOL rtl = is_rtl();
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 < sizeof(testitems)/sizeof(testitems[0]); i++) {
109 char buf[1024] = {0};
110 LRESULT result;
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);
119 ok (result == 0,
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";
136 int result;
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");
154 else
156 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
157 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
158 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,
165 LPBYTE pbBuff,
166 LONG cb,
167 LONG *pcb)
169 const char** str = (const char**)dwCookie;
170 int size = strlen(*str);
171 *pcb = cb;
172 if (*pcb > size) {
173 *pcb = size;
175 if (*pcb > 0) {
176 memcpy(pbBuff, *str, *pcb);
177 *str += *pcb;
179 return 0;
183 static void test_EM_STREAMIN(void)
185 HWND hwndRichEdit = new_richedit(NULL);
186 LRESULT result;
187 EDITSTREAM es;
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"
197 "}\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;
213 es.dwError = 0;
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);
219 ok (result == 12,
220 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
221 result = strcmp (buffer,"TestSomeText");
222 ok (result == 0,
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;
228 es.dwError = 0;
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);
234 ok (result == 12,
235 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
236 result = strcmp (buffer,"TestSomeText");
237 ok (result == 0,
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;
243 es.dwError = 0;
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);
249 ok (result == 14,
250 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
251 result = strcmp (buffer,"TestSomeText\r\n");
252 ok (result == 0,
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;
257 es.dwError = 0;
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);
263 ok (result == 12,
264 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
265 result = strcmp (buffer,"TestSomeText");
266 ok (result == 0,
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;
272 es.dwError = 0;
273 SendMessageA(hwndRichEdit, EM_STREAMIN,
274 (WPARAM)(SF_RTF), (LPARAM)&es);
276 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
277 todo_wine {
278 ok (result == 9,
279 "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result);
281 result = strcmp (buffer,"RichEdit1");
282 todo_wine {
283 ok (result == 0,
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;
289 es.dwError = 0;
290 SendMessageA(hwndRichEdit, EM_STREAMIN,
291 (WPARAM)(SF_RTF), (LPARAM)&es);
293 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
294 ok (result == 0,
295 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
296 ok (strlen(buffer) == 0,
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,
304 LPBYTE pbBuff,
305 LONG cb,
306 LONG *pcb)
308 char** str = (char**)dwCookie;
309 *pcb = cb;
310 if (*pcb > 0) {
311 memcpy(*str, pbBuff, *pcb);
312 *str += *pcb;
314 return 0;
317 static void test_EM_STREAMOUT(void)
319 HWND hwndRichEdit = new_richedit(NULL);
320 int r;
321 EDITSTREAM es;
322 char buf[1024] = {0};
323 char * p;
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);
330 p = buf;
331 es.dwCookie = (DWORD_PTR)&p;
332 es.dwError = 0;
333 es.pfnCallback = test_WM_SETTEXT_esCallback;
334 memset(buf, 0, sizeof(buf));
335 SendMessageA(hwndRichEdit, EM_STREAMOUT,
336 (WPARAM)(SF_TEXT), (LPARAM)&es);
337 r = strlen(buf);
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);
343 p = buf;
344 es.dwCookie = (DWORD_PTR)&p;
345 es.dwError = 0;
346 es.pfnCallback = test_WM_SETTEXT_esCallback;
347 memset(buf, 0, sizeof(buf));
348 SendMessageA(hwndRichEdit, EM_STREAMOUT,
349 (WPARAM)(SF_TEXT), (LPARAM)&es);
350 r = strlen(buf);
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);
357 p = buf;
358 es.dwCookie = (DWORD_PTR)&p;
359 es.dwError = 0;
360 es.pfnCallback = test_WM_SETTEXT_esCallback;
361 memset(buf, 0, sizeof(buf));
362 SendMessageA(hwndRichEdit, EM_STREAMOUT,
363 (WPARAM)(SF_TEXT), (LPARAM)&es);
364 r = strlen(buf);
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 {
373 int line;
374 size_t buffer_len;
375 const char *text;
376 const char *broken_text;
377 } gl[] = {
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"},
382 {4, 10, "\r\n"},
384 /* Buffer smaller than line length */
385 {0, 2, "foo bar\r"},
386 {0, 1, "foo bar\r"},
387 {0, 0, "foo bar\r"}
390 static void test_EM_GETLINE(void)
392 int i;
393 HWND hwndRichEdit = new_richedit(NULL);
394 static const int nBuf = 1024;
395 char dest[1024], origdest[1024];
396 LRESULT linecount;
397 const char text[] = "foo bar\r\n"
398 "\r"
399 "\r\r\n"
400 "bar\n";
401 BOOL broken_os = FALSE;
402 BOOL rtl = is_rtl();
404 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
405 linecount = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
406 if (linecount == 4)
408 broken_os = TRUE;
409 win_skip("Win9x, WinME and NT4 handle '\\r only' differently\n");
412 memset(origdest, 0xBB, nBuf);
413 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
415 int nCopied, expected_nCopied, expected_bytes_written;
416 char gl_text[1024];
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);
424 else
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,
438 expected_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),
442 "buffer_len=0\n");
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");
446 else
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);
454 else
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);
468 const char * text =
469 "richedit1\r"
470 "richedit1\n"
471 "richedit1\r\n"
472 "short\r"
473 "richedit1\r"
474 "\r"
475 "\r"
476 "\r\r\n";
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| */
495 int i;
496 LRESULT result;
498 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
500 result = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
501 if (result == 4) {
502 win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n");
503 return;
505 ok(result == 9, "Incorrect line count of %ld\n", result);
507 for (i = 0; i < sizeof(offset_test)/sizeof(offset_test[0]); 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");
516 else
518 const char *text1 =
519 "wine\n"
520 "richedit\x8e\xf0\n"
521 "wine";
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 < sizeof(offset_test1)/sizeof(offset_test1[0]); i++) {
529 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0);
530 if (offset_test1[i][2])
531 todo_wine 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]);
533 else
534 ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n",
535 offset_test1[i][0], result, offset_test1[i][1]);
539 DestroyWindow(hwndRichEdit);
542 static void test_EM_GETTEXTRANGE(void)
544 HWND hwndRichEdit = new_richedit(NULL);
545 const char * text1 = "foo bar\r\nfoo bar";
546 const char * text3 = "foo bar\rfoo bar";
547 const char * expect1 = "bar\r\nfoo";
548 const char * expect2 = "\nfoo";
549 const char * expect3 = "bar\rfoo";
550 char buffer[1024] = {0};
551 LRESULT result;
552 TEXTRANGEA textRange;
554 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
556 textRange.lpstrText = buffer;
557 textRange.chrg.cpMin = 4;
558 textRange.chrg.cpMax = 12;
559 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
560 ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
561 ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
563 textRange.lpstrText = buffer;
564 textRange.chrg.cpMin = 8;
565 textRange.chrg.cpMax = 12;
566 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
567 ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
568 ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
570 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
572 textRange.lpstrText = buffer;
573 textRange.chrg.cpMin = 4;
574 textRange.chrg.cpMax = 11;
575 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
576 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
578 ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
580 /* Test with multibyte character */
581 if (!is_lang_japanese)
582 skip("Skip multibyte character tests on non-Japanese platform\n");
583 else
585 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
586 textRange.chrg.cpMin = 4;
587 textRange.chrg.cpMax = 8;
588 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
589 ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
590 todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
593 DestroyWindow(hwndRichEdit);
596 static void test_EM_GETSELTEXT(void)
598 HWND hwndRichEdit = new_richedit(NULL);
599 const char * text1 = "foo bar\r\nfoo bar";
600 const char * text2 = "foo bar\rfoo bar";
601 const char * expect1 = "bar\r\nfoo";
602 const char * expect2 = "bar\rfoo";
603 char buffer[1024] = {0};
604 LRESULT result;
606 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
608 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 12);
609 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
610 ok(result == 8, "EM_GETSELTEXT returned %ld\n", result);
611 ok(!strcmp(expect1, buffer), "EM_GETSELTEXT filled %s\n", buffer);
613 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
615 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
616 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
617 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
618 ok(!strcmp(expect2, buffer), "EM_GETSELTEXT filled %s\n", buffer);
620 /* Test with multibyte character */
621 if (!is_lang_japanese)
622 skip("Skip multibyte character tests on non-Japanese platform\n");
623 else
625 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
626 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
627 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
628 ok(result == 4, "EM_GETSELTEXT returned %ld\n", result);
629 todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETSELTEXT filled %s\n", buffer);
632 DestroyWindow(hwndRichEdit);
635 static const char haystack[] = "WINEWine wineWine wine WineWine";
636 /* ^0 ^10 ^20 ^30 */
638 static const char haystack2[] = "first\r\r\nsecond";
640 struct find_s {
641 int start;
642 int end;
643 const char *needle;
644 int flags;
645 int expected_loc;
649 static struct find_s find_tests[] = {
650 /* Find in empty text */
651 {0, -1, "foo", FR_DOWN, -1},
652 {0, -1, "foo", 0, -1},
653 {0, -1, "", FR_DOWN, -1},
654 {20, 5, "foo", FR_DOWN, -1},
655 {5, 20, "foo", FR_DOWN, -1}
658 static struct find_s find_tests2[] = {
659 /* No-result find */
660 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
661 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
663 /* Subsequent finds */
664 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
665 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
666 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
667 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
669 /* Find backwards */
670 {19, 20, "Wine", FR_MATCHCASE, -1},
671 {10, 20, "Wine", FR_MATCHCASE, 13},
672 {20, 10, "Wine", FR_MATCHCASE, -1},
674 /* Case-insensitive */
675 {1, 31, "wInE", FR_DOWN, 4},
676 {1, 31, "Wine", FR_DOWN, 4},
678 /* High-to-low ranges */
679 {20, 5, "Wine", FR_DOWN, -1},
680 {2, 1, "Wine", FR_DOWN, -1},
681 {30, 29, "Wine", FR_DOWN, -1},
682 {20, 5, "Wine", 0, /*13*/ -1},
684 /* Find nothing */
685 {5, 10, "", FR_DOWN, -1},
686 {10, 5, "", FR_DOWN, -1},
687 {0, -1, "", FR_DOWN, -1},
688 {10, 5, "", 0, -1},
690 /* Whole-word search */
691 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
692 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
693 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
694 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
695 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
696 {11, -1, "winewine", FR_WHOLEWORD, 23},
697 {31, -1, "winewine", FR_WHOLEWORD, -1},
699 /* Bad ranges */
700 {5, 200, "XXX", FR_DOWN, -1},
701 {-20, 20, "Wine", FR_DOWN, -1},
702 {-20, 20, "Wine", FR_DOWN, -1},
703 {-15, -20, "Wine", FR_DOWN, -1},
704 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
706 /* Check the case noted in bug 4479 where matches at end aren't recognized */
707 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
708 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
709 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
710 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
711 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
713 /* The backwards case of bug 4479; bounds look right
714 * Fails because backward find is wrong */
715 {19, 20, "WINE", FR_MATCHCASE, -1},
716 {0, 20, "WINE", FR_MATCHCASE, 0},
718 {0, -1, "wineWine wine", FR_DOWN, 0},
719 {0, -1, "wineWine wine", 0, 0},
720 {0, -1, "INEW", 0, 1},
721 {0, 31, "INEW", 0, 1},
722 {4, -1, "INEW", 0, 10},
725 static struct find_s find_tests3[] = {
726 /* Searching for end of line characters */
727 {0, -1, "t\r\r\ns", FR_DOWN | FR_MATCHCASE, 4},
728 {6, -1, "\r\n", FR_DOWN | FR_MATCHCASE, 6},
729 {7, -1, "\n", FR_DOWN | FR_MATCHCASE, 7},
732 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
733 int findloc;
734 FINDTEXTA ft;
735 memset(&ft, 0, sizeof(ft));
736 ft.chrg.cpMin = f->start;
737 ft.chrg.cpMax = f->end;
738 ft.lpstrText = f->needle;
739 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ft);
740 ok(findloc == f->expected_loc,
741 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
742 name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
745 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
746 int id) {
747 int findloc;
748 FINDTEXTEXA ft;
749 int expected_end_loc;
751 memset(&ft, 0, sizeof(ft));
752 ft.chrg.cpMin = f->start;
753 ft.chrg.cpMax = f->end;
754 ft.lpstrText = f->needle;
755 ft.chrgText.cpMax = 0xdeadbeef;
756 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ft);
757 ok(findloc == f->expected_loc,
758 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
759 name, id, f->needle, f->start, f->end, f->flags, findloc);
760 ok(ft.chrgText.cpMin == f->expected_loc,
761 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n",
762 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin, f->expected_loc);
763 expected_end_loc = ((f->expected_loc == -1) ? -1
764 : f->expected_loc + strlen(f->needle));
765 ok(ft.chrgText.cpMax == expected_end_loc ||
766 broken(ft.chrgText.cpMin == -1 && ft.chrgText.cpMax == 0xdeadbeef), /* Win9x, WinME and NT4 */
767 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
768 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
771 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
772 int num_tests)
774 int i;
776 for (i = 0; i < num_tests; i++) {
777 check_EM_FINDTEXT(hwnd, name, &find[i], i);
778 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
782 static void test_EM_FINDTEXT(void)
784 HWND hwndRichEdit = new_richedit(NULL);
786 /* Empty rich edit control */
787 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
788 sizeof(find_tests)/sizeof(struct find_s));
790 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack);
792 /* Haystack text */
793 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
794 sizeof(find_tests2)/sizeof(struct find_s));
796 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack2);
798 /* Haystack text 2 (with EOL characters) */
799 run_tests_EM_FINDTEXT(hwndRichEdit, "3", find_tests3,
800 sizeof(find_tests3)/sizeof(struct find_s));
802 DestroyWindow(hwndRichEdit);
805 static void test_EM_POSFROMCHAR(void)
807 HWND hwndRichEdit = new_richedit(NULL);
808 int i;
809 POINTL pl;
810 LRESULT result;
811 unsigned int height = 0;
812 int xpos = 0;
813 int xpos_rtl_adjusted = 0;
814 static const char text[] = "aa\n"
815 "this is a long line of text that should be longer than the "
816 "control's width\n"
817 "cc\n"
818 "dd\n"
819 "ee\n"
820 "ff\n"
821 "gg\n"
822 "hh\n";
824 /* Fill the control to lines to ensure that most of them are offscreen */
825 for (i = 0; i < 50; i++)
827 /* Do not modify the string; it is exactly 16 characters long. */
828 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
829 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCD\r\n");
833 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
834 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
835 Richedit 3.0 accepts either of the above API conventions.
838 /* Testing Richedit 1.0 API format */
840 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
841 Since all lines are identical and drawn with the same font,
842 they should have the same height... right?
844 for (i = 0; i < 50; i++)
846 /* All the lines are 16 characters long */
847 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
848 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
849 if (i == 0)
851 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
852 ok(pl.x == 1 ||
853 broken(pl.x == 0), /* Win9x, WinME and NT4 */
854 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
855 xpos = pl.x;
856 xpos_rtl_adjusted = xpos + (is_rtl() ? 7 : 0);
858 else if (i == 1)
860 ok(pl.y > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", pl.y);
861 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
862 height = pl.y;
864 else
866 ok(pl.y == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, i * height);
867 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
871 /* Testing position at end of text */
872 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 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);
875 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
877 /* Testing position way past end of text */
878 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
879 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
880 ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
882 ok(pl.x == xpos_rtl_adjusted, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos_rtl_adjusted);
885 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
886 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
887 for (i = 0; i < 50; i++)
889 /* All the lines are 16 characters long */
890 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
891 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
892 ok(pl.y == (i - 1) * height,
893 "EM_POSFROMCHAR reports y=%d, expected %d\n",
894 pl.y, (i - 1) * height);
895 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
898 /* Testing position at end of text */
899 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 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, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
904 /* Testing position way past end of text */
905 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
906 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
907 ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
908 ok(pl.x == xpos_rtl_adjusted, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos_rtl_adjusted);
910 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
911 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
912 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
914 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
915 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
916 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
917 ok(pl.x == 1 ||
918 broken(pl.x == 0), /* Win9x, WinME and NT4 */
919 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
920 xpos = pl.x;
922 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
923 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
924 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
925 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
926 todo_wine {
927 /* Fails on builtin because horizontal scrollbar is not being shown */
928 ok(pl.x < xpos ||
929 broken(pl.x == xpos), /* Win9x, WinME and NT4 */
930 "EM_POSFROMCHAR reports x=%d, expected value less than %d\n", pl.x, xpos);
932 DestroyWindow(hwndRichEdit);
935 static void test_word_wrap(void)
937 HWND hwnd;
938 POINTL point = {0, 60}; /* This point must be below the first line */
939 const char *text = "Must be long enough to test line wrapping";
940 DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE;
941 int res, pos, lines, prevlines, reflines[3];
943 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
944 * when specified on window creation and set later. */
945 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
946 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
947 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
948 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text);
949 ok(res, "WM_SETTEXT failed.\n");
950 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
951 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
952 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
953 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
955 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
956 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
957 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
958 DestroyWindow(hwnd);
960 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle|WS_HSCROLL,
961 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
962 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
964 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text);
965 ok(res, "WM_SETTEXT failed.\n");
966 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
967 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
968 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
969 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
971 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
972 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
973 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
974 DestroyWindow(hwnd);
976 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle|ES_AUTOHSCROLL,
977 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
978 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
979 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text);
980 ok(res, "WM_SETTEXT failed.\n");
981 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
982 ok(!pos ||
983 broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
984 "pos=%d indicating word wrap when none is expected.\n", pos);
985 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
986 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
988 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle);
989 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
990 ok(!pos ||
991 broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
992 "pos=%d indicating word wrap when none is expected.\n", pos);
993 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
994 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
995 DestroyWindow(hwnd);
997 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL,
998 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
999 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
1000 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
1001 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text);
1002 ok(res, "WM_SETTEXT failed.\n");
1003 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
1004 ok(!pos ||
1005 broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1006 "pos=%d indicating word wrap when none is expected.\n", pos);
1007 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1008 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1010 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle);
1011 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
1012 ok(!pos ||
1013 broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1014 "pos=%d indicating word wrap when none is expected.\n", pos);
1015 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1016 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1018 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
1019 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 1);
1020 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
1021 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
1022 ok(!pos ||
1023 broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1024 "pos=%d indicating word wrap when none is expected.\n", pos);
1025 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1026 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1028 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 0);
1029 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
1030 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point);
1031 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
1032 DestroyWindow(hwnd);
1034 /* First lets see if the text would wrap normally (needed for reference) */
1035 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
1036 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
1037 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
1038 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1039 res = SendMessageA(hwnd, EM_REPLACESEL, FALSE, (LPARAM)text);
1040 ok(res, "EM_REPLACESEL failed.\n");
1041 /* Should have wrapped */
1042 reflines[0] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1043 ok(reflines[0] > 1, "Line was expected to wrap (%d lines).\n", reflines[0]);
1044 /* Resize the window to fit the line */
1045 MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
1046 /* Text should not be wrapped */
1047 reflines[1] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1048 ok(reflines[1] == 1, "Line wasn't expected to wrap (%d lines).\n", reflines[1]);
1049 /* Resize the window again to make sure the line wraps again */
1050 MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
1051 reflines[2] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1052 ok(reflines[2] > 1, "Line was expected to wrap (%d lines).\n", reflines[2]);
1053 DestroyWindow(hwnd);
1055 /* Same test with redraw disabled */
1056 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
1057 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
1058 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
1059 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1060 /* Redraw is disabled by making the window invisible. */
1061 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
1062 ok(!IsWindowVisible(hwnd), "Window shouldn't be visible.\n");
1063 res = SendMessageA(hwnd, EM_REPLACESEL, FALSE, (LPARAM)text);
1064 ok(res, "EM_REPLACESEL failed.\n");
1065 /* Should have wrapped */
1066 prevlines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1067 ok(prevlines == reflines[0],
1068 "Line was expected to wrap (%d lines).\n", prevlines);
1069 /* Resize the window to fit the line, no change to the number of lines */
1070 MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
1071 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1072 todo_wine
1073 ok(lines == prevlines ||
1074 broken(lines == reflines[1]), /* Win98, WinME and NT4 */
1075 "Expected no change in the number of lines\n");
1076 /* Resize the window again to make sure the line wraps again */
1077 MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
1078 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1079 todo_wine
1080 ok(lines == prevlines ||
1081 broken(lines == reflines[2]), /* Win98, WinME and NT4 */
1082 "Expected no change in the number of lines\n");
1083 DestroyWindow(hwnd);
1086 static void test_EM_GETOPTIONS(void)
1088 HWND hwnd;
1089 DWORD options;
1091 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL,
1092 WS_POPUP,
1093 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1094 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1095 ok(options == 0, "Incorrect options %x\n", options);
1096 DestroyWindow(hwnd);
1098 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL,
1099 WS_POPUP|WS_VSCROLL|WS_HSCROLL,
1100 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1101 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1102 ok(options == ECO_AUTOVSCROLL ||
1103 broken(options == 0), /* Win9x, WinME and NT4 */
1104 "Incorrect initial options %x\n", options);
1105 DestroyWindow(hwnd);
1108 static void test_autoscroll(void)
1110 HWND hwnd;
1111 UINT ret;
1113 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
1114 * auto vertical/horizontal scrolling options. */
1115 hwnd = CreateWindowExA(0, RICHEDIT_CLASS10A, NULL,
1116 WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL,
1117 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1118 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1119 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1120 ok(ret & ECO_AUTOVSCROLL ||
1121 broken(!(ret & ECO_AUTOVSCROLL)), /* Win9x, WinME and NT4 */
1122 "ECO_AUTOVSCROLL isn't set.\n");
1123 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1124 ret = GetWindowLongA(hwnd, GWL_STYLE);
1125 todo_wine
1126 ok(ret & ES_AUTOVSCROLL ||
1127 broken(!(ret & ES_AUTOVSCROLL)), /* Win9x, WinMe and NT4 */
1128 "ES_AUTOVSCROLL isn't set.\n");
1129 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1130 DestroyWindow(hwnd);
1132 hwnd = CreateWindowExA(0, RICHEDIT_CLASS10A, NULL,
1133 WS_POPUP|ES_MULTILINE,
1134 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1135 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1136 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1137 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
1138 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1139 ret = GetWindowLongA(hwnd, GWL_STYLE);
1140 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
1141 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1142 DestroyWindow(hwnd);
1145 static void simulate_typing_characters(HWND hwnd, const char* szChars)
1147 int ret;
1149 while (*szChars != '\0') {
1150 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
1151 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
1152 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
1153 SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
1154 szChars++;
1159 * This test attempts to show the effect of enter on a richedit
1160 * control v1.0 inserts CRLF whereas for higher versions it only
1161 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
1162 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
1163 * does for higher. The same test is cloned in riched32 and riched20.
1165 static void test_enter(void)
1167 static const struct {
1168 const char *initialtext;
1169 const int cursor;
1170 const char *expectedtext;
1171 } testenteritems[] = {
1172 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n"},
1173 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n"},
1174 { "aa\rabbb\r\n", 7, "aa\rabbb\r\n\r\n"},
1175 { "aa\rabbb\r\n", 3, "aa\r\r\nabbb\r\n"},
1176 { "aa\rabbb\r\n", 2, "aa\r\n\rabbb\r\n"}
1179 char expectedbuf[1024];
1180 char resultbuf[1024];
1181 HWND hwndRichEdit = new_richedit(NULL);
1182 UINT i,j;
1184 for (i = 0; i < sizeof(testenteritems)/sizeof(testenteritems[0]); i++) {
1186 char buf[1024] = {0};
1187 LRESULT result;
1188 GETTEXTEX getText;
1189 const char *expected;
1191 /* Set the text to the initial text */
1192 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext);
1193 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
1195 /* Send Enter */
1196 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor);
1197 simulate_typing_characters(hwndRichEdit, "\r");
1199 /* 1. Retrieve with WM_GETTEXT */
1200 buf[0] = 0x00;
1201 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
1202 expected = testenteritems[i].expectedtext;
1204 resultbuf[0]=0x00;
1205 for (j = 0; j < (UINT)result; j++)
1206 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF);
1207 expectedbuf[0] = '\0';
1208 for (j = 0; j < strlen(expected); j++)
1209 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF);
1211 result = strcmp(expected, buf);
1212 ok (result == 0,
1213 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
1214 i, resultbuf, expectedbuf);
1216 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
1217 getText.cb = sizeof(buf);
1218 getText.flags = GT_DEFAULT;
1219 getText.codepage = CP_ACP;
1220 getText.lpDefaultChar = NULL;
1221 getText.lpUsedDefChar = NULL;
1222 buf[0] = 0x00;
1223 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1224 expected = testenteritems[i].expectedtext;
1226 resultbuf[0]=0x00;
1227 for (j = 0; j < (UINT)result; j++)
1228 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF);
1229 expectedbuf[0] = '\0';
1230 for (j = 0; j < strlen(expected); j++)
1231 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF);
1233 result = strcmp(expected, buf);
1234 ok (result == 0 || broken(buf[0]==0x00 /* WinNT4 */),
1235 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
1236 i, resultbuf, expectedbuf);
1238 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
1239 getText.cb = sizeof(buf);
1240 getText.flags = GT_USECRLF;
1241 getText.codepage = CP_ACP;
1242 getText.lpDefaultChar = NULL;
1243 getText.lpUsedDefChar = NULL;
1244 buf[0] = 0x00;
1245 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1246 expected = testenteritems[i].expectedtext;
1248 resultbuf[0]=0x00;
1249 for (j = 0; j < (UINT)result; j++)
1250 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF);
1251 expectedbuf[0] = '\0';
1252 for (j = 0; j < strlen(expected); j++)
1253 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF);
1255 result = strcmp(expected, buf);
1256 ok (result == 0 || broken(buf[0]==0x00 /* WinNT4 */),
1257 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
1258 i, resultbuf, expectedbuf);
1261 DestroyWindow(hwndRichEdit);
1264 struct exsetsel_s {
1265 LONG min;
1266 LONG max;
1267 LRESULT expected_retval;
1268 int expected_getsel_start;
1269 int expected_getsel_end;
1270 BOOL result_todo;
1271 BOOL sel_todo;
1274 static const struct exsetsel_s exsetsel_tests[] = {
1275 /* sanity tests */
1276 {5, 10, 10, 5, 10, 0, 0 },
1277 {15, 17, 17, 15, 17, 0, 0 },
1278 /* test cpMax > strlen() */
1279 {0, 100, 19, 0, 19, 1, 0 },
1280 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
1281 {-1, 1, 17, 17, 17, 1, 0 },
1282 /* test cpMin == cpMax */
1283 {5, 5, 5, 5, 5, 0, 0 },
1284 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1285 {-1, 0, 5, 5, 5, 0, 0 },
1286 {-1, 17, 5, 5, 5, 0, 0 },
1287 {-1, 18, 5, 5, 5, 0, 0 },
1288 /* test cpMin < 0 && cpMax < 0 */
1289 {-1, -1, 17, 17, 17, 0, 0 },
1290 {-4, -5, 17, 17, 17, 0, 0 },
1291 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
1292 {0, -1, 19, 0, 19, 1, 0 },
1293 {17, -5, 19, 17, 19, 1, 0 },
1294 {18, -3, 19, 17, 19, 1, 1 },
1295 /* test if cpMin > cpMax */
1296 {15, 19, 19, 15, 19, 1, 0 },
1297 {19, 15, 19, 15, 19, 1, 0 },
1298 /* cpMin == strlen() && cpMax > cpMin */
1299 {17, 18, 17, 17, 17, 1, 1 },
1300 {17, 50, 19, 17, 19, 1, 0 },
1303 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1304 CHARRANGE cr;
1305 LRESULT result;
1306 int start, end;
1308 cr.cpMin = setsel->min;
1309 cr.cpMax = setsel->max;
1310 result = SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr);
1312 if (setsel->result_todo)
1313 todo_wine ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1314 else
1315 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1317 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1319 if (setsel->sel_todo) {
1320 todo_wine {
1321 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);
1323 } else {
1324 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);
1328 static void test_EM_EXSETSEL(void)
1330 HWND hwndRichEdit = new_richedit(NULL);
1331 int i;
1332 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1334 /* sending some text to the window */
1335 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
1336 /* 01234567890123456 */
1338 for (i = 0; i < num_tests; i++) {
1339 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1342 if (!is_lang_japanese)
1343 skip("Skip multibyte character tests on non-Japanese platform\n");
1344 else
1346 CHARRANGE cr;
1347 LRESULT result;
1348 #define MAX_BUF_LEN 1024
1349 char bufA[MAX_BUF_LEN] = {0};
1351 /* Test with multibyte character */
1352 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1353 /* 012345 6 7 8901 */
1354 cr.cpMin = 4, cr.cpMax = 8;
1355 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1356 todo_wine ok(result == 7, "EM_EXSETSEL return %ld expected 7\n", result);
1357 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA);
1358 todo_wine ok(!strcmp(bufA, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1359 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1360 ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin);
1361 ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax);
1364 DestroyWindow(hwndRichEdit);
1367 static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1368 LRESULT result;
1369 int start, end;
1371 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max);
1373 if (setsel->result_todo)
1374 todo_wine ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1375 else
1376 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1378 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1380 if (setsel->sel_todo) {
1381 todo_wine {
1382 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1384 } else {
1385 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1389 static void test_EM_SETSEL(void)
1391 char buffA[32] = {0};
1392 HWND hwndRichEdit = new_richedit(NULL);
1393 int i;
1394 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1396 /* sending some text to the window */
1397 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
1398 /* 01234567890123456 */
1400 for (i = 0; i < num_tests; i++) {
1401 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1404 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18);
1405 buffA[0] = 123;
1406 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
1407 ok(buffA[0] == 0, "selection text %s\n", buffA);
1409 if (!is_lang_japanese)
1410 skip("Skip multibyte character tests on non-Japanese platform\n");
1411 else
1413 int sel_start, sel_end;
1414 LRESULT result;
1416 /* Test with multibyte character */
1417 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1418 /* 012345 6 7 8901 */
1419 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
1420 todo_wine ok(result == 7, "EM_SETSEL return %ld expected 7\n", result);
1421 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA);
1422 todo_wine ok(!strcmp(buffA, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1423 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
1424 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start);
1425 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end);
1428 DestroyWindow(hwndRichEdit);
1431 START_TEST( editor )
1433 MSG msg;
1434 time_t end;
1435 BOOL ret;
1437 /* Must explicitly LoadLibrary(). The test has no references to functions in
1438 * RICHED32.DLL, so the linker doesn't actually link to it. */
1439 hmoduleRichEdit = LoadLibraryA("riched32.dll");
1440 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1441 is_lang_japanese = (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE);
1443 test_WM_SETTEXT();
1444 test_EM_GETTEXTRANGE();
1445 test_EM_GETSELTEXT();
1446 test_WM_GETTEXTLENGTH();
1447 test_EM_STREAMIN();
1448 test_EM_STREAMOUT();
1449 test_EM_GETLINE();
1450 test_EM_LINELENGTH();
1451 test_EM_FINDTEXT();
1452 test_EM_POSFROMCHAR();
1453 test_word_wrap();
1454 test_EM_GETOPTIONS();
1455 test_autoscroll();
1456 test_enter();
1457 test_EM_EXSETSEL();
1458 test_EM_SETSEL();
1460 /* Set the environment variable WINETEST_RICHED32 to keep windows
1461 * responsive and open for 30 seconds. This is useful for debugging.
1463 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1464 * 50ms before retrying the queue. */
1465 end = time(NULL) + 30;
1466 if (getenv( "WINETEST_RICHED32" )) {
1467 while (time(NULL) < end) {
1468 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
1469 TranslateMessage(&msg);
1470 DispatchMessageA(&msg);
1471 } else {
1472 Sleep(50);
1477 OleFlushClipboard();
1478 ret = FreeLibrary(hmoduleRichEdit);
1479 ok(ret, "error: %u\n", GetLastError());