1 /* 2 * Unit test suite for rich edit control 1.0 3 * 4 * Copyright 2006 Google (Thomas Kho) 5 * Copyright 2007 Matt Finnicum 6 * Copyright 2007 Dmitry Timoshkov 7 * Copyright 2007 Alex Villacís Lasso 8 * 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. 13 * 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. 18 * 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 22 */ 23 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> 36 37 static HMODULE hmoduleRichEdit; 38 static BOOL is_lang_japanese; 39 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; 47 } 48 49 static HWND new_richedit(HWND parent) { 50 return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent); 51 } 52 53 static BOOL is_rtl(void) { 54 LOCALESIGNATURE sig; 55 56 return (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE, 57 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) && 58 (sig.lsUsb[3] & 0x08000000) != 0); 59 } 60 61 static void test_WM_SETTEXT(void) 62 { 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 */ 85 }; 86 HWND hwndRichEdit = new_richedit(NULL); 87 int i; 88 BOOL rtl = is_rtl(); 89 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. 93 * 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) 105 */ 106 107 for (i = 0; i < ARRAY_SIZE(testitems); i++) { 108 109 char buf[1024] = {0}; 110 LRESULT result; 111 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); 125 } 126 127 DestroyWindow(hwndRichEdit); 128 } 129 130 static void test_WM_GETTEXTLENGTH(void) 131 { 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; 137 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)); 144 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)); 150 151 /* Test with multibyte character */ 152 if (!is_lang_japanese) 153 skip("Skip multibyte character tests on non-Japanese platform\n"); 154 else 155 { 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); 159 } 160 161 DestroyWindow(hwndRichEdit); 162 } 163 164 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, 165 LPBYTE pbBuff, 166 LONG cb, 167 LONG *pcb) 168 { 169 const char** str = (const char**)dwCookie; 170 int size = strlen(*str); 171 *pcb = cb; 172 if (*pcb > size) { 173 *pcb = size; 174 } 175 if (*pcb > 0) { 176 memcpy(pbBuff, *str, *pcb); 177 *str += *pcb; 178 } 179 return 0; 180 } 181 182 183 static void test_EM_STREAMIN(void) 184 { 185 HWND hwndRichEdit = new_richedit(NULL); 186 LRESULT result; 187 EDITSTREAM es; 188 char buffer[1024] = {0}; 189 190 const char * streamText0 = "{\\rtf1 TestSomeText}"; 191 const char * streamText0a = "{\\rtf1 TestSomeText\\par}"; 192 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; 193 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"; 198 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 }"; 208 209 const char * streamText3 = "RichEdit1"; 210 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); 217 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); 225 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); 232 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); 240 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); 247 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); 255 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); 261 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); 269 270 271 es.dwCookie = (DWORD_PTR)&streamText2; 272 es.dwError = 0; 273 SendMessageA(hwndRichEdit, EM_STREAMIN, 274 (WPARAM)(SF_RTF), (LPARAM)&es); 275 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); 280 } 281 result = strcmp (buffer,"RichEdit1"); 282 todo_wine { 283 ok (result == 0, 284 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 285 } 286 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); 287 288 es.dwCookie = (DWORD_PTR)&streamText3; 289 es.dwError = 0; 290 SendMessageA(hwndRichEdit, EM_STREAMIN, 291 (WPARAM)(SF_RTF), (LPARAM)&es); 292 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); 299 300 DestroyWindow(hwndRichEdit); 301 } 302 303 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, 304 LPBYTE pbBuff, 305 LONG cb, 306 LONG *pcb) 307 { 308 char** str = (char**)dwCookie; 309 *pcb = cb; 310 if (*pcb > 0) { 311 memcpy(*str, pbBuff, *pcb); 312 *str += *pcb; 313 } 314 return 0; 315 } 316 317 static void test_EM_STREAMOUT(void) 318 { 319 HWND hwndRichEdit = new_richedit(NULL); 320 int r; 321 EDITSTREAM es; 322 char buf[1024] = {0}; 323 char * p; 324 325 const char * TestItem1 = "TestSomeText"; 326 const char * TestItem2 = "TestSomeText\r"; 327 const char * TestItem3 = "TestSomeText\r\n"; 328 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); 341 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); 351 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); 355 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); 368 369 DestroyWindow(hwndRichEdit); 370 } 371 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"}, 383 384 /* Buffer smaller than line length */ 385 {0, 2, "foo bar\r"}, 386 {0, 1, "foo bar\r"}, 387 {0, 0, "foo bar\r"} 388 }; 389 390 static void test_EM_GETLINE(void) 391 { 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(); 403 404 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 405 linecount = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 406 if (linecount == 4) 407 { 408 broken_os = TRUE; 409 win_skip("Win9x, WinME and NT4 handle '\\r only' differently\n"); 410 } 411 412 memset(origdest, 0xBB, nBuf); 413 for (i = 0; i < ARRAY_SIZE(gl); i++) 414 { 415 int nCopied, expected_nCopied, expected_bytes_written; 416 char gl_text[1024]; 417 418 if (gl[i].line >= linecount) 419 continue; /* Win9x, WinME and NT4 */ 420 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); 426 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)); 430 431 memset(dest, 0xBB, nBuf); 432 *(WORD *) dest = gl[i].buffer_len; 433 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 447 { 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); 459 } 460 } 461 462 DestroyWindow(hwndRichEdit); 463 } 464 465 static void test_EM_LINELENGTH(void) 466 { 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| */ 494 }; 495 int i; 496 LRESULT result; 497 498 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 499 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; 504 } 505 ok(result == 9, "Incorrect line count of %ld\n", result); 506 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]); 511 } 512 513 /* Test with multibyte character */ 514 if (!is_lang_japanese) 515 skip("Skip multibyte character tests on non-Japanese platform\n"); 516 else 517 { 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 */ 526 }; 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]); 533 } 534 } 535 536 DestroyWindow(hwndRichEdit); 537 } 538 539 static void test_EM_GETTEXTRANGE(void) 540 { 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}; 548 LRESULT result; 549 TEXTRANGEA textRange; 550 551 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 552 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); 559 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); 566 567 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); 568 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); 574 575 ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 576 577 /* Test with multibyte character */ 578 if (!is_lang_japanese) 579 skip("Skip multibyte character tests on non-Japanese platform\n"); 580 else 581 { 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 todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 588 } 589 590 DestroyWindow(hwndRichEdit); 591 } 592 593 static void test_EM_GETSELTEXT(void) 594 { 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}; 601 LRESULT result; 602 603 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 604 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); 609 610 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 611 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); 616 617 /* Test with multibyte character */ 618 if (!is_lang_japanese) 619 skip("Skip multibyte character tests on non-Japanese platform\n"); 620 else 621 { 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 todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETSELTEXT filled %s\n", buffer); 627 } 628 629 DestroyWindow(hwndRichEdit); 630 } 631 632 static const char haystack[] = "WINEWine wineWine wine WineWine"; 633 /* ^0 ^10 ^20 ^30 */ 634 635 static const char haystack2[] = "first\r\r\nsecond"; 636 637 struct find_s { 638 int start; 639 int end; 640 const char *needle; 641 int flags; 642 int expected_loc; 643 }; 644 645 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} 653 }; 654 655 static struct find_s find_tests2[] = { 656 /* No-result find */ 657 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1}, 658 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1}, 659 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}, 665 666 /* Find backwards */ 667 {19, 20, "Wine", FR_MATCHCASE, -1}, 668 {10, 20, "Wine", FR_MATCHCASE, 13}, 669 {20, 10, "Wine", FR_MATCHCASE, -1}, 670 671 /* Case-insensitive */ 672 {1, 31, "wInE", FR_DOWN, 4}, 673 {1, 31, "Wine", FR_DOWN, 4}, 674 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}, 680 681 /* Find nothing */ 682 {5, 10, "", FR_DOWN, -1}, 683 {10, 5, "", FR_DOWN, -1}, 684 {0, -1, "", FR_DOWN, -1}, 685 {10, 5, "", 0, -1}, 686 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}, 695 696 /* Bad ranges */ 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}, 702 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}, 709 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}, 714 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}, 720 }; 721 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}, 727 }; 728 729 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) { 730 int findloc; 731 FINDTEXTA ft; 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); 740 } 741 742 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, 743 int id) { 744 int findloc; 745 FINDTEXTEXA ft; 746 int expected_end_loc; 747 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); 766 } 767 768 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, 769 int num_tests) 770 { 771 int i; 772 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); 776 } 777 } 778 779 static void test_EM_FINDTEXT(void) 780 { 781 HWND hwndRichEdit = new_richedit(NULL); 782 783 /* Empty rich edit control */ 784 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, ARRAY_SIZE(find_tests)); 785 786 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack); 787 788 /* Haystack text */ 789 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, ARRAY_SIZE(find_tests2)); 790 791 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack2); 792 793 /* Haystack text 2 (with EOL characters) */ 794 run_tests_EM_FINDTEXT(hwndRichEdit, "3", find_tests3, ARRAY_SIZE(find_tests3)); 795 796 DestroyWindow(hwndRichEdit); 797 } 798 799 static void test_EM_POSFROMCHAR(void) 800 { 801 HWND hwndRichEdit = new_richedit(NULL); 802 int i; 803 POINTL pl; 804 LRESULT result; 805 unsigned int height = 0; 806 int xpos = 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 " 810 "control's width\n" 811 "cc\n" 812 "dd\n" 813 "ee\n" 814 "ff\n" 815 "gg\n" 816 "hh\n"; 817 818 /* Fill the control to lines to ensure that most of them are offscreen */ 819 for (i = 0; i < 50; i++) 820 { 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"); 824 } 825 826 /* 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. 830 */ 831 832 /* Testing Richedit 1.0 API format */ 833 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? 837 */ 838 for (i = 0; i < 50; i++) 839 { 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); 843 if (i == 0) 844 { 845 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y); 846 ok(pl.x == 1 || 847 broken(pl.x == 0), /* Win9x, WinME and NT4 */ 848 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x); 849 xpos = pl.x; 850 xpos_rtl_adjusted = xpos + (is_rtl() ? 7 : 0); 851 } 852 else if (i == 1) 853 { 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); 856 height = pl.y; 857 } 858 else 859 { 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); 862 } 863 } 864 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); 870 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); 875 876 ok(pl.x == xpos_rtl_adjusted, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos_rtl_adjusted); 877 878 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++) 882 { 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); 890 } 891 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); 897 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); 903 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 */ 907 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); 911 ok(pl.x == 1 || 912 broken(pl.x == 0), /* Win9x, WinME and NT4 */ 913 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x); 914 xpos = pl.x; 915 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); 920 todo_wine { 921 /* Fails on builtin because horizontal scrollbar is not being shown */ 922 ok(pl.x < xpos || 923 broken(pl.x == xpos), /* Win9x, WinME and NT4 */ 924 "EM_POSFROMCHAR reports x=%d, expected value less than %d\n", pl.x, xpos); 925 } 926 DestroyWindow(hwndRichEdit); 927 } 928 929 static void test_word_wrap(void) 930 { 931 HWND hwnd; 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]; 936 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); 948 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); 952 DestroyWindow(hwnd); 953 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()); 957 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); 964 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); 968 DestroyWindow(hwnd); 969 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); 976 ok(!pos || 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); 981 982 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle); 983 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 984 ok(!pos || 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); 989 DestroyWindow(hwnd); 990 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); 998 ok(!pos || 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); 1003 1004 SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle); 1005 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 1006 ok(!pos || 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); 1011 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); 1016 ok(!pos || 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); 1021 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); 1027 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); 1048 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); 1066 todo_wine 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); 1073 todo_wine 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); 1078 } 1079 1080 static void test_EM_GETOPTIONS(void) 1081 { 1082 HWND hwnd; 1083 DWORD options; 1084 1085 hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, 1086 WS_POPUP, 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); 1091 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); 1100 } 1101 1102 static void test_autoscroll(void) 1103 { 1104 HWND hwnd; 1105 UINT ret; 1106 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); 1119 todo_wine 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); 1125 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); 1137 } 1138 1139 static void simulate_typing_characters(HWND hwnd, const char* szChars) 1140 { 1141 int ret; 1142 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); 1148 szChars++; 1149 } 1150 } 1151 1152 static void format_test_result(char *target, const char *src) 1153 { 1154 int i; 1155 for (i = 0; i < strlen(src); i++) 1156 sprintf(target + 2*i, "%02x", src[i] & 0xFF); 1157 target[2*i] = 0; 1158 } 1159 1160 /* 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 1167 */ 1168 static void test_enter(void) 1169 { 1170 static const struct { 1171 const char *initialtext; 1172 const int cursor; 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"} 1180 }; 1181 1182 char expectedbuf[1024]; 1183 char resultbuf[1024]; 1184 HWND hwndRichEdit = new_richedit(NULL); 1185 UINT i; 1186 char buf[1024] = {0}; 1187 GETTEXTEX getText = {sizeof(buf)}; 1188 LRESULT result; 1189 const char *expected; 1190 1191 for (i = 0; i < ARRAY_SIZE(testenteritems); i++) 1192 { 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); 1196 1197 /* Send Enter */ 1198 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor); 1199 simulate_typing_characters(hwndRichEdit, "\r"); 1200 1201 /* 1. Retrieve with WM_GETTEXT */ 1202 buf[0] = 0x00; 1203 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 1204 expected = testenteritems[i].expectedtext; 1205 1206 format_test_result(resultbuf, buf); 1207 format_test_result(expectedbuf, expected); 1208 1209 result = strcmp(expected, buf); 1210 ok (result == 0, 1211 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n", 1212 i, resultbuf, expectedbuf); 1213 1214 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */ 1215 getText.flags = GT_DEFAULT; 1216 getText.codepage = CP_ACP; 1217 buf[0] = 0x00; 1218 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 1219 expected = testenteritems[i].expectedtext; 1220 1221 format_test_result(resultbuf, buf); 1222 format_test_result(expectedbuf, expected); 1223 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); 1228 1229 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */ 1230 getText.flags = GT_USECRLF; 1231 getText.codepage = CP_ACP; 1232 buf[0] = 0x00; 1233 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 1234 expected = testenteritems[i].expectedtext; 1235 1236 format_test_result(resultbuf, buf); 1237 format_test_result(expectedbuf, expected); 1238 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); 1243 } 1244 1245 /* Show that WM_CHAR is handled differently from WM_KEYDOWN */ 1246 getText.flags = GT_DEFAULT; 1247 getText.codepage = CP_ACP; 1248 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); 1253 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); 1260 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); 1265 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); 1272 1273 DestroyWindow(hwndRichEdit); 1274 } 1275 1276 struct exsetsel_s { 1277 LONG min; 1278 LONG max; 1279 LRESULT expected_retval; 1280 int expected_getsel_start; 1281 int expected_getsel_end; 1282 BOOL result_todo; 1283 BOOL sel_todo; 1284 }; 1285 1286 static const struct exsetsel_s exsetsel_tests[] = { 1287 /* sanity 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 }, 1313 }; 1314 1315 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 1316 CHARRANGE cr; 1317 LRESULT result; 1318 int start, end; 1319 1320 cr.cpMin = setsel->min; 1321 cr.cpMax = setsel->max; 1322 result = SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); 1323 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); 1326 1327 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 1328 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); 1333 } 1334 1335 static void test_EM_EXSETSEL(void) 1336 { 1337 HWND hwndRichEdit = new_richedit(NULL); 1338 int i; 1339 const int num_tests = ARRAY_SIZE(exsetsel_tests); 1340 1341 /* sending some text to the window */ 1342 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 1343 /* 01234567890123456 */ 1344 1345 for (i = 0; i < num_tests; i++) { 1346 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i); 1347 } 1348 1349 if (!is_lang_japanese) 1350 skip("Skip multibyte character tests on non-Japanese platform\n"); 1351 else 1352 { 1353 CHARRANGE cr; 1354 LRESULT result; 1355 #define MAX_BUF_LEN 1024 1356 char bufA[MAX_BUF_LEN] = {0}; 1357 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 todo_wine 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); 1369 } 1370 1371 DestroyWindow(hwndRichEdit); 1372 } 1373 1374 static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 1375 LRESULT result; 1376 int start, end; 1377 1378 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max); 1379 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); 1382 1383 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 1384 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); 1389 } 1390 1391 static void test_EM_SETSEL(void) 1392 { 1393 char buffA[32] = {0}; 1394 HWND hwndRichEdit = new_richedit(NULL); 1395 int i; 1396 const int num_tests = ARRAY_SIZE(exsetsel_tests); 1397 1398 /* sending some text to the window */ 1399 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 1400 /* 01234567890123456 */ 1401 1402 for (i = 0; i < num_tests; i++) { 1403 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i); 1404 } 1405 1406 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18); 1407 buffA[0] = 123; 1408 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA); 1409 ok(buffA[0] == 0, "selection text %s\n", buffA); 1410 1411 if (!is_lang_japanese) 1412 skip("Skip multibyte character tests on non-Japanese platform\n"); 1413 else 1414 { 1415 int sel_start, sel_end; 1416 LRESULT result; 1417 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 todo_wine 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); 1428 } 1429 1430 DestroyWindow(hwndRichEdit); 1431 } 1432 1433 START_TEST( editor ) 1434 { 1435 MSG msg; 1436 time_t end; 1437 BOOL ret; 1438 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(GetUserDefaultLangID()) == LANG_JAPANESE); 1444 1445 test_WM_SETTEXT(); 1446 test_EM_GETTEXTRANGE(); 1447 test_EM_GETSELTEXT(); 1448 test_WM_GETTEXTLENGTH(); 1449 test_EM_STREAMIN(); 1450 test_EM_STREAMOUT(); 1451 test_EM_GETLINE(); 1452 test_EM_LINELENGTH(); 1453 test_EM_FINDTEXT(); 1454 test_EM_POSFROMCHAR(); 1455 test_word_wrap(); 1456 test_EM_GETOPTIONS(); 1457 test_autoscroll(); 1458 test_enter(); 1459 test_EM_EXSETSEL(); 1460 test_EM_SETSEL(); 1461 1462 /* Set the environment variable WINETEST_RICHED32 to keep windows 1463 * responsive and open for 30 seconds. This is useful for debugging. 1464 * 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); 1473 } else { 1474 Sleep(50); 1475 } 1476 } 1477 } 1478 1479 OleFlushClipboard(); 1480 ret = FreeLibrary(hmoduleRichEdit); 1481 ok(ret, "error: %u\n", GetLastError()); 1482 } 1483