1 /* 2 * Unit test suite for rich edit control 3 * 4 * Copyright 2006 Google (Thomas Kho) 5 * Copyright 2007 Matt Finnicum 6 * Copyright 2007 Dmitry Timoshkov 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #define COBJMACROS 24 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <assert.h> 28 #include <windef.h> 29 #include <winbase.h> 30 #include <wingdi.h> 31 #include <winuser.h> 32 #include <winnls.h> 33 #include <ole2.h> 34 #include <richedit.h> 35 #include <richole.h> 36 #include <commdlg.h> 37 #include <time.h> 38 #include <wine/test.h> 39 40 #define ID_RICHEDITTESTDBUTTON 0x123 41 42 static CHAR string1[MAX_PATH], string2[MAX_PATH], string3[MAX_PATH]; 43 44 #define ok_w3(format, szString1, szString2, szString3) \ 45 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ 46 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ 47 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \ 48 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \ 49 format, string1, string2, string3); 50 51 static HMODULE hmoduleRichEdit; 52 static BOOL is_lang_japanese; 53 54 static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent) { 55 HWND hwnd; 56 hwnd = CreateWindowA(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL 57 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL, 58 hmoduleRichEdit, NULL); 59 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError()); 60 return hwnd; 61 } 62 63 static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent) { 64 HWND hwnd; 65 hwnd = CreateWindowW(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL 66 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL, 67 hmoduleRichEdit, NULL); 68 ok(hwnd != NULL, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName), (int) GetLastError()); 69 return hwnd; 70 } 71 72 static HWND new_richedit(HWND parent) { 73 return new_window(RICHEDIT_CLASS20A, ES_MULTILINE, parent); 74 } 75 76 static HWND new_richedit_with_style(HWND parent, DWORD style) { 77 return new_window(RICHEDIT_CLASS20A, style, parent); 78 } 79 80 static HWND new_richeditW(HWND parent) { 81 return new_windowW(RICHEDIT_CLASS20W, ES_MULTILINE, parent); 82 } 83 84 /* Keeps the window reponsive for the deley_time in seconds. 85 * This is useful for debugging a test to see what is happening. */ 86 static void keep_responsive(time_t delay_time) 87 { 88 MSG msg; 89 time_t end; 90 91 /* The message pump uses PeekMessage() to empty the queue and then 92 * sleeps for 50ms before retrying the queue. */ 93 end = time(NULL) + delay_time; 94 while (time(NULL) < end) { 95 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { 96 TranslateMessage(&msg); 97 DispatchMessageA(&msg); 98 } else { 99 Sleep(50); 100 } 101 } 102 } 103 104 static void simulate_typing_characters(HWND hwnd, const char* szChars) 105 { 106 int ret; 107 108 while (*szChars != '\0') { 109 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1); 110 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1); 111 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret); 112 SendMessageA(hwnd, WM_KEYUP, *szChars, 1); 113 szChars++; 114 } 115 } 116 117 static BOOL hold_key(int vk) 118 { 119 BYTE key_state[256]; 120 BOOL result; 121 122 result = GetKeyboardState(key_state); 123 ok(result, "GetKeyboardState failed.\n"); 124 if (!result) return FALSE; 125 key_state[vk] |= 0x80; 126 result = SetKeyboardState(key_state); 127 ok(result, "SetKeyboardState failed.\n"); 128 return result != 0; 129 } 130 131 static BOOL release_key(int vk) 132 { 133 BYTE key_state[256]; 134 BOOL result; 135 136 result = GetKeyboardState(key_state); 137 ok(result, "GetKeyboardState failed.\n"); 138 if (!result) return FALSE; 139 key_state[vk] &= ~0x80; 140 result = SetKeyboardState(key_state); 141 ok(result, "SetKeyboardState failed.\n"); 142 return result != 0; 143 } 144 145 static const char haystack[] = "WINEWine wineWine wine WineWine"; 146 /* ^0 ^10 ^20 ^30 */ 147 148 struct find_s { 149 int start; 150 int end; 151 const char *needle; 152 int flags; 153 int expected_loc; 154 }; 155 156 157 static struct find_s find_tests[] = { 158 /* Find in empty text */ 159 {0, -1, "foo", FR_DOWN, -1}, 160 {0, -1, "foo", 0, -1}, 161 {0, -1, "", FR_DOWN, -1}, 162 {20, 5, "foo", FR_DOWN, -1}, 163 {5, 20, "foo", FR_DOWN, -1} 164 }; 165 166 static struct find_s find_tests2[] = { 167 /* No-result find */ 168 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1}, 169 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1}, 170 171 /* Subsequent finds */ 172 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4}, 173 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13}, 174 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, 175 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 176 177 /* Find backwards */ 178 {19, 20, "Wine", FR_MATCHCASE, 13}, 179 {10, 20, "Wine", FR_MATCHCASE, 4}, 180 {20, 10, "Wine", FR_MATCHCASE, 13}, 181 182 /* Case-insensitive */ 183 {1, 31, "wInE", FR_DOWN, 4}, 184 {1, 31, "Wine", FR_DOWN, 4}, 185 186 /* High-to-low ranges */ 187 {20, 5, "Wine", FR_DOWN, -1}, 188 {2, 1, "Wine", FR_DOWN, -1}, 189 {30, 29, "Wine", FR_DOWN, -1}, 190 {20, 5, "Wine", 0, 13}, 191 192 /* Find nothing */ 193 {5, 10, "", FR_DOWN, -1}, 194 {10, 5, "", FR_DOWN, -1}, 195 {0, -1, "", FR_DOWN, -1}, 196 {10, 5, "", 0, -1}, 197 198 /* Whole-word search */ 199 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, 200 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1}, 201 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, 202 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0}, 203 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23}, 204 {11, -1, "winewine", FR_WHOLEWORD, 0}, 205 {31, -1, "winewine", FR_WHOLEWORD, 23}, 206 207 /* Bad ranges */ 208 {5, 200, "XXX", FR_DOWN, -1}, 209 {-20, 20, "Wine", FR_DOWN, -1}, 210 {-20, 20, "Wine", FR_DOWN, -1}, 211 {-15, -20, "Wine", FR_DOWN, -1}, 212 {1<<12, 1<<13, "Wine", FR_DOWN, -1}, 213 214 /* Check the case noted in bug 4479 where matches at end aren't recognized */ 215 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, 216 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 217 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 218 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, 219 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, 220 221 /* The backwards case of bug 4479; bounds look right 222 * Fails because backward find is wrong */ 223 {19, 20, "WINE", FR_MATCHCASE, 0}, 224 {0, 20, "WINE", FR_MATCHCASE, -1}, 225 226 {0, -1, "wineWine wine", 0, -1}, 227 }; 228 229 static WCHAR *atowstr(const char *str) 230 { 231 WCHAR *ret; 232 DWORD len; 233 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 234 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 235 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 236 return ret; 237 } 238 239 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode) 240 { 241 int findloc; 242 243 if(unicode){ 244 FINDTEXTW ftw; 245 memset(&ftw, 0, sizeof(ftw)); 246 ftw.chrg.cpMin = f->start; 247 ftw.chrg.cpMax = f->end; 248 ftw.lpstrText = atowstr(f->needle); 249 250 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ftw); 251 ok(findloc == f->expected_loc, 252 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 253 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 254 255 findloc = SendMessageA(hwnd, EM_FINDTEXTW, f->flags, (LPARAM)&ftw); 256 ok(findloc == f->expected_loc, 257 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 258 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 259 260 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText); 261 }else{ 262 FINDTEXTA fta; 263 memset(&fta, 0, sizeof(fta)); 264 fta.chrg.cpMin = f->start; 265 fta.chrg.cpMax = f->end; 266 fta.lpstrText = f->needle; 267 268 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&fta); 269 ok(findloc == f->expected_loc, 270 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 271 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 272 } 273 } 274 275 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, 276 int id, BOOL unicode) 277 { 278 int findloc; 279 int expected_end_loc; 280 281 if(unicode){ 282 FINDTEXTEXW ftw; 283 memset(&ftw, 0, sizeof(ftw)); 284 ftw.chrg.cpMin = f->start; 285 ftw.chrg.cpMax = f->end; 286 ftw.lpstrText = atowstr(f->needle); 287 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ftw); 288 ok(findloc == f->expected_loc, 289 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 290 name, id, f->needle, f->start, f->end, f->flags, findloc); 291 ok(ftw.chrgText.cpMin == f->expected_loc, 292 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 293 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMin); 294 expected_end_loc = ((f->expected_loc == -1) ? -1 295 : f->expected_loc + strlen(f->needle)); 296 ok(ftw.chrgText.cpMax == expected_end_loc, 297 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n", 298 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMax, expected_end_loc); 299 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText); 300 }else{ 301 FINDTEXTEXA fta; 302 memset(&fta, 0, sizeof(fta)); 303 fta.chrg.cpMin = f->start; 304 fta.chrg.cpMax = f->end; 305 fta.lpstrText = f->needle; 306 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&fta); 307 ok(findloc == f->expected_loc, 308 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 309 name, id, f->needle, f->start, f->end, f->flags, findloc); 310 ok(fta.chrgText.cpMin == f->expected_loc, 311 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 312 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMin); 313 expected_end_loc = ((f->expected_loc == -1) ? -1 314 : f->expected_loc + strlen(f->needle)); 315 ok(fta.chrgText.cpMax == expected_end_loc, 316 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n", 317 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMax, expected_end_loc); 318 } 319 } 320 321 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, 322 int num_tests, BOOL unicode) 323 { 324 int i; 325 326 for (i = 0; i < num_tests; i++) { 327 check_EM_FINDTEXT(hwnd, name, &find[i], i, unicode); 328 check_EM_FINDTEXTEX(hwnd, name, &find[i], i, unicode); 329 } 330 } 331 332 static void test_EM_FINDTEXT(BOOL unicode) 333 { 334 HWND hwndRichEdit; 335 CHARFORMAT2A cf2; 336 337 if(unicode) 338 hwndRichEdit = new_richeditW(NULL); 339 else 340 hwndRichEdit = new_richedit(NULL); 341 342 /* Empty rich edit control */ 343 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, 344 sizeof(find_tests)/sizeof(struct find_s), unicode); 345 346 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack); 347 348 /* Haystack text */ 349 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, 350 sizeof(find_tests2)/sizeof(struct find_s), unicode); 351 352 /* Setting a format on an arbitrary range should have no effect in search 353 results. This tests correct offset reporting across runs. */ 354 cf2.cbSize = sizeof(CHARFORMAT2A); 355 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 356 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 357 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 358 SendMessageA(hwndRichEdit, EM_SETSEL, 6, 20); 359 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 360 361 /* Haystack text, again */ 362 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, 363 sizeof(find_tests2)/sizeof(struct find_s), unicode); 364 365 /* Yet another range */ 366 cf2.dwMask = CFM_BOLD | cf2.dwMask; 367 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects; 368 SendMessageA(hwndRichEdit, EM_SETSEL, 11, 15); 369 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 370 371 /* Haystack text, again */ 372 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, 373 sizeof(find_tests2)/sizeof(struct find_s), unicode); 374 375 DestroyWindow(hwndRichEdit); 376 } 377 378 static const struct getline_s { 379 int line; 380 size_t buffer_len; 381 const char *text; 382 } gl[] = { 383 {0, 10, "foo bar\r"}, 384 {1, 10, "\r"}, 385 {2, 10, "bar\r"}, 386 {3, 10, "\r"}, 387 388 /* Buffer smaller than line length */ 389 {0, 2, "foo bar\r"}, 390 {0, 1, "foo bar\r"}, 391 {0, 0, "foo bar\r"} 392 }; 393 394 static void test_EM_GETLINE(void) 395 { 396 int i; 397 HWND hwndRichEdit = new_richedit(NULL); 398 static const int nBuf = 1024; 399 char dest[1024], origdest[1024]; 400 const char text[] = "foo bar\n" 401 "\n" 402 "bar\n"; 403 404 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 405 406 memset(origdest, 0xBB, nBuf); 407 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++) 408 { 409 int nCopied; 410 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text)); 411 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text)); 412 memset(dest, 0xBB, nBuf); 413 *(WORD *) dest = gl[i].buffer_len; 414 415 /* EM_GETLINE appends a "\r\0" to the end of the line 416 * nCopied counts up to and including the '\r' */ 417 nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest); 418 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, 419 expected_nCopied); 420 /* two special cases since a parameter is passed via dest */ 421 if (gl[i].buffer_len == 0) 422 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2), 423 "buffer_len=0\n"); 424 else if (gl[i].buffer_len == 1) 425 ok(dest[0] == gl[i].text[0] && !dest[1] && 426 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n"); 427 else 428 { 429 /* Prepare hex strings of buffers to dump on failure. */ 430 char expectedbuf[1024]; 431 char resultbuf[1024]; 432 int j; 433 resultbuf[0] = '\0'; 434 for (j = 0; j < 32; j++) 435 sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF); 436 expectedbuf[0] = '\0'; 437 for (j = 0; j < expected_bytes_written; j++) /* Written bytes */ 438 sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF); 439 for (; j < gl[i].buffer_len; j++) /* Ignored bytes */ 440 sprintf(expectedbuf+strlen(expectedbuf), "??"); 441 for (; j < 32; j++) /* Bytes after declared buffer size */ 442 sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF); 443 444 /* Test the part of the buffer that is expected to be written according 445 * to the MSDN documentation fo EM_GETLINE, which does not state that 446 * a NULL terminating character will be added unless no text is copied. 447 * 448 * Windows NT does not append a NULL terminating character, but 449 * Windows 2000 and up do append a NULL terminating character if there 450 * is space in the buffer. The test will ignore this difference. */ 451 ok(!strncmp(dest, gl[i].text, expected_bytes_written), 452 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", 453 i, expected_bytes_written, expectedbuf, resultbuf); 454 /* Test the part of the buffer after the declared length to make sure 455 * there are no buffer overruns. */ 456 ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len, 457 nBuf - gl[i].buffer_len), 458 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", 459 i, expected_bytes_written, expectedbuf, resultbuf); 460 } 461 } 462 463 DestroyWindow(hwndRichEdit); 464 } 465 466 static void test_EM_LINELENGTH(void) 467 { 468 HWND hwndRichEdit = new_richedit(NULL); 469 const char * text = 470 "richedit1\r" 471 "richedit1\n" 472 "richedit1\r\n" 473 "richedit1"; 474 int offset_test[10][2] = { 475 {0, 9}, 476 {5, 9}, 477 {10, 9}, 478 {15, 9}, 479 {20, 9}, 480 {25, 9}, 481 {30, 9}, 482 {35, 9}, 483 {40, 0}, 484 {45, 0}, 485 }; 486 int i; 487 LRESULT result; 488 489 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 490 491 for (i = 0; i < 10; i++) { 492 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0); 493 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n", 494 offset_test[i][0], result, offset_test[i][1]); 495 } 496 497 /* Test with multibyte character */ 498 if (!is_lang_japanese) 499 skip("Skip multibyte character tests on non-Japanese platform\n"); 500 else 501 { 502 const char *text1 = 503 "wine\n" 504 "richedit\x8e\xf0\n" 505 "wine"; 506 int offset_test1[3][2] = { 507 {0, 4}, /* Line 1: |wine\n */ 508 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */ 509 {15, 4}, /* Line 3: |wine */ 510 }; 511 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 512 for (i = 0; i < sizeof(offset_test1)/sizeof(offset_test1[0]); i++) { 513 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0); 514 ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n", 515 offset_test1[i][0], result, offset_test1[i][1]); 516 } 517 } 518 519 DestroyWindow(hwndRichEdit); 520 } 521 522 static int get_scroll_pos_y(HWND hwnd) 523 { 524 POINT p = {-1, -1}; 525 SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&p); 526 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y); 527 return p.y; 528 } 529 530 static void move_cursor(HWND hwnd, LONG charindex) 531 { 532 CHARRANGE cr; 533 cr.cpMax = charindex; 534 cr.cpMin = charindex; 535 SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); 536 } 537 538 static void line_scroll(HWND hwnd, int amount) 539 { 540 SendMessageA(hwnd, EM_LINESCROLL, 0, amount); 541 } 542 543 static void test_EM_SCROLLCARET(void) 544 { 545 int prevY, curY; 546 const char text[] = "aa\n" 547 "this is a long line of text that should be longer than the " 548 "control's width\n" 549 "cc\n" 550 "dd\n" 551 "ee\n" 552 "ff\n" 553 "gg\n" 554 "hh\n"; 555 /* The richedit window height needs to be large enough vertically to fit in 556 * more than two lines of text, so the new_richedit function can't be used 557 * since a height of 60 was not large enough on some systems. 558 */ 559 HWND hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, 560 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 561 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 562 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 563 564 /* Can't verify this */ 565 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 566 567 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 568 569 /* Caret above visible window */ 570 line_scroll(hwndRichEdit, 3); 571 prevY = get_scroll_pos_y(hwndRichEdit); 572 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 573 curY = get_scroll_pos_y(hwndRichEdit); 574 ok(prevY != curY, "%d == %d\n", prevY, curY); 575 576 /* Caret below visible window */ 577 move_cursor(hwndRichEdit, sizeof(text) - 1); 578 line_scroll(hwndRichEdit, -3); 579 prevY = get_scroll_pos_y(hwndRichEdit); 580 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 581 curY = get_scroll_pos_y(hwndRichEdit); 582 ok(prevY != curY, "%d == %d\n", prevY, curY); 583 584 /* Caret in visible window */ 585 move_cursor(hwndRichEdit, sizeof(text) - 2); 586 prevY = get_scroll_pos_y(hwndRichEdit); 587 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 588 curY = get_scroll_pos_y(hwndRichEdit); 589 ok(prevY == curY, "%d != %d\n", prevY, curY); 590 591 /* Caret still in visible window */ 592 line_scroll(hwndRichEdit, -1); 593 prevY = get_scroll_pos_y(hwndRichEdit); 594 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 595 curY = get_scroll_pos_y(hwndRichEdit); 596 ok(prevY == curY, "%d != %d\n", prevY, curY); 597 598 DestroyWindow(hwndRichEdit); 599 } 600 601 static void test_EM_POSFROMCHAR(void) 602 { 603 HWND hwndRichEdit = new_richedit(NULL); 604 int i, expected; 605 LRESULT result; 606 unsigned int height = 0; 607 int xpos = 0; 608 POINTL pt; 609 LOCALESIGNATURE sig; 610 BOOL rtl; 611 PARAFORMAT2 fmt; 612 static const char text[] = "aa\n" 613 "this is a long line of text that should be longer than the " 614 "control's width\n" 615 "cc\n" 616 "dd\n" 617 "ee\n" 618 "ff\n" 619 "gg\n" 620 "hh\n"; 621 622 rtl = (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE, 623 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) && 624 (sig.lsUsb[3] & 0x08000000) != 0); 625 626 /* Fill the control to lines to ensure that most of them are offscreen */ 627 for (i = 0; i < 50; i++) 628 { 629 /* Do not modify the string; it is exactly 16 characters long. */ 630 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 631 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n"); 632 } 633 634 /* 635 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void. 636 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y) 637 Richedit 3.0 accepts either of the above API conventions. 638 */ 639 640 /* Testing Richedit 2.0 API format */ 641 642 /* Testing start of lines. X-offset should be constant on all cases (native is 1). 643 Since all lines are identical and drawn with the same font, 644 they should have the same height... right? 645 */ 646 for (i = 0; i < 50; i++) 647 { 648 /* All the lines are 16 characters long */ 649 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0); 650 if (i == 0) 651 { 652 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 653 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 654 xpos = LOWORD(result); 655 } 656 else if (i == 1) 657 { 658 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result)); 659 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 660 height = HIWORD(result); 661 } 662 else 663 { 664 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height); 665 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 666 } 667 } 668 669 /* Testing position at end of text */ 670 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0); 671 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height); 672 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 673 674 /* Testing position way past end of text */ 675 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0); 676 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height); 677 expected = (rtl ? 8 : 1); 678 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected); 679 680 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */ 681 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */ 682 for (i = 0; i < 50; i++) 683 { 684 /* All the lines are 16 characters long */ 685 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0); 686 ok((signed short)(HIWORD(result)) == (i - 1) * height, 687 "EM_POSFROMCHAR reports y=%hd, expected %d\n", 688 (signed short)(HIWORD(result)), (i - 1) * height); 689 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 690 } 691 692 /* Testing position at end of text */ 693 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0); 694 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height); 695 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 696 697 /* Testing position way past end of text */ 698 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0); 699 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height); 700 expected = (rtl ? 8 : 1); 701 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected); 702 703 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */ 704 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 705 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */ 706 707 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0); 708 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 709 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 710 xpos = LOWORD(result); 711 712 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0); 713 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0); 714 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 715 ok((signed short)(LOWORD(result)) < xpos, 716 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n", 717 (signed short)(LOWORD(result)), xpos); 718 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0); 719 720 /* Test around end of text that doesn't end in a newline. */ 721 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"12345678901234"); 722 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 723 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1); 724 ok(pt.x > 1, "pt.x = %d\n", pt.x); 725 xpos = pt.x; 726 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 727 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)); 728 ok(pt.x > xpos, "pt.x = %d\n", pt.x); 729 xpos = (rtl ? pt.x + 7 : pt.x); 730 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 731 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1); 732 ok(pt.x == xpos, "pt.x = %d\n", pt.x); 733 734 /* Try a negative position. */ 735 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1); 736 ok(pt.x == 1, "pt.x = %d\n", pt.x); 737 738 /* test negative indentation */ 739 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 740 (LPARAM)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}"); 741 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 0); 742 ok(pt.x == 1, "pt.x = %d\n", pt.x); 743 744 fmt.cbSize = sizeof(fmt); 745 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 746 ok(fmt.dxStartIndent == -400, "got %d\n", fmt.dxStartIndent); 747 ok(fmt.dxOffset == 200, "got %d\n", fmt.dxOffset); 748 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment); 749 750 DestroyWindow(hwndRichEdit); 751 } 752 753 static void test_EM_SETCHARFORMAT(void) 754 { 755 HWND hwndRichEdit = new_richedit(NULL); 756 CHARFORMAT2A cf2; 757 CHARFORMAT2W cfW; 758 int rc = 0; 759 int tested_effects[] = { 760 CFE_BOLD, 761 CFE_ITALIC, 762 CFE_UNDERLINE, 763 CFE_STRIKEOUT, 764 CFE_PROTECTED, 765 CFE_LINK, 766 CFE_SUBSCRIPT, 767 CFE_SUPERSCRIPT, 768 0 769 }; 770 int i; 771 CHARRANGE cr; 772 LOCALESIGNATURE sig; 773 BOOL rtl; 774 DWORD expect_effects; 775 776 rtl = (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE, 777 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) && 778 (sig.lsUsb[3] & 0x08000000) != 0); 779 780 /* check charformat defaults */ 781 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 782 cf2.cbSize = sizeof(CHARFORMAT2A); 783 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 784 ok(cf2.dwMask == CFM_ALL2, "got %08x\n", cf2.dwMask); 785 expect_effects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; 786 if (cf2.wWeight > 550) expect_effects |= CFE_BOLD; 787 ok(cf2.dwEffects == expect_effects, "got %08x\n", cf2.dwEffects); 788 ok(cf2.yOffset == 0, "got %d\n", cf2.yOffset); 789 ok(cf2.sSpacing == 0, "got %d\n", cf2.sSpacing); 790 ok(cf2.lcid == GetSystemDefaultLCID(), "got %x\n", cf2.lcid); 791 ok(cf2.sStyle == 0, "got %d\n", cf2.sStyle); 792 ok(cf2.wKerning == 0, "got %d\n", cf2.wKerning); 793 ok(cf2.bAnimation == 0, "got %d\n", cf2.bAnimation); 794 ok(cf2.bRevAuthor == 0, "got %d\n", cf2.bRevAuthor); 795 796 /* Invalid flags, CHARFORMAT2 structure blanked out */ 797 memset(&cf2, 0, sizeof(cf2)); 798 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2); 799 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 800 801 /* A valid flag, CHARFORMAT2 structure blanked out */ 802 memset(&cf2, 0, sizeof(cf2)); 803 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 804 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 805 806 /* A valid flag, CHARFORMAT2 structure blanked out */ 807 memset(&cf2, 0, sizeof(cf2)); 808 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 809 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 810 811 /* A valid flag, CHARFORMAT2 structure blanked out */ 812 memset(&cf2, 0, sizeof(cf2)); 813 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2); 814 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 815 816 /* A valid flag, CHARFORMAT2 structure blanked out */ 817 memset(&cf2, 0, sizeof(cf2)); 818 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 819 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 820 821 /* Invalid flags, CHARFORMAT2 structure minimally filled */ 822 memset(&cf2, 0, sizeof(cf2)); 823 cf2.cbSize = sizeof(CHARFORMAT2A); 824 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2); 825 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 826 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 827 ok(rc == FALSE, "Should not be able to undo here.\n"); 828 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 829 830 /* A valid flag, CHARFORMAT2 structure minimally filled */ 831 memset(&cf2, 0, sizeof(cf2)); 832 cf2.cbSize = sizeof(CHARFORMAT2A); 833 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 834 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 835 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 836 ok(rc == FALSE, "Should not be able to undo here.\n"); 837 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 838 839 /* A valid flag, CHARFORMAT2 structure minimally filled */ 840 memset(&cf2, 0, sizeof(cf2)); 841 cf2.cbSize = sizeof(CHARFORMAT2A); 842 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 843 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 844 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 845 ok(rc == FALSE, "Should not be able to undo here.\n"); 846 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 847 848 /* A valid flag, CHARFORMAT2 structure minimally filled */ 849 memset(&cf2, 0, sizeof(cf2)); 850 cf2.cbSize = sizeof(CHARFORMAT2A); 851 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2); 852 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 853 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 854 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n"); 855 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 856 857 /* A valid flag, CHARFORMAT2 structure minimally filled */ 858 memset(&cf2, 0, sizeof(cf2)); 859 cf2.cbSize = sizeof(CHARFORMAT2A); 860 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 861 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 862 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 863 ok(rc == TRUE, "Should not be able to undo here.\n"); 864 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 865 866 cf2.cbSize = sizeof(CHARFORMAT2A); 867 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 868 869 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */ 870 cf2.cbSize = sizeof(CHARFORMAT2A); 871 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 872 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 873 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 874 875 /* wParam==0 is default char format, does not set modify */ 876 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 877 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 878 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 879 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 880 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 881 if (! rtl) 882 { 883 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 884 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 885 } 886 else 887 skip("RTL language found\n"); 888 889 /* wParam==SCF_SELECTION sets modify if nonempty selection */ 890 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 891 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 892 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 893 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 894 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 895 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 896 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 897 898 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 899 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 900 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 901 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 902 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 903 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 904 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 905 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 906 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 907 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 908 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 909 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 910 911 /* wParam==SCF_ALL sets modify regardless of whether text is present */ 912 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 913 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 914 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 915 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 916 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 917 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 918 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 919 920 DestroyWindow(hwndRichEdit); 921 922 /* EM_GETCHARFORMAT tests */ 923 for (i = 0; tested_effects[i]; i++) 924 { 925 hwndRichEdit = new_richedit(NULL); 926 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 927 928 /* Need to set a TrueType font to get consistent CFM_BOLD results */ 929 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 930 cf2.cbSize = sizeof(CHARFORMAT2A); 931 cf2.dwMask = CFM_FACE|CFM_WEIGHT; 932 cf2.dwEffects = 0; 933 strcpy(cf2.szFaceName, "Courier New"); 934 cf2.wWeight = FW_DONTCARE; 935 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 936 937 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 938 cf2.cbSize = sizeof(CHARFORMAT2A); 939 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 4); 940 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 941 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 942 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 943 || 944 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 945 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 946 ok((cf2.dwEffects & tested_effects[i]) == 0, 947 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 948 949 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 950 cf2.cbSize = sizeof(CHARFORMAT2A); 951 cf2.dwMask = tested_effects[i]; 952 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT) 953 cf2.dwMask = CFM_SUPERSCRIPT; 954 cf2.dwEffects = tested_effects[i]; 955 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 956 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 957 958 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 959 cf2.cbSize = sizeof(CHARFORMAT2A); 960 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 961 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 962 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 963 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 964 || 965 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 966 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 967 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 968 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]); 969 970 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 971 cf2.cbSize = sizeof(CHARFORMAT2A); 972 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 973 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 974 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 975 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 976 || 977 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 978 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 979 ok((cf2.dwEffects & tested_effects[i]) == 0, 980 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 981 982 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 983 cf2.cbSize = sizeof(CHARFORMAT2A); 984 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3); 985 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 986 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 987 (cf2.dwMask & CFM_SUPERSCRIPT) == 0) 988 || 989 (cf2.dwMask & tested_effects[i]) == 0), 990 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]); 991 992 DestroyWindow(hwndRichEdit); 993 } 994 995 for (i = 0; tested_effects[i]; i++) 996 { 997 hwndRichEdit = new_richedit(NULL); 998 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 999 1000 /* Need to set a TrueType font to get consistent CFM_BOLD results */ 1001 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1002 cf2.cbSize = sizeof(CHARFORMAT2A); 1003 cf2.dwMask = CFM_FACE|CFM_WEIGHT; 1004 cf2.dwEffects = 0; 1005 strcpy(cf2.szFaceName, "Courier New"); 1006 cf2.wWeight = FW_DONTCARE; 1007 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 1008 1009 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1010 cf2.cbSize = sizeof(CHARFORMAT2A); 1011 cf2.dwMask = tested_effects[i]; 1012 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT) 1013 cf2.dwMask = CFM_SUPERSCRIPT; 1014 cf2.dwEffects = tested_effects[i]; 1015 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 1016 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1017 1018 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1019 cf2.cbSize = sizeof(CHARFORMAT2A); 1020 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 1021 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1022 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1023 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 1024 || 1025 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 1026 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 1027 ok((cf2.dwEffects & tested_effects[i]) == 0, 1028 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 1029 1030 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1031 cf2.cbSize = sizeof(CHARFORMAT2A); 1032 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 1033 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1034 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1035 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 1036 || 1037 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 1038 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 1039 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 1040 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]); 1041 1042 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1043 cf2.cbSize = sizeof(CHARFORMAT2A); 1044 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3); 1045 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1046 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1047 (cf2.dwMask & CFM_SUPERSCRIPT) == 0) 1048 || 1049 (cf2.dwMask & tested_effects[i]) == 0), 1050 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]); 1051 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 1052 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]); 1053 1054 DestroyWindow(hwndRichEdit); 1055 } 1056 1057 /* Effects applied on an empty selection should take effect when selection is 1058 replaced with text */ 1059 hwndRichEdit = new_richedit(NULL); 1060 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1061 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1062 1063 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1064 cf2.cbSize = sizeof(CHARFORMAT2A); 1065 cf2.dwMask = CFM_BOLD; 1066 cf2.dwEffects = CFE_BOLD; 1067 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1068 1069 /* Selection is now nonempty */ 1070 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1071 1072 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1073 cf2.cbSize = sizeof(CHARFORMAT2A); 1074 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1075 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1076 1077 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1078 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1079 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1080 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1081 1082 1083 /* Set two effects on an empty selection */ 1084 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1085 /* first clear bold, italic */ 1086 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1087 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1088 cf2.cbSize = sizeof(CHARFORMAT2A); 1089 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1090 cf2.dwEffects = 0; 1091 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1092 1093 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1094 1095 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1096 cf2.cbSize = sizeof(CHARFORMAT2A); 1097 cf2.dwMask = CFM_BOLD; 1098 cf2.dwEffects = CFE_BOLD; 1099 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1100 cf2.dwMask = CFM_ITALIC; 1101 cf2.dwEffects = CFE_ITALIC; 1102 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1103 1104 /* Selection is now nonempty */ 1105 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1106 1107 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1108 cf2.cbSize = sizeof(CHARFORMAT2A); 1109 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1110 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1111 1112 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)), 1113 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC)); 1114 ok((cf2.dwEffects & (CFE_BOLD|CFE_ITALIC)) == (CFE_BOLD|CFE_ITALIC), 1115 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC)); 1116 1117 /* Setting the (empty) selection to exactly the same place as before should 1118 NOT clear the insertion style! */ 1119 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1120 /* first clear bold, italic */ 1121 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1122 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1123 cf2.cbSize = sizeof(CHARFORMAT2A); 1124 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1125 cf2.dwEffects = 0; 1126 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1127 1128 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1129 1130 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1131 cf2.cbSize = sizeof(CHARFORMAT2A); 1132 cf2.dwMask = CFM_BOLD; 1133 cf2.dwEffects = CFE_BOLD; 1134 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1135 1136 /* Empty selection in same place, insert style should NOT be forgotten here. */ 1137 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); 1138 1139 /* Selection is now nonempty */ 1140 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1141 1142 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1143 cf2.cbSize = sizeof(CHARFORMAT2A); 1144 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1145 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1146 1147 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1148 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1149 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1150 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1151 1152 /* Moving the selection will clear the insertion style */ 1153 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1154 /* first clear bold, italic */ 1155 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1156 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1157 cf2.cbSize = sizeof(CHARFORMAT2A); 1158 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1159 cf2.dwEffects = 0; 1160 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1161 1162 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1163 1164 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1165 cf2.cbSize = sizeof(CHARFORMAT2A); 1166 cf2.dwMask = CFM_BOLD; 1167 cf2.dwEffects = CFE_BOLD; 1168 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1169 1170 /* Move selection and then put it back, insert style should be forgotten here. */ 1171 SendMessageA(hwndRichEdit, EM_SETSEL, 3, 3); 1172 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1173 1174 /* Selection is now nonempty */ 1175 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1176 1177 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1178 cf2.cbSize = sizeof(CHARFORMAT2A); 1179 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1180 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1181 1182 ok(((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1183 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1184 ok((cf2.dwEffects & CFE_BOLD) == 0, 1185 "%d, cf2.dwEffects == 0x%08x not expecting effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1186 1187 /* Ditto with EM_EXSETSEL */ 1188 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1189 /* first clear bold, italic */ 1190 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1191 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1192 cf2.cbSize = sizeof(CHARFORMAT2A); 1193 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1194 cf2.dwEffects = 0; 1195 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1196 1197 cr.cpMin = 2; cr.cpMax = 2; 1198 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1199 1200 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1201 cf2.cbSize = sizeof(CHARFORMAT2A); 1202 cf2.dwMask = CFM_BOLD; 1203 cf2.dwEffects = CFE_BOLD; 1204 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1205 1206 /* Empty selection in same place, insert style should NOT be forgotten here. */ 1207 cr.cpMin = 2; cr.cpMax = 2; 1208 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1209 1210 /* Selection is now nonempty */ 1211 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1212 1213 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1214 cf2.cbSize = sizeof(CHARFORMAT2A); 1215 cr.cpMin = 2; cr.cpMax = 6; 1216 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1217 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1218 1219 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1220 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1221 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1222 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1223 1224 /* show that wWeight is at the correct offset in CHARFORMAT2A */ 1225 memset(&cf2, 0, sizeof(cf2)); 1226 cf2.cbSize = sizeof(cf2); 1227 cf2.dwMask = CFM_WEIGHT; 1228 cf2.wWeight = 100; 1229 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1230 memset(&cf2, 0, sizeof(cf2)); 1231 cf2.cbSize = sizeof(cf2); 1232 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1233 ok(cf2.wWeight == 100, "got %d\n", cf2.wWeight); 1234 1235 memset(&cf2, 0, sizeof(cf2)); 1236 cf2.cbSize = sizeof(cf2); 1237 cf2.dwMask = CFM_SPACING; 1238 cf2.sSpacing = 10; 1239 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1240 memset(&cf2, 0, sizeof(cf2)); 1241 cf2.cbSize = sizeof(cf2); 1242 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1243 ok(cf2.sSpacing == 10, "got %d\n", cf2.sSpacing); 1244 1245 /* show that wWeight is at the correct offset in CHARFORMAT2W */ 1246 memset(&cfW, 0, sizeof(cfW)); 1247 cfW.cbSize = sizeof(cfW); 1248 cfW.dwMask = CFM_WEIGHT; 1249 cfW.wWeight = 100; 1250 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1251 memset(&cfW, 0, sizeof(cfW)); 1252 cfW.cbSize = sizeof(cfW); 1253 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1254 ok(cfW.wWeight == 100, "got %d\n", cfW.wWeight); 1255 1256 memset(&cfW, 0, sizeof(cfW)); 1257 cfW.cbSize = sizeof(cfW); 1258 cfW.dwMask = CFM_SPACING; 1259 cfW.sSpacing = 10; 1260 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1261 memset(&cfW, 0, sizeof(cfW)); 1262 cfW.cbSize = sizeof(cfW); 1263 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1264 ok(cfW.sSpacing == 10, "got %d\n", cfW.sSpacing); 1265 1266 /* test CFE_UNDERLINE and bUnderlineType interaction */ 1267 /* clear bold, italic */ 1268 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1269 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1270 cf2.cbSize = sizeof(CHARFORMAT2A); 1271 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1272 cf2.dwEffects = 0; 1273 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1274 1275 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */ 1276 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1277 cf2.cbSize = sizeof(CHARFORMAT2A); 1278 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1279 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1280 "got %08x\n", cf2.dwMask); 1281 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1282 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType); 1283 1284 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */ 1285 cf2.dwMask = CFM_UNDERLINETYPE; 1286 cf2.bUnderlineType = CFU_UNDERLINE; 1287 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1288 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1289 cf2.cbSize = sizeof(CHARFORMAT2A); 1290 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1291 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1292 "got %08x\n", cf2.dwMask); 1293 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1294 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType); 1295 1296 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */ 1297 cf2.dwMask = CFM_UNDERLINETYPE; 1298 cf2.bUnderlineType = CFU_UNDERLINENONE; 1299 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1300 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1301 cf2.cbSize = sizeof(CHARFORMAT2A); 1302 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1303 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1304 "got %08x\n", cf2.dwMask); 1305 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1306 ok(cf2.bUnderlineType == CFU_UNDERLINENONE, "got %x\n", cf2.bUnderlineType); 1307 1308 /* another underline type also sets CFE_UNDERLINE */ 1309 cf2.dwMask = CFM_UNDERLINETYPE; 1310 cf2.bUnderlineType = CFU_UNDERLINEDOUBLE; 1311 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1312 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1313 cf2.cbSize = sizeof(CHARFORMAT2A); 1314 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1315 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1316 "got %08x\n", cf2.dwMask); 1317 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1318 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1319 1320 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */ 1321 cf2.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; 1322 cf2.bUnderlineType = CFU_UNDERLINEDOUBLE; 1323 cf2.dwEffects = 0; 1324 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1325 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1326 cf2.cbSize = sizeof(CHARFORMAT2A); 1327 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1328 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1329 "got %08x\n", cf2.dwMask); 1330 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1331 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1332 1333 /* And turing it back on again by just setting CFE_UNDERLINE */ 1334 cf2.dwMask = CFM_UNDERLINE; 1335 cf2.dwEffects = CFE_UNDERLINE; 1336 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1337 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1338 cf2.cbSize = sizeof(CHARFORMAT2A); 1339 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1340 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1341 "got %08x\n", cf2.dwMask); 1342 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1343 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1344 1345 DestroyWindow(hwndRichEdit); 1346 } 1347 1348 static void test_EM_SETTEXTMODE(void) 1349 { 1350 HWND hwndRichEdit = new_richedit(NULL); 1351 CHARFORMAT2A cf2, cf2test; 1352 CHARRANGE cr; 1353 int rc = 0; 1354 1355 /*Attempt to use mutually exclusive modes*/ 1356 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT|TM_RICHTEXT, 0); 1357 ok(rc == E_INVALIDARG, 1358 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc); 1359 1360 /*Test that EM_SETTEXTMODE fails if text exists within the control*/ 1361 /*Insert text into the control*/ 1362 1363 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1364 1365 /*Attempt to change the control to plain text mode*/ 1366 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 1367 ok(rc == E_UNEXPECTED, 1368 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc); 1369 1370 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted. 1371 If rich text is pasted, it should have the same formatting as the rest 1372 of the text in the control*/ 1373 1374 /*Italicize the text 1375 *NOTE: If the default text was already italicized, the test will simply 1376 reverse; in other words, it will copy a regular "wine" into a plain 1377 text window that uses an italicized format*/ 1378 cf2.cbSize = sizeof(CHARFORMAT2A); 1379 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 1380 1381 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 1382 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 1383 1384 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 1385 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 1386 1387 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine; 1388 however, SCF_ALL has been implemented*/ 1389 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 1390 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1391 1392 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 1393 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 1394 1395 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1396 1397 /*Select the string "wine"*/ 1398 cr.cpMin = 0; 1399 cr.cpMax = 4; 1400 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1401 1402 /*Copy the italicized "wine" to the clipboard*/ 1403 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 1404 1405 /*Reset the formatting to default*/ 1406 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects; 1407 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 1408 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1409 1410 /*Clear the text in the control*/ 1411 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1412 1413 /*Switch to Plain Text Mode*/ 1414 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 1415 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc); 1416 1417 /*Input "wine" again in normal format*/ 1418 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1419 1420 /*Paste the italicized "wine" into the control*/ 1421 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1422 1423 /*Select a character from the first "wine" string*/ 1424 cr.cpMin = 2; 1425 cr.cpMax = 3; 1426 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1427 1428 /*Retrieve its formatting*/ 1429 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 1430 1431 /*Select a character from the second "wine" string*/ 1432 cr.cpMin = 5; 1433 cr.cpMax = 6; 1434 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1435 1436 /*Retrieve its formatting*/ 1437 cf2test.cbSize = sizeof(CHARFORMAT2A); 1438 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test); 1439 1440 /*Compare the two formattings*/ 1441 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1442 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n", 1443 cf2.dwEffects, cf2test.dwEffects); 1444 /*Test TM_RICHTEXT by: switching back to Rich Text mode 1445 printing "wine" in the current format(normal) 1446 pasting "wine" from the clipboard(italicized) 1447 comparing the two formats(should differ)*/ 1448 1449 /*Attempt to switch with text in control*/ 1450 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0); 1451 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc); 1452 1453 /*Clear control*/ 1454 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1455 1456 /*Switch into Rich Text mode*/ 1457 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0); 1458 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc); 1459 1460 /*Print "wine" in normal formatting into the control*/ 1461 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1462 1463 /*Paste italicized "wine" into the control*/ 1464 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1465 1466 /*Select text from the first "wine" string*/ 1467 cr.cpMin = 1; 1468 cr.cpMax = 3; 1469 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1470 1471 /*Retrieve its formatting*/ 1472 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 1473 1474 /*Select text from the second "wine" string*/ 1475 cr.cpMin = 6; 1476 cr.cpMax = 7; 1477 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1478 1479 /*Retrieve its formatting*/ 1480 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test); 1481 1482 /*Test that the two formattings are not the same*/ 1483 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects), 1484 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1485 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1486 1487 DestroyWindow(hwndRichEdit); 1488 } 1489 1490 static void test_SETPARAFORMAT(void) 1491 { 1492 HWND hwndRichEdit = new_richedit(NULL); 1493 PARAFORMAT2 fmt; 1494 HRESULT ret; 1495 LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER; 1496 fmt.cbSize = sizeof(PARAFORMAT2); 1497 fmt.dwMask = PFM_ALIGNMENT; 1498 fmt.wAlignment = PFA_LEFT; 1499 1500 ret = SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt); 1501 ok(ret != 0, "expected non-zero got %d\n", ret); 1502 1503 fmt.cbSize = sizeof(PARAFORMAT2); 1504 fmt.dwMask = -1; 1505 ret = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 1506 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes 1507 * between richedit different native builds of riched20.dll 1508 * used on different Windows versions. */ 1509 ret &= ~PFM_TABLEROWDELIMITER; 1510 fmt.dwMask &= ~PFM_TABLEROWDELIMITER; 1511 1512 ok(ret == expectedMask, "expected %x got %x\n", expectedMask, ret); 1513 ok(fmt.dwMask == expectedMask, "expected %x got %x\n", expectedMask, fmt.dwMask); 1514 1515 /* Test some other paraformat field defaults */ 1516 ok( fmt.wNumbering == 0, "got %d\n", fmt.wNumbering ); 1517 ok( fmt.wNumberingStart == 0, "got %d\n", fmt.wNumberingStart ); 1518 ok( fmt.wNumberingStyle == 0, "got %04x\n", fmt.wNumberingStyle ); 1519 ok( fmt.wNumberingTab == 0, "got %d\n", fmt.wNumberingTab ); 1520 1521 DestroyWindow(hwndRichEdit); 1522 } 1523 1524 static void test_TM_PLAINTEXT(void) 1525 { 1526 /*Tests plain text properties*/ 1527 1528 HWND hwndRichEdit = new_richedit(NULL); 1529 CHARFORMAT2A cf2, cf2test; 1530 CHARRANGE cr; 1531 int rc = 0; 1532 1533 /*Switch to plain text mode*/ 1534 1535 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1536 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0); 1537 1538 /*Fill control with text*/ 1539 1540 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Is Wine an emulator? No it's not"); 1541 1542 /*Select some text and bold it*/ 1543 1544 cr.cpMin = 10; 1545 cr.cpMax = 20; 1546 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1547 cf2.cbSize = sizeof(CHARFORMAT2A); 1548 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 1549 1550 cf2.dwMask = CFM_BOLD | cf2.dwMask; 1551 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects; 1552 1553 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1554 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 1555 1556 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_WORD | SCF_SELECTION, (LPARAM)&cf2); 1557 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 1558 1559 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 1560 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1561 1562 /*Get the formatting of those characters*/ 1563 1564 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1565 1566 /*Get the formatting of some other characters*/ 1567 cf2test.cbSize = sizeof(CHARFORMAT2A); 1568 cr.cpMin = 21; 1569 cr.cpMax = 30; 1570 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1571 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test); 1572 1573 /*Test that they are the same as plain text allows only one formatting*/ 1574 1575 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1576 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1577 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1578 1579 /*Fill the control with a "wine" string, which when inserted will be bold*/ 1580 1581 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1582 1583 /*Copy the bolded "wine" string*/ 1584 1585 cr.cpMin = 0; 1586 cr.cpMax = 4; 1587 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1588 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 1589 1590 /*Swap back to rich text*/ 1591 1592 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1593 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_RICHTEXT, 0); 1594 1595 /*Set the default formatting to bold italics*/ 1596 1597 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 1598 cf2.dwMask |= CFM_ITALIC; 1599 cf2.dwEffects ^= CFE_ITALIC; 1600 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 1601 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1602 1603 /*Set the text in the control to "wine", which will be bold and italicized*/ 1604 1605 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1606 1607 /*Paste the plain text "wine" string, which should take the insert 1608 formatting, which at the moment is bold italics*/ 1609 1610 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1611 1612 /*Select the first "wine" string and retrieve its formatting*/ 1613 1614 cr.cpMin = 1; 1615 cr.cpMax = 3; 1616 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1617 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1618 1619 /*Select the second "wine" string and retrieve its formatting*/ 1620 1621 cr.cpMin = 5; 1622 cr.cpMax = 7; 1623 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1624 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test); 1625 1626 /*Compare the two formattings. They should be the same.*/ 1627 1628 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1629 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1630 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1631 DestroyWindow(hwndRichEdit); 1632 } 1633 1634 static void test_WM_GETTEXT(void) 1635 { 1636 HWND hwndRichEdit = new_richedit(NULL); 1637 static const char text[] = "Hello. My name is RichEdit!"; 1638 static const char text2[] = "Hello. My name is RichEdit!\r"; 1639 static const char text2_after[] = "Hello. My name is RichEdit!\r\n"; 1640 char buffer[1024] = {0}; 1641 int result; 1642 1643 /* Baseline test with normal-sized buffer */ 1644 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1645 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1646 ok(result == lstrlenA(buffer), 1647 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer)); 1648 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1649 result = strcmp(buffer,text); 1650 ok(result == 0, 1651 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1652 1653 /* Test for returned value of WM_GETTEXTLENGTH */ 1654 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 1655 ok(result == lstrlenA(text), 1656 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", 1657 result, lstrlenA(text)); 1658 1659 /* Test for behavior in overflow case */ 1660 memset(buffer, 0, 1024); 1661 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer); 1662 ok(result == 0 || 1663 result == lstrlenA(text) - 1, /* XP, win2k3 */ 1664 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1); 1665 result = strcmp(buffer,text); 1666 if (result) 1667 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */ 1668 ok(result == 0, 1669 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1670 1671 /* Baseline test with normal-sized buffer and carriage return */ 1672 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1673 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1674 ok(result == lstrlenA(buffer), 1675 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer)); 1676 result = strcmp(buffer,text2_after); 1677 ok(result == 0, 1678 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1679 1680 /* Test for returned value of WM_GETTEXTLENGTH */ 1681 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 1682 ok(result == lstrlenA(text2_after), 1683 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", 1684 result, lstrlenA(text2_after)); 1685 1686 /* Test for behavior of CRLF conversion in case of overflow */ 1687 memset(buffer, 0, 1024); 1688 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer); 1689 ok(result == 0 || 1690 result == lstrlenA(text2) - 1, /* XP, win2k3 */ 1691 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1); 1692 result = strcmp(buffer,text2); 1693 if (result) 1694 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */ 1695 ok(result == 0, 1696 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1697 1698 DestroyWindow(hwndRichEdit); 1699 } 1700 1701 static void test_EM_GETTEXTRANGE(void) 1702 { 1703 HWND hwndRichEdit = new_richedit(NULL); 1704 const char * text1 = "foo bar\r\nfoo bar"; 1705 const char * text2 = "foo bar\rfoo bar"; 1706 const char * expect = "bar\rfoo"; 1707 char buffer[1024] = {0}; 1708 LRESULT result; 1709 TEXTRANGEA textRange; 1710 1711 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 1712 1713 textRange.lpstrText = buffer; 1714 textRange.chrg.cpMin = 4; 1715 textRange.chrg.cpMax = 11; 1716 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1717 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); 1718 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1719 1720 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1721 1722 textRange.lpstrText = buffer; 1723 textRange.chrg.cpMin = 4; 1724 textRange.chrg.cpMax = 11; 1725 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1726 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); 1727 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1728 1729 /* cpMax of text length is used instead of -1 in this case */ 1730 textRange.lpstrText = buffer; 1731 textRange.chrg.cpMin = 0; 1732 textRange.chrg.cpMax = -1; 1733 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1734 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); 1735 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1736 1737 /* cpMin < 0 causes no text to be copied, and 0 to be returned */ 1738 textRange.lpstrText = buffer; 1739 textRange.chrg.cpMin = -1; 1740 textRange.chrg.cpMax = 1; 1741 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1742 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1743 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1744 1745 /* cpMax of -1 is not replaced with text length if cpMin != 0 */ 1746 textRange.lpstrText = buffer; 1747 textRange.chrg.cpMin = 1; 1748 textRange.chrg.cpMax = -1; 1749 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1750 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1751 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1752 1753 /* no end character is copied if cpMax - cpMin < 0 */ 1754 textRange.lpstrText = buffer; 1755 textRange.chrg.cpMin = 5; 1756 textRange.chrg.cpMax = 5; 1757 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1758 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1759 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1760 1761 /* cpMax of text length is used if cpMax > text length*/ 1762 textRange.lpstrText = buffer; 1763 textRange.chrg.cpMin = 0; 1764 textRange.chrg.cpMax = 1000; 1765 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1766 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); 1767 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1768 1769 /* Test with multibyte character */ 1770 if (!is_lang_japanese) 1771 skip("Skip multibyte character tests on non-Japanese platform\n"); 1772 else 1773 { 1774 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 1775 textRange.chrg.cpMin = 4; 1776 textRange.chrg.cpMax = 8; 1777 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1778 todo_wine ok(result == 5, "EM_GETTEXTRANGE returned %ld\n", result); 1779 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1780 } 1781 1782 DestroyWindow(hwndRichEdit); 1783 } 1784 1785 static void test_EM_GETSELTEXT(void) 1786 { 1787 HWND hwndRichEdit = new_richedit(NULL); 1788 const char * text1 = "foo bar\r\nfoo bar"; 1789 const char * text2 = "foo bar\rfoo bar"; 1790 const char * expect = "bar\rfoo"; 1791 char buffer[1024] = {0}; 1792 LRESULT result; 1793 1794 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 1795 1796 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11); 1797 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1798 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result); 1799 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer); 1800 1801 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1802 1803 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11); 1804 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1805 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result); 1806 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer); 1807 1808 /* Test with multibyte character */ 1809 if (!is_lang_japanese) 1810 skip("Skip multibyte character tests on non-Japanese platform\n"); 1811 else 1812 { 1813 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 1814 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8); 1815 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1816 todo_wine ok(result == 5, "EM_GETSELTEXT returned %ld\n", result); 1817 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETSELTEXT filled %s\n", buffer); 1818 } 1819 1820 DestroyWindow(hwndRichEdit); 1821 } 1822 1823 /* FIXME: need to test unimplemented options and robustly test wparam */ 1824 static void test_EM_SETOPTIONS(void) 1825 { 1826 HWND hwndRichEdit; 1827 static const char text[] = "Hello. My name is RichEdit!"; 1828 char buffer[1024] = {0}; 1829 DWORD dwStyle, options, oldOptions; 1830 DWORD optionStyles = ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL| 1831 ES_READONLY|ES_WANTRETURN|ES_SAVESEL| 1832 ES_SELECTIONBAR|ES_VERTICAL; 1833 1834 /* Test initial options. */ 1835 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, WS_POPUP, 1836 0, 0, 200, 60, NULL, NULL, 1837 hmoduleRichEdit, NULL); 1838 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", 1839 RICHEDIT_CLASS20A, (int) GetLastError()); 1840 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1841 ok(options == 0, "Incorrect initial options %x\n", options); 1842 DestroyWindow(hwndRichEdit); 1843 1844 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, 1845 WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 1846 0, 0, 200, 60, NULL, NULL, 1847 hmoduleRichEdit, NULL); 1848 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", 1849 RICHEDIT_CLASS20A, (int) GetLastError()); 1850 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1851 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */ 1852 ok(options == (ECO_AUTOVSCROLL|ECO_AUTOHSCROLL), 1853 "Incorrect initial options %x\n", options); 1854 1855 /* NEGATIVE TESTING - NO OPTIONS SET */ 1856 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1857 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0); 1858 1859 /* testing no readonly by sending 'a' to the control*/ 1860 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001); 1861 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1862 ok(buffer[0]=='a', 1863 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer); 1864 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1865 1866 /* READONLY - sending 'a' to the control */ 1867 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1868 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY); 1869 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001); 1870 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1871 ok(buffer[0]==text[0], 1872 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); 1873 1874 /* EM_SETOPTIONS changes the window style, but changing the 1875 * window style does not change the options. */ 1876 dwStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE); 1877 ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n"); 1878 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY); 1879 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1880 ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n"); 1881 /* Confirm that the text is still read only. */ 1882 SendMessageA(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001); 1883 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1884 ok(buffer[0]==text[0], 1885 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); 1886 1887 oldOptions = options; 1888 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles); 1889 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1890 ok(options == oldOptions, 1891 "Options set by SetWindowLong (%x -> %x)\n", oldOptions, options); 1892 1893 DestroyWindow(hwndRichEdit); 1894 } 1895 1896 static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end) 1897 { 1898 CHARFORMAT2A text_format; 1899 text_format.cbSize = sizeof(text_format); 1900 SendMessageA(hwnd, EM_SETSEL, sel_start, sel_end); 1901 SendMessageA(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&text_format); 1902 return (text_format.dwEffects & CFE_LINK) != 0; 1903 } 1904 1905 static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char * url) 1906 { 1907 BOOL link_present = FALSE; 1908 1909 link_present = check_CFE_LINK_selection(hwnd, 0, 1); 1910 if (is_url) 1911 { /* control text is url; should get CFE_LINK */ 1912 ok(link_present, "URL Case: CFE_LINK not set for [%s].\n", url); 1913 } 1914 else 1915 { 1916 ok(!link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url); 1917 } 1918 } 1919 1920 static HWND new_static_wnd(HWND parent) { 1921 return new_window("Static", 0, parent); 1922 } 1923 1924 static void test_EM_AUTOURLDETECT(void) 1925 { 1926 /* DO NOT change the properties of the first two elements. To shorten the 1927 tests, all tests after WM_SETTEXT test just the first two elements - 1928 one non-URL and one URL */ 1929 struct urls_s { 1930 const char *text; 1931 BOOL is_url; 1932 } urls[12] = { 1933 {"winehq.org", FALSE}, 1934 {"http://www.winehq.org", TRUE}, 1935 {"http//winehq.org", FALSE}, 1936 {"ww.winehq.org", FALSE}, 1937 {"www.winehq.org", TRUE}, 1938 {"ftp://192.168.1.1", TRUE}, 1939 {"ftp//192.168.1.1", FALSE}, 1940 {"mailto:your@email.com", TRUE}, 1941 {"prospero:prosperoserver", TRUE}, 1942 {"telnet:test", TRUE}, 1943 {"news:newserver", TRUE}, 1944 {"wais:waisserver", TRUE} 1945 }; 1946 1947 int i, j; 1948 int urlRet=-1; 1949 HWND hwndRichEdit, parent; 1950 1951 /* All of the following should cause the URL to be detected */ 1952 const char * templates_delim[] = { 1953 "This is some text with X on it", 1954 "This is some text with (X) on it", 1955 "This is some text with X\r on it", 1956 "This is some text with ---X--- on it", 1957 "This is some text with \"X\" on it", 1958 "This is some text with 'X' on it", 1959 "This is some text with 'X' on it", 1960 "This is some text with :X: on it", 1961 1962 "This text ends with X", 1963 1964 "This is some text with X) on it", 1965 "This is some text with X--- on it", 1966 "This is some text with X\" on it", 1967 "This is some text with X' on it", 1968 "This is some text with X: on it", 1969 1970 "This is some text with (X on it", 1971 "This is some text with \rX on it", 1972 "This is some text with ---X on it", 1973 "This is some text with \"X on it", 1974 "This is some text with 'X on it", 1975 "This is some text with :X on it", 1976 }; 1977 /* None of these should cause the URL to be detected */ 1978 const char * templates_non_delim[] = { 1979 "This is some text with |X| on it", 1980 "This is some text with *X* on it", 1981 "This is some text with /X/ on it", 1982 "This is some text with +X+ on it", 1983 "This is some text with %X% on it", 1984 "This is some text with #X# on it", 1985 "This is some text with @X@ on it", 1986 "This is some text with \\X\\ on it", 1987 "This is some text with |X on it", 1988 "This is some text with *X on it", 1989 "This is some text with /X on it", 1990 "This is some text with +X on it", 1991 "This is some text with %X on it", 1992 "This is some text with #X on it", 1993 "This is some text with @X on it", 1994 "This is some text with \\X on it", 1995 "This is some text with _X on it", 1996 }; 1997 /* All of these cause the URL detection to be extended by one more byte, 1998 thus demonstrating that the tested character is considered as part 1999 of the URL. */ 2000 const char * templates_xten_delim[] = { 2001 "This is some text with X| on it", 2002 "This is some text with X* on it", 2003 "This is some text with X/ on it", 2004 "This is some text with X+ on it", 2005 "This is some text with X% on it", 2006 "This is some text with X# on it", 2007 "This is some text with X@ on it", 2008 "This is some text with X\\ on it", 2009 "This is some text with X_ on it", 2010 }; 2011 /* These delims act as neutral breaks. Whether the url is ended 2012 or not depends on the next non-neutral character. We'll test 2013 with Y unchanged, in which case the url should include the 2014 deliminator and the Y. We'll also test with the Y changed 2015 to a space, in which case the url stops before the 2016 deliminator. */ 2017 const char * templates_neutral_delim[] = { 2018 "This is some text with X-Y on it", 2019 "This is some text with X--Y on it", 2020 "This is some text with X!Y on it", 2021 "This is some text with X[Y on it", 2022 "This is some text with X]Y on it", 2023 "This is some text with X{Y on it", 2024 "This is some text with X}Y on it", 2025 "This is some text with X(Y on it", 2026 "This is some text with X)Y on it", 2027 "This is some text with X\"Y on it", 2028 "This is some text with X;Y on it", 2029 "This is some text with X:Y on it", 2030 "This is some text with X'Y on it", 2031 "This is some text with X?Y on it", 2032 "This is some text with X<Y on it", 2033 "This is some text with X>Y on it", 2034 "This is some text with X.Y on it", 2035 "This is some text with X,Y on it", 2036 }; 2037 char buffer[1024]; 2038 2039 parent = new_static_wnd(NULL); 2040 hwndRichEdit = new_richedit(parent); 2041 /* Try and pass EM_AUTOURLDETECT some test wParam values */ 2042 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0); 2043 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet); 2044 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 1, 0); 2045 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet); 2046 /* Windows returns -2147024809 (0x80070057) on bad wParam values */ 2047 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 8, 0); 2048 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet); 2049 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h"); 2050 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet); 2051 /* for each url, check the text to see if CFE_LINK effect is present */ 2052 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { 2053 2054 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0); 2055 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text); 2056 check_CFE_LINK_rcvd(hwndRichEdit, FALSE, urls[i].text); 2057 2058 /* Link detection should happen immediately upon WM_SETTEXT */ 2059 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2060 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text); 2061 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text); 2062 } 2063 DestroyWindow(hwndRichEdit); 2064 2065 /* Test detection of URLs within normal text - WM_SETTEXT case. */ 2066 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { 2067 hwndRichEdit = new_richedit(parent); 2068 2069 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2070 char * at_pos; 2071 int at_offset; 2072 int end_offset; 2073 2074 at_pos = strchr(templates_delim[j], 'X'); 2075 at_offset = at_pos - templates_delim[j]; 2076 memcpy(buffer, templates_delim[j], at_offset); 2077 buffer[at_offset] = '\0'; 2078 strcat(buffer, urls[i].text); 2079 strcat(buffer, templates_delim[j] + at_offset + 1); 2080 end_offset = at_offset + strlen(urls[i].text); 2081 2082 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2083 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2084 2085 /* This assumes no templates start with the URL itself, and that they 2086 have at least two characters before the URL text */ 2087 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2088 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2089 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2090 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2091 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2092 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2093 2094 if (urls[i].is_url) 2095 { 2096 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2097 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2098 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2099 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2100 } 2101 else 2102 { 2103 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2104 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2105 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2106 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2107 } 2108 if (buffer[end_offset] != '\0') 2109 { 2110 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2111 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2112 if (buffer[end_offset +1] != '\0') 2113 { 2114 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2115 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2116 } 2117 } 2118 } 2119 2120 for (j = 0; j < sizeof(templates_non_delim) / sizeof(const char *); j++) { 2121 char * at_pos; 2122 int at_offset; 2123 int end_offset; 2124 2125 at_pos = strchr(templates_non_delim[j], 'X'); 2126 at_offset = at_pos - templates_non_delim[j]; 2127 memcpy(buffer, templates_non_delim[j], at_offset); 2128 buffer[at_offset] = '\0'; 2129 strcat(buffer, urls[i].text); 2130 strcat(buffer, templates_non_delim[j] + at_offset + 1); 2131 end_offset = at_offset + strlen(urls[i].text); 2132 2133 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2134 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2135 2136 /* This assumes no templates start with the URL itself, and that they 2137 have at least two characters before the URL text */ 2138 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2139 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2140 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2141 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2142 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2143 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2144 2145 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2146 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2147 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2148 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2149 if (buffer[end_offset] != '\0') 2150 { 2151 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2152 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2153 if (buffer[end_offset +1] != '\0') 2154 { 2155 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2156 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2157 } 2158 } 2159 } 2160 2161 for (j = 0; j < sizeof(templates_xten_delim) / sizeof(const char *); j++) { 2162 char * at_pos; 2163 int at_offset; 2164 int end_offset; 2165 2166 at_pos = strchr(templates_xten_delim[j], 'X'); 2167 at_offset = at_pos - templates_xten_delim[j]; 2168 memcpy(buffer, templates_xten_delim[j], at_offset); 2169 buffer[at_offset] = '\0'; 2170 strcat(buffer, urls[i].text); 2171 strcat(buffer, templates_xten_delim[j] + at_offset + 1); 2172 end_offset = at_offset + strlen(urls[i].text); 2173 2174 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2175 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2176 2177 /* This assumes no templates start with the URL itself, and that they 2178 have at least two characters before the URL text */ 2179 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2180 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2181 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2182 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2183 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2184 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2185 2186 if (urls[i].is_url) 2187 { 2188 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2189 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2190 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2191 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2192 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2193 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2194 } 2195 else 2196 { 2197 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2198 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2199 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2200 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2201 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2202 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2203 } 2204 if (buffer[end_offset +1] != '\0') 2205 { 2206 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2207 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer); 2208 if (buffer[end_offset +2] != '\0') 2209 { 2210 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3), 2211 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer); 2212 } 2213 } 2214 } 2215 2216 for (j = 0; j < sizeof(templates_neutral_delim) / sizeof(const char *); j++) { 2217 char * at_pos, * end_pos; 2218 int at_offset; 2219 int end_offset; 2220 2221 if (!urls[i].is_url) continue; 2222 2223 at_pos = strchr(templates_neutral_delim[j], 'X'); 2224 at_offset = at_pos - templates_neutral_delim[j]; 2225 memcpy(buffer, templates_neutral_delim[j], at_offset); 2226 buffer[at_offset] = '\0'; 2227 strcat(buffer, urls[i].text); 2228 strcat(buffer, templates_neutral_delim[j] + at_offset + 1); 2229 2230 end_pos = strchr(buffer, 'Y'); 2231 end_offset = end_pos - buffer; 2232 2233 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2234 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2235 2236 /* This assumes no templates start with the URL itself, and that they 2237 have at least two characters before the URL text */ 2238 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2239 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2240 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2241 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2242 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2243 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2244 2245 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2246 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2247 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2248 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2249 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2250 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2251 2252 *end_pos = ' '; 2253 2254 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2255 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2256 2257 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2258 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2259 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2260 "CFE_LINK set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2261 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2262 "CFE_LINK set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2263 } 2264 2265 DestroyWindow(hwndRichEdit); 2266 hwndRichEdit = NULL; 2267 } 2268 2269 /* Test detection of URLs within normal text - WM_CHAR case. */ 2270 /* Test only the first two URL examples for brevity */ 2271 for (i = 0; i < 2; i++) { 2272 hwndRichEdit = new_richedit(parent); 2273 2274 /* Also for brevity, test only the first three delimiters */ 2275 for (j = 0; j < 3; j++) { 2276 char * at_pos; 2277 int at_offset; 2278 int end_offset; 2279 int u, v; 2280 2281 at_pos = strchr(templates_delim[j], 'X'); 2282 at_offset = at_pos - templates_delim[j]; 2283 end_offset = at_offset + strlen(urls[i].text); 2284 2285 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2286 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2287 for (u = 0; templates_delim[j][u]; u++) { 2288 if (templates_delim[j][u] == '\r') { 2289 simulate_typing_characters(hwndRichEdit, "\r"); 2290 } else if (templates_delim[j][u] != 'X') { 2291 SendMessageA(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1); 2292 } else { 2293 for (v = 0; urls[i].text[v]; v++) { 2294 SendMessageA(hwndRichEdit, WM_CHAR, urls[i].text[v], 1); 2295 } 2296 } 2297 } 2298 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2299 2300 /* This assumes no templates start with the URL itself, and that they 2301 have at least two characters before the URL text */ 2302 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2303 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2304 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2305 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2306 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2307 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2308 2309 if (urls[i].is_url) 2310 { 2311 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2312 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2313 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2314 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2315 } 2316 else 2317 { 2318 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2319 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2320 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2321 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2322 } 2323 if (buffer[end_offset] != '\0') 2324 { 2325 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2326 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2327 if (buffer[end_offset +1] != '\0') 2328 { 2329 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2330 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2331 } 2332 } 2333 2334 /* The following will insert a paragraph break after the first character 2335 of the URL candidate, thus breaking the URL. It is expected that the 2336 CFE_LINK attribute should break across both pieces of the URL */ 2337 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1); 2338 simulate_typing_characters(hwndRichEdit, "\r"); 2339 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2340 2341 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2342 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2343 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2344 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2345 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2346 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2347 2348 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2349 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2350 /* end_offset moved because of paragraph break */ 2351 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2352 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer); 2353 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer); 2354 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0') 2355 { 2356 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2), 2357 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer); 2358 if (buffer[end_offset +2] != '\0') 2359 { 2360 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3), 2361 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer); 2362 } 2363 } 2364 2365 /* The following will remove the just-inserted paragraph break, thus 2366 restoring the URL */ 2367 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2); 2368 simulate_typing_characters(hwndRichEdit, "\b"); 2369 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2370 2371 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2372 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2373 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2374 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2375 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2376 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2377 2378 if (urls[i].is_url) 2379 { 2380 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2381 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2382 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2383 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2384 } 2385 else 2386 { 2387 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2388 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2389 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2390 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2391 } 2392 if (buffer[end_offset] != '\0') 2393 { 2394 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2395 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2396 if (buffer[end_offset +1] != '\0') 2397 { 2398 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2399 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2400 } 2401 } 2402 } 2403 DestroyWindow(hwndRichEdit); 2404 hwndRichEdit = NULL; 2405 } 2406 2407 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */ 2408 /* Test just the first two URL examples for brevity */ 2409 for (i = 0; i < 2; i++) { 2410 SETTEXTEX st; 2411 2412 hwndRichEdit = new_richedit(parent); 2413 2414 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to 2415 be detected: 2416 1) Set entire text, a la WM_SETTEXT 2417 2) Set a selection of the text to the URL 2418 3) Set a portion of the text at a time, which eventually results in 2419 an URL 2420 All of them should give equivalent results 2421 */ 2422 2423 /* Set entire text in one go, like WM_SETTEXT */ 2424 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2425 char * at_pos; 2426 int at_offset; 2427 int end_offset; 2428 2429 st.codepage = CP_ACP; 2430 st.flags = ST_DEFAULT; 2431 2432 at_pos = strchr(templates_delim[j], 'X'); 2433 at_offset = at_pos - templates_delim[j]; 2434 memcpy(buffer, templates_delim[j], at_offset); 2435 buffer[at_offset] = '\0'; 2436 strcat(buffer, urls[i].text); 2437 strcat(buffer, templates_delim[j] + at_offset + 1); 2438 end_offset = at_offset + strlen(urls[i].text); 2439 2440 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2441 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer); 2442 2443 /* This assumes no templates start with the URL itself, and that they 2444 have at least two characters before the URL text */ 2445 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2446 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2447 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2448 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2449 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2450 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2451 2452 if (urls[i].is_url) 2453 { 2454 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2455 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2456 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2457 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2458 } 2459 else 2460 { 2461 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2462 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2463 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2464 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2465 } 2466 if (buffer[end_offset] != '\0') 2467 { 2468 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2469 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2470 if (buffer[end_offset +1] != '\0') 2471 { 2472 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2473 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2474 } 2475 } 2476 } 2477 2478 /* Set selection with X to the URL */ 2479 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2480 char * at_pos; 2481 int at_offset; 2482 int end_offset; 2483 2484 at_pos = strchr(templates_delim[j], 'X'); 2485 at_offset = at_pos - templates_delim[j]; 2486 end_offset = at_offset + strlen(urls[i].text); 2487 2488 st.codepage = CP_ACP; 2489 st.flags = ST_DEFAULT; 2490 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2491 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]); 2492 st.flags = ST_SELECTION; 2493 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2494 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)urls[i].text); 2495 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2496 2497 /* This assumes no templates start with the URL itself, and that they 2498 have at least two characters before the URL text */ 2499 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2500 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2501 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2502 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2503 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2504 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2505 2506 if (urls[i].is_url) 2507 { 2508 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2509 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2510 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2511 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2512 } 2513 else 2514 { 2515 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2516 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2517 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2518 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2519 } 2520 if (buffer[end_offset] != '\0') 2521 { 2522 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2523 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2524 if (buffer[end_offset +1] != '\0') 2525 { 2526 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2527 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2528 } 2529 } 2530 } 2531 2532 /* Set selection with X to the first character of the URL, then the rest */ 2533 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2534 char * at_pos; 2535 int at_offset; 2536 int end_offset; 2537 2538 at_pos = strchr(templates_delim[j], 'X'); 2539 at_offset = at_pos - templates_delim[j]; 2540 end_offset = at_offset + strlen(urls[i].text); 2541 2542 strcpy(buffer, "YY"); 2543 buffer[0] = urls[i].text[0]; 2544 2545 st.codepage = CP_ACP; 2546 st.flags = ST_DEFAULT; 2547 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2548 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]); 2549 st.flags = ST_SELECTION; 2550 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2551 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer); 2552 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2); 2553 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1)); 2554 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2555 2556 /* This assumes no templates start with the URL itself, and that they 2557 have at least two characters before the URL text */ 2558 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2559 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2560 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2561 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2562 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2563 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2564 2565 if (urls[i].is_url) 2566 { 2567 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2568 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2569 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2570 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2571 } 2572 else 2573 { 2574 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2575 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2576 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2577 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2578 } 2579 if (buffer[end_offset] != '\0') 2580 { 2581 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2582 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2583 if (buffer[end_offset +1] != '\0') 2584 { 2585 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2586 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2587 } 2588 } 2589 } 2590 2591 DestroyWindow(hwndRichEdit); 2592 hwndRichEdit = NULL; 2593 } 2594 2595 /* Test detection of URLs within normal text - EM_REPLACESEL case. */ 2596 /* Test just the first two URL examples for brevity */ 2597 for (i = 0; i < 2; i++) { 2598 hwndRichEdit = new_richedit(parent); 2599 2600 /* Set selection with X to the URL */ 2601 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2602 char * at_pos; 2603 int at_offset; 2604 int end_offset; 2605 2606 at_pos = strchr(templates_delim[j], 'X'); 2607 at_offset = at_pos - templates_delim[j]; 2608 end_offset = at_offset + strlen(urls[i].text); 2609 2610 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2611 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]); 2612 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2613 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urls[i].text); 2614 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2615 2616 /* This assumes no templates start with the URL itself, and that they 2617 have at least two characters before the URL text */ 2618 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2619 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2620 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2621 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2622 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2623 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2624 2625 if (urls[i].is_url) 2626 { 2627 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2628 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2629 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2630 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2631 } 2632 else 2633 { 2634 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2635 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2636 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2637 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2638 } 2639 if (buffer[end_offset] != '\0') 2640 { 2641 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2642 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2643 if (buffer[end_offset +1] != '\0') 2644 { 2645 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2646 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2647 } 2648 } 2649 } 2650 2651 /* Set selection with X to the first character of the URL, then the rest */ 2652 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2653 char * at_pos; 2654 int at_offset; 2655 int end_offset; 2656 2657 at_pos = strchr(templates_delim[j], 'X'); 2658 at_offset = at_pos - templates_delim[j]; 2659 end_offset = at_offset + strlen(urls[i].text); 2660 2661 strcpy(buffer, "YY"); 2662 buffer[0] = urls[i].text[0]; 2663 2664 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2665 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]); 2666 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2667 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)buffer); 2668 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2); 2669 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1)); 2670 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2671 2672 /* This assumes no templates start with the URL itself, and that they 2673 have at least two characters before the URL text */ 2674 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2675 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2676 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2677 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2678 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2679 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2680 2681 if (urls[i].is_url) 2682 { 2683 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2684 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2685 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2686 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2687 } 2688 else 2689 { 2690 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2691 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2692 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2693 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2694 } 2695 if (buffer[end_offset] != '\0') 2696 { 2697 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2698 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2699 if (buffer[end_offset +1] != '\0') 2700 { 2701 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2702 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2703 } 2704 } 2705 } 2706 2707 DestroyWindow(hwndRichEdit); 2708 hwndRichEdit = NULL; 2709 } 2710 2711 DestroyWindow(parent); 2712 } 2713 2714 static void test_EM_SCROLL(void) 2715 { 2716 int i, j; 2717 int r; /* return value */ 2718 int expr; /* expected return value */ 2719 HWND hwndRichEdit = new_richedit(NULL); 2720 int y_before, y_after; /* units of lines of text */ 2721 2722 /* test a richedit box containing a single line of text */ 2723 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");/* one line of text */ 2724 expr = 0x00010000; 2725 for (i = 0; i < 4; i++) { 2726 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP }; 2727 2728 r = SendMessageA(hwndRichEdit, EM_SCROLL, cmd[i], 0); 2729 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2730 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). " 2731 "Got 0x%08x, expected 0x%08x\n", i, r, expr); 2732 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 " 2733 "(i == %d)\n", y_after, i); 2734 } 2735 2736 /* 2737 * test a richedit box that will scroll. There are two general 2738 * cases: the case without any long lines and the case with a long 2739 * line. 2740 */ 2741 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */ 2742 if (i == 0) 2743 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\nb\nc\nd\ne"); 2744 else 2745 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) 2746 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " 2747 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " 2748 "LONG LINE \nb\nc\nd\ne"); 2749 for (j = 0; j < 12; j++) /* reset scroll position to top */ 2750 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); 2751 2752 /* get first visible line */ 2753 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2754 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */ 2755 2756 /* get new current first visible line */ 2757 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2758 2759 ok(((r & 0xffffff00) == 0x00010000) && 2760 ((r & 0x000000ff) != 0x00000000), 2761 "EM_SCROLL page down didn't scroll by a small positive number of " 2762 "lines (r == 0x%08x)\n", r); 2763 ok(y_after > y_before, "EM_SCROLL page down not functioning " 2764 "(line %d scrolled to line %d\n", y_before, y_after); 2765 2766 y_before = y_after; 2767 2768 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */ 2769 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2770 ok(((r & 0xffffff00) == 0x0001ff00), 2771 "EM_SCROLL page up didn't scroll by a small negative number of lines " 2772 "(r == 0x%08x)\n", r); 2773 ok(y_after < y_before, "EM_SCROLL page up not functioning (line " 2774 "%d scrolled to line %d\n", y_before, y_after); 2775 2776 y_before = y_after; 2777 2778 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */ 2779 2780 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2781 2782 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line " 2783 "(r == 0x%08x)\n", r); 2784 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by " 2785 "1 line (%d scrolled to %d)\n", y_before, y_after); 2786 2787 y_before = y_after; 2788 2789 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */ 2790 2791 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2792 2793 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line " 2794 "(r == 0x%08x)\n", r); 2795 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 " 2796 "line (%d scrolled to %d)\n", y_before, y_after); 2797 2798 y_before = y_after; 2799 2800 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2801 SB_LINEUP, 0); /* lineup beyond top */ 2802 2803 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2804 2805 ok(r == 0x00010000, 2806 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r); 2807 ok(y_before == y_after, 2808 "EM_SCROLL line up beyond top worked (%d)\n", y_after); 2809 2810 y_before = y_after; 2811 2812 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2813 SB_PAGEUP, 0);/*page up beyond top */ 2814 2815 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2816 2817 ok(r == 0x00010000, 2818 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r); 2819 ok(y_before == y_after, 2820 "EM_SCROLL page up beyond top worked (%d)\n", y_after); 2821 2822 for (j = 0; j < 12; j++) /* page down all the way to the bottom */ 2823 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); 2824 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2825 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2826 SB_PAGEDOWN, 0); /* page down beyond bot */ 2827 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2828 2829 ok(r == 0x00010000, 2830 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r); 2831 ok(y_before == y_after, 2832 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n", 2833 y_before, y_after); 2834 2835 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2836 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down beyond bot */ 2837 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2838 2839 ok(r == 0x00010000, 2840 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r); 2841 ok(y_before == y_after, 2842 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n", 2843 y_before, y_after); 2844 } 2845 DestroyWindow(hwndRichEdit); 2846 } 2847 2848 static unsigned int recursionLevel = 0; 2849 static unsigned int WM_SIZE_recursionLevel = 0; 2850 static BOOL bailedOutOfRecursion = FALSE; 2851 static LRESULT (WINAPI *richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 2852 2853 static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 2854 { 2855 LRESULT r; 2856 2857 if (bailedOutOfRecursion) return 0; 2858 if (recursionLevel >= 32) { 2859 bailedOutOfRecursion = TRUE; 2860 return 0; 2861 } 2862 2863 recursionLevel++; 2864 switch (message) { 2865 case WM_SIZE: 2866 WM_SIZE_recursionLevel++; 2867 r = richeditProc(hwnd, message, wParam, lParam); 2868 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */ 2869 ShowScrollBar(hwnd, SB_VERT, TRUE); 2870 WM_SIZE_recursionLevel--; 2871 break; 2872 default: 2873 r = richeditProc(hwnd, message, wParam, lParam); 2874 break; 2875 } 2876 recursionLevel--; 2877 return r; 2878 } 2879 2880 static void test_scrollbar_visibility(void) 2881 { 2882 HWND hwndRichEdit; 2883 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"; 2884 SCROLLINFO si; 2885 WNDCLASSA cls; 2886 BOOL r; 2887 2888 /* These tests show that richedit should temporarily refrain from automatically 2889 hiding or showing its scrollbars (vertical at least) when an explicit request 2890 is made via ShowScrollBar() or similar, outside of standard richedit logic. 2891 Some applications depend on forced showing (when otherwise richedit would 2892 hide the vertical scrollbar) and are thrown on an endless recursive loop 2893 if richedit auto-hides the scrollbar again. Apparently they never heard of 2894 the ES_DISABLENOSCROLL style... */ 2895 2896 hwndRichEdit = new_richedit(NULL); 2897 2898 /* Test default scrollbar visibility behavior */ 2899 memset(&si, 0, sizeof(si)); 2900 si.cbSize = sizeof(si); 2901 si.fMask = SIF_PAGE | SIF_RANGE; 2902 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2903 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2904 "Vertical scrollbar is visible, should be invisible.\n"); 2905 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 2906 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 2907 si.nPage, si.nMin, si.nMax); 2908 2909 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2910 memset(&si, 0, sizeof(si)); 2911 si.cbSize = sizeof(si); 2912 si.fMask = SIF_PAGE | SIF_RANGE; 2913 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2914 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2915 "Vertical scrollbar is visible, should be invisible.\n"); 2916 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 2917 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 2918 si.nPage, si.nMin, si.nMax); 2919 2920 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 2921 memset(&si, 0, sizeof(si)); 2922 si.cbSize = sizeof(si); 2923 si.fMask = SIF_PAGE | SIF_RANGE; 2924 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2925 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 2926 "Vertical scrollbar is invisible, should be visible.\n"); 2927 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2928 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2929 si.nPage, si.nMin, si.nMax); 2930 2931 /* Oddly, setting text to NULL does *not* reset the scrollbar range, 2932 even though it hides the scrollbar */ 2933 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2934 memset(&si, 0, sizeof(si)); 2935 si.cbSize = sizeof(si); 2936 si.fMask = SIF_PAGE | SIF_RANGE; 2937 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2938 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2939 "Vertical scrollbar is visible, should be invisible.\n"); 2940 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2941 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2942 si.nPage, si.nMin, si.nMax); 2943 2944 /* Setting non-scrolling text again does *not* reset scrollbar range */ 2945 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 2946 memset(&si, 0, sizeof(si)); 2947 si.cbSize = sizeof(si); 2948 si.fMask = SIF_PAGE | SIF_RANGE; 2949 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2950 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2951 "Vertical scrollbar is visible, should be invisible.\n"); 2952 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2953 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2954 si.nPage, si.nMin, si.nMax); 2955 2956 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2957 memset(&si, 0, sizeof(si)); 2958 si.cbSize = sizeof(si); 2959 si.fMask = SIF_PAGE | SIF_RANGE; 2960 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2961 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2962 "Vertical scrollbar is visible, should be invisible.\n"); 2963 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2964 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2965 si.nPage, si.nMin, si.nMax); 2966 2967 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 2968 memset(&si, 0, sizeof(si)); 2969 si.cbSize = sizeof(si); 2970 si.fMask = SIF_PAGE | SIF_RANGE; 2971 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2972 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2973 "Vertical scrollbar is visible, should be invisible.\n"); 2974 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2975 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2976 si.nPage, si.nMin, si.nMax); 2977 2978 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 2979 memset(&si, 0, sizeof(si)); 2980 si.cbSize = sizeof(si); 2981 si.fMask = SIF_PAGE | SIF_RANGE; 2982 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2983 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2984 "Vertical scrollbar is visible, should be invisible.\n"); 2985 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2986 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2987 si.nPage, si.nMin, si.nMax); 2988 2989 DestroyWindow(hwndRichEdit); 2990 2991 /* Test again, with ES_DISABLENOSCROLL style */ 2992 hwndRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_DISABLENOSCROLL, NULL); 2993 2994 /* Test default scrollbar visibility behavior */ 2995 memset(&si, 0, sizeof(si)); 2996 si.cbSize = sizeof(si); 2997 si.fMask = SIF_PAGE | SIF_RANGE; 2998 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2999 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3000 "Vertical scrollbar is invisible, should be visible.\n"); 3001 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, 3002 "reported page/range is %d (%d..%d) expected 0 (0..1)\n", 3003 si.nPage, si.nMin, si.nMax); 3004 3005 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3006 memset(&si, 0, sizeof(si)); 3007 si.cbSize = sizeof(si); 3008 si.fMask = SIF_PAGE | SIF_RANGE; 3009 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3010 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3011 "Vertical scrollbar is invisible, should be visible.\n"); 3012 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, 3013 "reported page/range is %d (%d..%d) expected 0 (0..1)\n", 3014 si.nPage, si.nMin, si.nMax); 3015 3016 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3017 memset(&si, 0, sizeof(si)); 3018 si.cbSize = sizeof(si); 3019 si.fMask = SIF_PAGE | SIF_RANGE; 3020 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3021 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3022 "Vertical scrollbar is invisible, should be visible.\n"); 3023 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3024 "reported page/range is %d (%d..%d)\n", 3025 si.nPage, si.nMin, si.nMax); 3026 3027 /* Oddly, setting text to NULL does *not* reset the scrollbar range */ 3028 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3029 memset(&si, 0, sizeof(si)); 3030 si.cbSize = sizeof(si); 3031 si.fMask = SIF_PAGE | SIF_RANGE; 3032 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3033 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3034 "Vertical scrollbar is invisible, should be visible.\n"); 3035 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3036 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3037 si.nPage, si.nMin, si.nMax); 3038 3039 /* Setting non-scrolling text again does *not* reset scrollbar range */ 3040 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3041 memset(&si, 0, sizeof(si)); 3042 si.cbSize = sizeof(si); 3043 si.fMask = SIF_PAGE | SIF_RANGE; 3044 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3045 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3046 "Vertical scrollbar is invisible, should be visible.\n"); 3047 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3048 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3049 si.nPage, si.nMin, si.nMax); 3050 3051 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3052 memset(&si, 0, sizeof(si)); 3053 si.cbSize = sizeof(si); 3054 si.fMask = SIF_PAGE | SIF_RANGE; 3055 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3056 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3057 "Vertical scrollbar is invisible, should be visible.\n"); 3058 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3059 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3060 si.nPage, si.nMin, si.nMax); 3061 3062 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3063 memset(&si, 0, sizeof(si)); 3064 si.cbSize = sizeof(si); 3065 si.fMask = SIF_PAGE | SIF_RANGE; 3066 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3067 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3068 "Vertical scrollbar is invisible, should be visible.\n"); 3069 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3070 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3071 si.nPage, si.nMin, si.nMax); 3072 3073 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 3074 memset(&si, 0, sizeof(si)); 3075 si.cbSize = sizeof(si); 3076 si.fMask = SIF_PAGE | SIF_RANGE; 3077 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3078 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3079 "Vertical scrollbar is invisible, should be visible.\n"); 3080 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3081 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3082 si.nPage, si.nMin, si.nMax); 3083 3084 DestroyWindow(hwndRichEdit); 3085 3086 /* Test behavior with explicit visibility request, using ShowScrollBar() */ 3087 hwndRichEdit = new_richedit(NULL); 3088 3089 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ 3090 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE); 3091 memset(&si, 0, sizeof(si)); 3092 si.cbSize = sizeof(si); 3093 si.fMask = SIF_PAGE | SIF_RANGE; 3094 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3095 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3096 "Vertical scrollbar is invisible, should be visible.\n"); 3097 todo_wine { 3098 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3099 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3100 si.nPage, si.nMin, si.nMax); 3101 } 3102 3103 /* Ditto, see above */ 3104 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3105 memset(&si, 0, sizeof(si)); 3106 si.cbSize = sizeof(si); 3107 si.fMask = SIF_PAGE | SIF_RANGE; 3108 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3109 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3110 "Vertical scrollbar is invisible, should be visible.\n"); 3111 todo_wine { 3112 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3113 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3114 si.nPage, si.nMin, si.nMax); 3115 } 3116 3117 /* Ditto, see above */ 3118 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3119 memset(&si, 0, sizeof(si)); 3120 si.cbSize = sizeof(si); 3121 si.fMask = SIF_PAGE | SIF_RANGE; 3122 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3123 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3124 "Vertical scrollbar is invisible, should be visible.\n"); 3125 todo_wine { 3126 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3127 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3128 si.nPage, si.nMin, si.nMax); 3129 } 3130 3131 /* Ditto, see above */ 3132 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); 3133 memset(&si, 0, sizeof(si)); 3134 si.cbSize = sizeof(si); 3135 si.fMask = SIF_PAGE | SIF_RANGE; 3136 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3137 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3138 "Vertical scrollbar is invisible, should be visible.\n"); 3139 todo_wine { 3140 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3141 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3142 si.nPage, si.nMin, si.nMax); 3143 } 3144 3145 /* Ditto, see above */ 3146 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3147 memset(&si, 0, sizeof(si)); 3148 si.cbSize = sizeof(si); 3149 si.fMask = SIF_PAGE | SIF_RANGE; 3150 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3151 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3152 "Vertical scrollbar is invisible, should be visible.\n"); 3153 todo_wine { 3154 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3155 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3156 si.nPage, si.nMin, si.nMax); 3157 } 3158 3159 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3160 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3161 memset(&si, 0, sizeof(si)); 3162 si.cbSize = sizeof(si); 3163 si.fMask = SIF_PAGE | SIF_RANGE; 3164 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3165 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3166 "Vertical scrollbar is visible, should be invisible.\n"); 3167 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3168 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3169 si.nPage, si.nMin, si.nMax); 3170 3171 DestroyWindow(hwndRichEdit); 3172 3173 hwndRichEdit = new_richedit(NULL); 3174 3175 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3176 memset(&si, 0, sizeof(si)); 3177 si.cbSize = sizeof(si); 3178 si.fMask = SIF_PAGE | SIF_RANGE; 3179 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3180 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3181 "Vertical scrollbar is visible, should be invisible.\n"); 3182 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3183 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3184 si.nPage, si.nMin, si.nMax); 3185 3186 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3187 memset(&si, 0, sizeof(si)); 3188 si.cbSize = sizeof(si); 3189 si.fMask = SIF_PAGE | SIF_RANGE; 3190 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3191 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3192 "Vertical scrollbar is visible, should be invisible.\n"); 3193 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3194 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3195 si.nPage, si.nMin, si.nMax); 3196 3197 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3198 memset(&si, 0, sizeof(si)); 3199 si.cbSize = sizeof(si); 3200 si.fMask = SIF_PAGE | SIF_RANGE; 3201 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3202 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3203 "Vertical scrollbar is visible, should be invisible.\n"); 3204 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3205 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3206 si.nPage, si.nMin, si.nMax); 3207 3208 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3209 memset(&si, 0, sizeof(si)); 3210 si.cbSize = sizeof(si); 3211 si.fMask = SIF_PAGE | SIF_RANGE; 3212 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3213 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3214 "Vertical scrollbar is visible, should be invisible.\n"); 3215 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3216 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3217 si.nPage, si.nMin, si.nMax); 3218 3219 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3220 memset(&si, 0, sizeof(si)); 3221 si.cbSize = sizeof(si); 3222 si.fMask = SIF_PAGE | SIF_RANGE; 3223 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3224 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3225 "Vertical scrollbar is invisible, should be visible.\n"); 3226 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3227 "reported page/range is %d (%d..%d)\n", 3228 si.nPage, si.nMin, si.nMax); 3229 3230 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ 3231 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3232 memset(&si, 0, sizeof(si)); 3233 si.cbSize = sizeof(si); 3234 si.fMask = SIF_PAGE | SIF_RANGE; 3235 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3236 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3237 "Vertical scrollbar is visible, should be invisible.\n"); 3238 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3239 "reported page/range is %d (%d..%d)\n", 3240 si.nPage, si.nMin, si.nMax); 3241 3242 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3243 memset(&si, 0, sizeof(si)); 3244 si.cbSize = sizeof(si); 3245 si.fMask = SIF_PAGE | SIF_RANGE; 3246 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3247 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3248 "Vertical scrollbar is visible, should be invisible.\n"); 3249 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3250 "reported page/range is %d (%d..%d)\n", 3251 si.nPage, si.nMin, si.nMax); 3252 3253 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 3254 EM_SCROLL will make visible any forcefully invisible scrollbar */ 3255 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); 3256 memset(&si, 0, sizeof(si)); 3257 si.cbSize = sizeof(si); 3258 si.fMask = SIF_PAGE | SIF_RANGE; 3259 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3260 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3261 "Vertical scrollbar is invisible, should be visible.\n"); 3262 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3263 "reported page/range is %d (%d..%d)\n", 3264 si.nPage, si.nMin, si.nMax); 3265 3266 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3267 memset(&si, 0, sizeof(si)); 3268 si.cbSize = sizeof(si); 3269 si.fMask = SIF_PAGE | SIF_RANGE; 3270 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3271 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3272 "Vertical scrollbar is visible, should be invisible.\n"); 3273 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3274 "reported page/range is %d (%d..%d)\n", 3275 si.nPage, si.nMin, si.nMax); 3276 3277 /* Again, EM_SCROLL, with SB_LINEUP */ 3278 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); 3279 memset(&si, 0, sizeof(si)); 3280 si.cbSize = sizeof(si); 3281 si.fMask = SIF_PAGE | SIF_RANGE; 3282 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3283 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3284 "Vertical scrollbar is invisible, should be visible.\n"); 3285 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3286 "reported page/range is %d (%d..%d)\n", 3287 si.nPage, si.nMin, si.nMax); 3288 3289 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3290 memset(&si, 0, sizeof(si)); 3291 si.cbSize = sizeof(si); 3292 si.fMask = SIF_PAGE | SIF_RANGE; 3293 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3294 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3295 "Vertical scrollbar is visible, should be invisible.\n"); 3296 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3297 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3298 si.nPage, si.nMin, si.nMax); 3299 3300 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3301 memset(&si, 0, sizeof(si)); 3302 si.cbSize = sizeof(si); 3303 si.fMask = SIF_PAGE | SIF_RANGE; 3304 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3305 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3306 "Vertical scrollbar is invisible, should be visible.\n"); 3307 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3308 "reported page/range is %d (%d..%d)\n", 3309 si.nPage, si.nMin, si.nMax); 3310 3311 DestroyWindow(hwndRichEdit); 3312 3313 3314 /* Test behavior with explicit visibility request, using SetWindowLongA()() */ 3315 hwndRichEdit = new_richedit(NULL); 3316 3317 #define ENABLE_WS_VSCROLL(hwnd) \ 3318 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL) 3319 #define DISABLE_WS_VSCROLL(hwnd) \ 3320 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL) 3321 3322 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ 3323 ENABLE_WS_VSCROLL(hwndRichEdit); 3324 memset(&si, 0, sizeof(si)); 3325 si.cbSize = sizeof(si); 3326 si.fMask = SIF_PAGE | SIF_RANGE; 3327 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3328 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3329 "Vertical scrollbar is invisible, should be visible.\n"); 3330 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3331 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3332 si.nPage, si.nMin, si.nMax); 3333 3334 /* Ditto, see above */ 3335 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3336 memset(&si, 0, sizeof(si)); 3337 si.cbSize = sizeof(si); 3338 si.fMask = SIF_PAGE | SIF_RANGE; 3339 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3340 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3341 "Vertical scrollbar is invisible, should be visible.\n"); 3342 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3343 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3344 si.nPage, si.nMin, si.nMax); 3345 3346 /* Ditto, see above */ 3347 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3348 memset(&si, 0, sizeof(si)); 3349 si.cbSize = sizeof(si); 3350 si.fMask = SIF_PAGE | SIF_RANGE; 3351 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3352 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3353 "Vertical scrollbar is invisible, should be visible.\n"); 3354 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3355 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3356 si.nPage, si.nMin, si.nMax); 3357 3358 /* Ditto, see above */ 3359 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); 3360 memset(&si, 0, sizeof(si)); 3361 si.cbSize = sizeof(si); 3362 si.fMask = SIF_PAGE | SIF_RANGE; 3363 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3364 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3365 "Vertical scrollbar is invisible, should be visible.\n"); 3366 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3367 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3368 si.nPage, si.nMin, si.nMax); 3369 3370 /* Ditto, see above */ 3371 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3372 memset(&si, 0, sizeof(si)); 3373 si.cbSize = sizeof(si); 3374 si.fMask = SIF_PAGE | SIF_RANGE; 3375 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3376 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3377 "Vertical scrollbar is invisible, should be visible.\n"); 3378 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3379 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3380 si.nPage, si.nMin, si.nMax); 3381 3382 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3383 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3384 memset(&si, 0, sizeof(si)); 3385 si.cbSize = sizeof(si); 3386 si.fMask = SIF_PAGE | SIF_RANGE; 3387 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3388 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3389 "Vertical scrollbar is visible, should be invisible.\n"); 3390 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3391 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3392 si.nPage, si.nMin, si.nMax); 3393 3394 DestroyWindow(hwndRichEdit); 3395 3396 hwndRichEdit = new_richedit(NULL); 3397 3398 DISABLE_WS_VSCROLL(hwndRichEdit); 3399 memset(&si, 0, sizeof(si)); 3400 si.cbSize = sizeof(si); 3401 si.fMask = SIF_PAGE | SIF_RANGE; 3402 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3403 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3404 "Vertical scrollbar is visible, should be invisible.\n"); 3405 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3406 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3407 si.nPage, si.nMin, si.nMax); 3408 3409 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3410 memset(&si, 0, sizeof(si)); 3411 si.cbSize = sizeof(si); 3412 si.fMask = SIF_PAGE | SIF_RANGE; 3413 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3414 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3415 "Vertical scrollbar is visible, should be invisible.\n"); 3416 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3417 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3418 si.nPage, si.nMin, si.nMax); 3419 3420 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3421 memset(&si, 0, sizeof(si)); 3422 si.cbSize = sizeof(si); 3423 si.fMask = SIF_PAGE | SIF_RANGE; 3424 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3425 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3426 "Vertical scrollbar is visible, should be invisible.\n"); 3427 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3428 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3429 si.nPage, si.nMin, si.nMax); 3430 3431 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3432 memset(&si, 0, sizeof(si)); 3433 si.cbSize = sizeof(si); 3434 si.fMask = SIF_PAGE | SIF_RANGE; 3435 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3436 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3437 "Vertical scrollbar is visible, should be invisible.\n"); 3438 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3439 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3440 si.nPage, si.nMin, si.nMax); 3441 3442 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3443 memset(&si, 0, sizeof(si)); 3444 si.cbSize = sizeof(si); 3445 si.fMask = SIF_PAGE | SIF_RANGE; 3446 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3447 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3448 "Vertical scrollbar is invisible, should be visible.\n"); 3449 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3450 "reported page/range is %d (%d..%d)\n", 3451 si.nPage, si.nMin, si.nMax); 3452 3453 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ 3454 DISABLE_WS_VSCROLL(hwndRichEdit); 3455 memset(&si, 0, sizeof(si)); 3456 si.cbSize = sizeof(si); 3457 si.fMask = SIF_PAGE | SIF_RANGE; 3458 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3459 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3460 "Vertical scrollbar is visible, should be invisible.\n"); 3461 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3462 "reported page/range is %d (%d..%d)\n", 3463 si.nPage, si.nMin, si.nMax); 3464 3465 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3466 memset(&si, 0, sizeof(si)); 3467 si.cbSize = sizeof(si); 3468 si.fMask = SIF_PAGE | SIF_RANGE; 3469 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3470 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3471 "Vertical scrollbar is visible, should be invisible.\n"); 3472 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3473 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3474 si.nPage, si.nMin, si.nMax); 3475 3476 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3477 memset(&si, 0, sizeof(si)); 3478 si.cbSize = sizeof(si); 3479 si.fMask = SIF_PAGE | SIF_RANGE; 3480 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3481 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3482 "Vertical scrollbar is invisible, should be visible.\n"); 3483 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3484 "reported page/range is %d (%d..%d)\n", 3485 si.nPage, si.nMin, si.nMax); 3486 3487 DISABLE_WS_VSCROLL(hwndRichEdit); 3488 memset(&si, 0, sizeof(si)); 3489 si.cbSize = sizeof(si); 3490 si.fMask = SIF_PAGE | SIF_RANGE; 3491 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3492 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3493 "Vertical scrollbar is visible, should be invisible.\n"); 3494 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3495 "reported page/range is %d (%d..%d)\n", 3496 si.nPage, si.nMin, si.nMax); 3497 3498 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 3499 EM_SCROLL will make visible any forcefully invisible scrollbar */ 3500 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); 3501 memset(&si, 0, sizeof(si)); 3502 si.cbSize = sizeof(si); 3503 si.fMask = SIF_PAGE | SIF_RANGE; 3504 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3505 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3506 "Vertical scrollbar is invisible, should be visible.\n"); 3507 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3508 "reported page/range is %d (%d..%d)\n", 3509 si.nPage, si.nMin, si.nMax); 3510 3511 DISABLE_WS_VSCROLL(hwndRichEdit); 3512 memset(&si, 0, sizeof(si)); 3513 si.cbSize = sizeof(si); 3514 si.fMask = SIF_PAGE | SIF_RANGE; 3515 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3516 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3517 "Vertical scrollbar is visible, should be invisible.\n"); 3518 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3519 "reported page/range is %d (%d..%d)\n", 3520 si.nPage, si.nMin, si.nMax); 3521 3522 /* Again, EM_SCROLL, with SB_LINEUP */ 3523 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); 3524 memset(&si, 0, sizeof(si)); 3525 si.cbSize = sizeof(si); 3526 si.fMask = SIF_PAGE | SIF_RANGE; 3527 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3528 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3529 "Vertical scrollbar is invisible, should be visible.\n"); 3530 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3531 "reported page/range is %d (%d..%d)\n", 3532 si.nPage, si.nMin, si.nMax); 3533 3534 DestroyWindow(hwndRichEdit); 3535 3536 /* This window proc models what is going on with Corman Lisp 3.0. 3537 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to 3538 force the scrollbar into visibility. Recursion should NOT happen 3539 as a result of this action. 3540 */ 3541 r = GetClassInfoA(NULL, RICHEDIT_CLASS20A, &cls); 3542 if (r) { 3543 richeditProc = cls.lpfnWndProc; 3544 cls.lpfnWndProc = RicheditStupidOverrideProcA; 3545 cls.lpszClassName = "RicheditStupidOverride"; 3546 if(!RegisterClassA(&cls)) assert(0); 3547 3548 recursionLevel = 0; 3549 WM_SIZE_recursionLevel = 0; 3550 bailedOutOfRecursion = FALSE; 3551 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL); 3552 ok(!bailedOutOfRecursion, 3553 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); 3554 3555 recursionLevel = 0; 3556 WM_SIZE_recursionLevel = 0; 3557 bailedOutOfRecursion = FALSE; 3558 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE); 3559 ok(!bailedOutOfRecursion, 3560 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); 3561 3562 /* Unblock window in order to process WM_DESTROY */ 3563 recursionLevel = 0; 3564 bailedOutOfRecursion = FALSE; 3565 WM_SIZE_recursionLevel = 0; 3566 DestroyWindow(hwndRichEdit); 3567 } 3568 } 3569 3570 static void test_EM_SETUNDOLIMIT(void) 3571 { 3572 /* cases we test for: 3573 * default behaviour - limiting at 100 undo's 3574 * undo disabled - setting a limit of 0 3575 * undo limited - undo limit set to some to some number, like 2 3576 * bad input - sending a negative number should default to 100 undo's */ 3577 3578 HWND hwndRichEdit = new_richedit(NULL); 3579 CHARRANGE cr; 3580 int i; 3581 int result; 3582 3583 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x"); 3584 cr.cpMin = 0; 3585 cr.cpMax = -1; 3586 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 3587 3588 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 3589 /*Load "x" into the clipboard. Paste is an easy, undo'able operation. 3590 also, multiple pastes don't combine like WM_CHAR would */ 3591 3592 /* first case - check the default */ 3593 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 3594 for (i=0; i<101; i++) /* Put 101 undo's on the stack */ 3595 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3596 for (i=0; i<100; i++) /* Undo 100 of them */ 3597 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 3598 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3599 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n"); 3600 3601 /* second case - cannot undo */ 3602 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 3603 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0); 3604 SendMessageA(hwndRichEdit, 3605 WM_PASTE, 0, 0); /* Try to put something in the undo stack */ 3606 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3607 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n"); 3608 3609 /* third case - set it to an arbitrary number */ 3610 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 3611 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0); 3612 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3613 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3614 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3615 /* If SETUNDOLIMIT is working, there should only be two undo's after this */ 3616 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0,0), 3617 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n"); 3618 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 3619 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3620 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n"); 3621 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 3622 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3623 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n"); 3624 3625 /* fourth case - setting negative numbers should default to 100 undos */ 3626 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 3627 result = SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0); 3628 ok (result == 100, 3629 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result); 3630 3631 DestroyWindow(hwndRichEdit); 3632 } 3633 3634 static void test_ES_PASSWORD(void) 3635 { 3636 /* This isn't hugely testable, so we're just going to run it through its paces */ 3637 3638 HWND hwndRichEdit = new_richedit(NULL); 3639 WCHAR result; 3640 3641 /* First, check the default of a regular control */ 3642 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3643 ok (result == 0, 3644 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result); 3645 3646 /* Now, set it to something normal */ 3647 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0); 3648 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3649 ok (result == 120, 3650 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); 3651 3652 /* Now, set it to something odd */ 3653 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0); 3654 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3655 ok (result == 1234, 3656 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); 3657 DestroyWindow(hwndRichEdit); 3658 } 3659 3660 LONG streamout_written = 0; 3661 3662 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, 3663 LPBYTE pbBuff, 3664 LONG cb, 3665 LONG *pcb) 3666 { 3667 char** str = (char**)dwCookie; 3668 *pcb = cb; 3669 if (*pcb > 0) { 3670 memcpy(*str, pbBuff, *pcb); 3671 *str += *pcb; 3672 } 3673 streamout_written = *pcb; 3674 return 0; 3675 } 3676 3677 static void test_WM_SETTEXT(void) 3678 { 3679 HWND hwndRichEdit = new_richedit(NULL); 3680 const char * TestItem1 = "TestSomeText"; 3681 const char * TestItem2 = "TestSomeText\r"; 3682 const char * TestItem2_after = "TestSomeText\r\n"; 3683 const char * TestItem3 = "TestSomeText\rSomeMoreText\r"; 3684 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n"; 3685 const char * TestItem4 = "TestSomeText\n\nTestSomeText"; 3686 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText"; 3687 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText"; 3688 const char * TestItem5_after = "TestSomeText TestSomeText"; 3689 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText"; 3690 const char * TestItem6_after = "TestSomeText \r\nTestSomeText"; 3691 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText"; 3692 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText"; 3693 3694 const char rtftextA[] = "{\\rtf sometext}"; 3695 const char urtftextA[] = "{\\urtf sometext}"; 3696 const WCHAR rtftextW[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0}; 3697 const WCHAR urtftextW[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0}; 3698 const WCHAR sometextW[] = {'s','o','m','e','t','e','x','t',0}; 3699 3700 char buf[1024] = {0}; 3701 WCHAR bufW[1024] = {0}; 3702 LRESULT result; 3703 3704 /* This test attempts to show that WM_SETTEXT on a riched20 control causes 3705 any solitary \r to be converted to \r\n on return. Properly paired 3706 \r\n are not affected. It also shows that the special sequence \r\r\n 3707 gets converted to a single space. 3708 */ 3709 3710 #define TEST_SETTEXT(a, b) \ 3711 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \ 3712 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ 3713 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \ 3714 ok (result == lstrlenA(buf), \ 3715 "WM_GETTEXT returned %ld instead of expected %u\n", \ 3716 result, lstrlenA(buf)); \ 3717 result = strcmp(b, buf); \ 3718 ok(result == 0, \ 3719 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf); 3720 3721 TEST_SETTEXT(TestItem1, TestItem1) 3722 TEST_SETTEXT(TestItem2, TestItem2_after) 3723 TEST_SETTEXT(TestItem3, TestItem3_after) 3724 TEST_SETTEXT(TestItem3_after, TestItem3_after) 3725 TEST_SETTEXT(TestItem4, TestItem4_after) 3726 TEST_SETTEXT(TestItem5, TestItem5_after) 3727 TEST_SETTEXT(TestItem6, TestItem6_after) 3728 TEST_SETTEXT(TestItem7, TestItem7_after) 3729 3730 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */ 3731 TEST_SETTEXT(rtftextA, "sometext") /* interpreted as ascii rtf */ 3732 TEST_SETTEXT(urtftextA, "sometext") /* interpreted as ascii rtf */ 3733 TEST_SETTEXT(rtftextW, "{") /* interpreted as ascii text */ 3734 TEST_SETTEXT(urtftextW, "{") /* interpreted as ascii text */ 3735 DestroyWindow(hwndRichEdit); 3736 #undef TEST_SETTEXT 3737 3738 #define TEST_SETTEXTW(a, b) \ 3739 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \ 3740 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ 3741 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \ 3742 ok (result == lstrlenW(bufW), \ 3743 "WM_GETTEXT returned %ld instead of expected %u\n", \ 3744 result, lstrlenW(bufW)); \ 3745 result = lstrcmpW(b, bufW); \ 3746 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result); 3747 3748 hwndRichEdit = CreateWindowW(RICHEDIT_CLASS20W, NULL, 3749 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 3750 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 3751 ok(hwndRichEdit != NULL, "class: RichEdit20W, error: %d\n", (int) GetLastError()); 3752 TEST_SETTEXTW(rtftextA, sometextW) /* interpreted as ascii rtf */ 3753 TEST_SETTEXTW(urtftextA, sometextW) /* interpreted as ascii rtf */ 3754 TEST_SETTEXTW(rtftextW, rtftextW) /* interpreted as ascii text */ 3755 TEST_SETTEXTW(urtftextW, urtftextW) /* interpreted as ascii text */ 3756 DestroyWindow(hwndRichEdit); 3757 #undef TEST_SETTEXTW 3758 3759 /* Single-line richedit */ 3760 hwndRichEdit = new_richedit_with_style(NULL, 0); 3761 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"line1\r\nline2"); 3762 ok(result == 1, "WM_SETTEXT returned %ld, expected 12\n", result); 3763 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 3764 ok(result == 5, "WM_GETTEXT returned %ld, expected 5\n", result); 3765 ok(!strcmp(buf, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buf); 3766 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}"); 3767 ok(result == 1, "WM_SETTEXT returned %ld, expected 1\n", result); 3768 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 3769 ok(result == 3, "WM_GETTEXT returned %ld, expected 3\n", result); 3770 ok(!strcmp(buf, "ABC"), "WM_GETTEXT returned incorrect string '%s'\n", buf); 3771 DestroyWindow(hwndRichEdit); 3772 } 3773 3774 /* Set *pcb to one to show that the remaining cb-1 bytes are not 3775 resent to the callkack. */ 3776 static DWORD CALLBACK test_esCallback_written_1(DWORD_PTR dwCookie, 3777 LPBYTE pbBuff, 3778 LONG cb, 3779 LONG *pcb) 3780 { 3781 char** str = (char**)dwCookie; 3782 ok(*pcb == cb || *pcb == 0, "cb %d, *pcb %d\n", cb, *pcb); 3783 *pcb = 0; 3784 if (cb > 0) { 3785 memcpy(*str, pbBuff, cb); 3786 *str += cb; 3787 *pcb = 1; 3788 } 3789 return 0; 3790 } 3791 3792 static int count_pars(const char *buf) 3793 { 3794 const char *p = buf; 3795 int count = 0; 3796 while ((p = strstr( p, "\\par" )) != NULL) 3797 { 3798 if (!isalpha( p[4] )) 3799 count++; 3800 p++; 3801 } 3802 return count; 3803 } 3804 3805 static void test_EM_STREAMOUT(void) 3806 { 3807 HWND hwndRichEdit = new_richedit(NULL); 3808 int r; 3809 EDITSTREAM es; 3810 char buf[1024] = {0}; 3811 char * p; 3812 LRESULT result; 3813 3814 const char * TestItem1 = "TestSomeText"; 3815 const char * TestItem2 = "TestSomeText\r"; 3816 const char * TestItem3 = "TestSomeText\r\n"; 3817 3818 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1); 3819 p = buf; 3820 es.dwCookie = (DWORD_PTR)&p; 3821 es.dwError = 0; 3822 es.pfnCallback = test_WM_SETTEXT_esCallback; 3823 memset(buf, 0, sizeof(buf)); 3824 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3825 r = strlen(buf); 3826 ok(r == 12, "streamed text length is %d, expecting 12\n", r); 3827 ok(strcmp(buf, TestItem1) == 0, 3828 "streamed text different, got %s\n", buf); 3829 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3830 3831 /* RTF mode writes the final end of para \r if it's part of the selection */ 3832 p = buf; 3833 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3834 ok (count_pars(buf) == 1, "got %s\n", buf); 3835 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3836 p = buf; 3837 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 12); 3838 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3839 ok (count_pars(buf) == 0, "got %s\n", buf); 3840 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3841 p = buf; 3842 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 3843 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3844 ok (count_pars(buf) == 1, "got %s\n", buf); 3845 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3846 3847 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2); 3848 p = buf; 3849 es.dwCookie = (DWORD_PTR)&p; 3850 es.dwError = 0; 3851 es.pfnCallback = test_WM_SETTEXT_esCallback; 3852 memset(buf, 0, sizeof(buf)); 3853 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3854 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3855 r = strlen(buf); 3856 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */ 3857 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3858 ok(strcmp(buf, TestItem3) == 0, 3859 "streamed text different from, got %s\n", buf); 3860 3861 /* And again RTF mode writes the final end of para \r if it's part of the selection */ 3862 p = buf; 3863 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3864 ok (count_pars(buf) == 2, "got %s\n", buf); 3865 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3866 p = buf; 3867 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 13); 3868 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3869 ok (count_pars(buf) == 1, "got %s\n", buf); 3870 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3871 p = buf; 3872 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 3873 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3874 ok (count_pars(buf) == 2, "got %s\n", buf); 3875 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3876 3877 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3); 3878 p = buf; 3879 es.dwCookie = (DWORD_PTR)&p; 3880 es.dwError = 0; 3881 es.pfnCallback = test_WM_SETTEXT_esCallback; 3882 memset(buf, 0, sizeof(buf)); 3883 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3884 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3885 r = strlen(buf); 3886 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3887 ok(strcmp(buf, TestItem3) == 0, 3888 "streamed text different, got %s\n", buf); 3889 3890 /* Use a callback that sets *pcb to one */ 3891 p = buf; 3892 es.dwCookie = (DWORD_PTR)&p; 3893 es.dwError = 0; 3894 es.pfnCallback = test_esCallback_written_1; 3895 memset(buf, 0, sizeof(buf)); 3896 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3897 r = strlen(buf); 3898 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3899 ok(strcmp(buf, TestItem3) == 0, 3900 "streamed text different, got %s\n", buf); 3901 ok(result == 0, "got %ld expected 0\n", result); 3902 3903 3904 DestroyWindow(hwndRichEdit); 3905 } 3906 3907 static void test_EM_STREAMOUT_FONTTBL(void) 3908 { 3909 HWND hwndRichEdit = new_richedit(NULL); 3910 EDITSTREAM es; 3911 char buf[1024] = {0}; 3912 char * p; 3913 char * fontTbl; 3914 int brackCount; 3915 3916 const char * TestItem = "TestSomeText"; 3917 3918 /* fills in the richedit control with some text */ 3919 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem); 3920 3921 /* streams out the text in rtf format */ 3922 p = buf; 3923 es.dwCookie = (DWORD_PTR)&p; 3924 es.dwError = 0; 3925 es.pfnCallback = test_WM_SETTEXT_esCallback; 3926 memset(buf, 0, sizeof(buf)); 3927 SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3928 3929 /* scans for \fonttbl, error if not found */ 3930 fontTbl = strstr(buf, "\\fonttbl"); 3931 ok(fontTbl != NULL, "missing \\fonttbl section\n"); 3932 if(fontTbl) 3933 { 3934 /* scans for terminating closing bracket */ 3935 brackCount = 1; 3936 while(*fontTbl && brackCount) 3937 { 3938 if(*fontTbl == '{') 3939 brackCount++; 3940 else if(*fontTbl == '}') 3941 brackCount--; 3942 fontTbl++; 3943 } 3944 /* checks whether closing bracket is ok */ 3945 ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n"); 3946 if(!brackCount) 3947 { 3948 /* char before closing fonttbl block should be a closed bracket */ 3949 fontTbl -= 2; 3950 ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl); 3951 3952 /* char after fonttbl block should be a crlf */ 3953 fontTbl += 2; 3954 ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n"); 3955 } 3956 } 3957 DestroyWindow(hwndRichEdit); 3958 } 3959 3960 static void test_EM_STREAMOUT_empty_para(void) 3961 { 3962 HWND hwnd = new_richedit(NULL); 3963 char buf[1024], *p = buf; 3964 EDITSTREAM es; 3965 3966 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 3967 3968 memset(buf, 0, sizeof(buf)); 3969 es.dwCookie = (DWORD_PTR)&p; 3970 es.dwError = 0; 3971 es.pfnCallback = test_WM_SETTEXT_esCallback; 3972 3973 SendMessageA(hwnd, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3974 ok((p = strstr(buf, "\\pard")) != NULL, "missing \\pard\n"); 3975 ok(((p = strstr(p, "\\fs")) && isdigit(p[3])), "missing \\fs\n"); 3976 3977 DestroyWindow(hwnd); 3978 } 3979 3980 static void test_EM_SETTEXTEX(void) 3981 { 3982 HWND hwndRichEdit, parent; 3983 SCROLLINFO si; 3984 int sel_start, sel_end; 3985 SETTEXTEX setText; 3986 GETTEXTEX getText; 3987 WCHAR TestItem1[] = {'T', 'e', 's', 't', 3988 'S', 'o', 'm', 'e', 3989 'T', 'e', 'x', 't', 0}; 3990 WCHAR TestItem1alt[] = {'T', 'T', 'e', 's', 3991 't', 'S', 'o', 'm', 3992 'e', 'T', 'e', 'x', 3993 't', 't', 'S', 'o', 3994 'm', 'e', 'T', 'e', 3995 'x', 't', 0}; 3996 WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t', 3997 '\r','t','S','o','m','e','T','e','x','t',0}; 3998 WCHAR TestItem2[] = {'T', 'e', 's', 't', 3999 'S', 'o', 'm', 'e', 4000 'T', 'e', 'x', 't', 4001 '\r', 0}; 4002 const char * TestItem2_after = "TestSomeText\r\n"; 4003 WCHAR TestItem3[] = {'T', 'e', 's', 't', 4004 'S', 'o', 'm', 'e', 4005 'T', 'e', 'x', 't', 4006 '\r','\n','\r','\n', 0}; 4007 WCHAR TestItem3alt[] = {'T', 'e', 's', 't', 4008 'S', 'o', 'm', 'e', 4009 'T', 'e', 'x', 't', 4010 '\n','\n', 0}; 4011 WCHAR TestItem3_after[] = {'T', 'e', 's', 't', 4012 'S', 'o', 'm', 'e', 4013 'T', 'e', 'x', 't', 4014 '\r','\r', 0}; 4015 WCHAR TestItem4[] = {'T', 'e', 's', 't', 4016 'S', 'o', 'm', 'e', 4017 'T', 'e', 'x', 't', 4018 '\r','\r','\n','\r', 4019 '\n', 0}; 4020 WCHAR TestItem4_after[] = {'T', 'e', 's', 't', 4021 'S', 'o', 'm', 'e', 4022 'T', 'e', 'x', 't', 4023 ' ','\r', 0}; 4024 #define MAX_BUF_LEN 1024 4025 WCHAR buf[MAX_BUF_LEN]; 4026 char bufACP[MAX_BUF_LEN]; 4027 char * p; 4028 int result; 4029 CHARRANGE cr; 4030 EDITSTREAM es; 4031 WNDCLASSA cls; 4032 4033 /* Test the scroll position with and without a parent window. 4034 * 4035 * For some reason the scroll position is 0 after EM_SETTEXTEX 4036 * with the ST_SELECTION flag only when the control has a parent 4037 * window, even though the selection is at the end. */ 4038 cls.style = 0; 4039 cls.lpfnWndProc = DefWindowProcA; 4040 cls.cbClsExtra = 0; 4041 cls.cbWndExtra = 0; 4042 cls.hInstance = GetModuleHandleA(0); 4043 cls.hIcon = 0; 4044 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 4045 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 4046 cls.lpszMenuName = NULL; 4047 cls.lpszClassName = "ParentTestClass"; 4048 if(!RegisterClassA(&cls)) assert(0); 4049 4050 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 4051 0, 0, 200, 60, NULL, NULL, NULL, NULL); 4052 ok (parent != 0, "Failed to create parent window\n"); 4053 4054 hwndRichEdit = CreateWindowExA(0, 4055 RICHEDIT_CLASS20A, NULL, 4056 ES_MULTILINE|WS_VSCROLL|WS_VISIBLE|WS_CHILD, 4057 0, 0, 200, 60, parent, NULL, 4058 hmoduleRichEdit, NULL); 4059 4060 setText.codepage = CP_ACP; 4061 setText.flags = ST_SELECTION; 4062 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4063 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4064 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result); 4065 si.cbSize = sizeof(si); 4066 si.fMask = SIF_ALL; 4067 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4068 todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); 4069 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4070 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); 4071 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); 4072 4073 DestroyWindow(parent); 4074 4075 /* Test without a parent window */ 4076 hwndRichEdit = new_richedit(NULL); 4077 setText.codepage = CP_ACP; 4078 setText.flags = ST_SELECTION; 4079 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4080 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4081 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result); 4082 si.cbSize = sizeof(si); 4083 si.fMask = SIF_ALL; 4084 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4085 ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos); 4086 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4087 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); 4088 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); 4089 4090 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT, 4091 * but this time it is because the selection is at the beginning. */ 4092 setText.codepage = CP_ACP; 4093 setText.flags = ST_DEFAULT; 4094 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4095 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4096 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4097 si.cbSize = sizeof(si); 4098 si.fMask = SIF_ALL; 4099 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4100 ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); 4101 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4102 ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start); 4103 ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end); 4104 4105 setText.codepage = 1200; /* no constant for unicode */ 4106 getText.codepage = 1200; /* no constant for unicode */ 4107 getText.cb = MAX_BUF_LEN; 4108 getText.flags = GT_DEFAULT; 4109 getText.lpDefaultChar = NULL; 4110 getText.lpUsedDefChar = NULL; 4111 4112 setText.flags = 0; 4113 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4114 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4115 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4116 ok(lstrcmpW(buf, TestItem1) == 0, 4117 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4118 4119 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not 4120 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf 4121 */ 4122 setText.codepage = 1200; /* no constant for unicode */ 4123 getText.codepage = 1200; /* no constant for unicode */ 4124 getText.cb = MAX_BUF_LEN; 4125 getText.flags = GT_DEFAULT; 4126 getText.lpDefaultChar = NULL; 4127 getText.lpUsedDefChar = NULL; 4128 setText.flags = 0; 4129 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem2); 4130 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4131 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4132 ok(lstrcmpW(buf, TestItem2) == 0, 4133 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4134 4135 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */ 4136 SendMessageA(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf); 4137 ok(strcmp((const char *)buf, TestItem2_after) == 0, 4138 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n"); 4139 4140 /* Baseline test for just-enough buffer space for string */ 4141 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); 4142 getText.codepage = 1200; /* no constant for unicode */ 4143 getText.flags = GT_DEFAULT; 4144 getText.lpDefaultChar = NULL; 4145 getText.lpUsedDefChar = NULL; 4146 memset(buf, 0, sizeof(buf)); 4147 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4148 ok(lstrcmpW(buf, TestItem2) == 0, 4149 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4150 4151 /* When there is enough space for one character, but not both, of the CRLF 4152 pair at the end of the string, the CR is not copied at all. That is, 4153 the caller must not see CRLF pairs truncated to CR at the end of the 4154 string. 4155 */ 4156 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); 4157 getText.codepage = 1200; /* no constant for unicode */ 4158 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */ 4159 getText.lpDefaultChar = NULL; 4160 getText.lpUsedDefChar = NULL; 4161 memset(buf, 0, sizeof(buf)); 4162 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4163 ok(lstrcmpW(buf, TestItem1) == 0, 4164 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4165 4166 4167 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */ 4168 setText.codepage = 1200; /* no constant for unicode */ 4169 getText.codepage = 1200; /* no constant for unicode */ 4170 getText.cb = MAX_BUF_LEN; 4171 getText.flags = GT_DEFAULT; 4172 getText.lpDefaultChar = NULL; 4173 getText.lpUsedDefChar = NULL; 4174 setText.flags = 0; 4175 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3); 4176 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4177 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4178 ok(lstrcmpW(buf, TestItem3_after) == 0, 4179 "EM_SETTEXTEX did not convert properly\n"); 4180 4181 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */ 4182 setText.codepage = 1200; /* no constant for unicode */ 4183 getText.codepage = 1200; /* no constant for unicode */ 4184 getText.cb = MAX_BUF_LEN; 4185 getText.flags = GT_DEFAULT; 4186 getText.lpDefaultChar = NULL; 4187 getText.lpUsedDefChar = NULL; 4188 setText.flags = 0; 4189 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3alt); 4190 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4191 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4192 ok(lstrcmpW(buf, TestItem3_after) == 0, 4193 "EM_SETTEXTEX did not convert properly\n"); 4194 4195 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */ 4196 setText.codepage = 1200; /* no constant for unicode */ 4197 getText.codepage = 1200; /* no constant for unicode */ 4198 getText.cb = MAX_BUF_LEN; 4199 getText.flags = GT_DEFAULT; 4200 getText.lpDefaultChar = NULL; 4201 getText.lpUsedDefChar = NULL; 4202 setText.flags = 0; 4203 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem4); 4204 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4205 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4206 ok(lstrcmpW(buf, TestItem4_after) == 0, 4207 "EM_SETTEXTEX did not convert properly\n"); 4208 4209 /* !ST_SELECTION && Unicode && !\rtf */ 4210 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); 4211 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4212 4213 ok (result == 1, 4214 "EM_SETTEXTEX returned %d, instead of 1\n",result); 4215 ok(!buf[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n"); 4216 4217 /* put some text back: !ST_SELECTION && Unicode && !\rtf */ 4218 setText.flags = 0; 4219 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4220 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4221 /* select some text */ 4222 cr.cpMax = 1; 4223 cr.cpMin = 3; 4224 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4225 /* replace current selection: ST_SELECTION && Unicode && !\rtf */ 4226 setText.flags = ST_SELECTION; 4227 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); 4228 ok(result == 0, 4229 "EM_SETTEXTEX with NULL lParam to replace selection" 4230 " with no text should return 0. Got %i\n", 4231 result); 4232 4233 /* put some text back: !ST_SELECTION && Unicode && !\rtf */ 4234 setText.flags = 0; 4235 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4236 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4237 /* select some text */ 4238 cr.cpMax = 1; 4239 cr.cpMin = 3; 4240 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4241 /* replace current selection: ST_SELECTION && Unicode && !\rtf */ 4242 setText.flags = ST_SELECTION; 4243 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4244 /* get text */ 4245 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4246 ok(result == lstrlenW(TestItem1), 4247 "EM_SETTEXTEX with NULL lParam to replace selection" 4248 " with no text should return 0. Got %i\n", 4249 result); 4250 ok(lstrlenW(buf) == 22, 4251 "EM_SETTEXTEX to replace selection with more text failed: %i.\n", 4252 lstrlenW(buf) ); 4253 4254 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */ 4255 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */ 4256 p = (char *)buf; 4257 es.dwCookie = (DWORD_PTR)&p; 4258 es.dwError = 0; 4259 es.pfnCallback = test_WM_SETTEXT_esCallback; 4260 memset(buf, 0, sizeof(buf)); 4261 SendMessageA(hwndRichEdit, EM_STREAMOUT, 4262 (WPARAM)(SF_RTF), (LPARAM)&es); 4263 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf); 4264 4265 /* !ST_SELECTION && !Unicode && \rtf */ 4266 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ 4267 getText.codepage = 1200; /* no constant for unicode */ 4268 getText.cb = MAX_BUF_LEN; 4269 getText.flags = GT_DEFAULT; 4270 getText.lpDefaultChar = NULL; 4271 getText.lpUsedDefChar = NULL; 4272 4273 setText.flags = 0; 4274 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf); 4275 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4276 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4277 ok(lstrcmpW(buf, TestItem1) == 0, 4278 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4279 4280 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it 4281 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */ 4282 setText.codepage = 1200; /* Lie about code page (actual ASCII) */ 4283 getText.codepage = CP_ACP; 4284 getText.cb = MAX_BUF_LEN; 4285 getText.flags = GT_DEFAULT; 4286 getText.lpDefaultChar = NULL; 4287 getText.lpUsedDefChar = NULL; 4288 4289 setText.flags = ST_SELECTION; 4290 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4291 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf not unicode}"); 4292 todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result); 4293 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4294 ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP); 4295 4296 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */ 4297 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */ 4298 p = (char *)buf; 4299 es.dwCookie = (DWORD_PTR)&p; 4300 es.dwError = 0; 4301 es.pfnCallback = test_WM_SETTEXT_esCallback; 4302 memset(buf, 0, sizeof(buf)); 4303 SendMessageA(hwndRichEdit, EM_STREAMOUT, 4304 (WPARAM)(SF_RTF), (LPARAM)&es); 4305 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf); 4306 4307 /* select some text */ 4308 cr.cpMax = 1; 4309 cr.cpMin = 3; 4310 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4311 4312 /* ST_SELECTION && !Unicode && \rtf */ 4313 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ 4314 getText.codepage = 1200; /* no constant for unicode */ 4315 getText.cb = MAX_BUF_LEN; 4316 getText.flags = GT_DEFAULT; 4317 getText.lpDefaultChar = NULL; 4318 getText.lpUsedDefChar = NULL; 4319 4320 setText.flags = ST_SELECTION; 4321 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf); 4322 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4323 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf); 4324 4325 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */ 4326 setText.codepage = 1200; /* no constant for unicode */ 4327 getText.codepage = CP_ACP; 4328 getText.cb = MAX_BUF_LEN; 4329 4330 setText.flags = 0; 4331 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); /* TestItem1 */ 4332 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4333 4334 /* select some text */ 4335 cr.cpMax = 1; 4336 cr.cpMin = 3; 4337 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4338 4339 /* ST_SELECTION && !Unicode && !\rtf */ 4340 setText.codepage = CP_ACP; 4341 getText.codepage = 1200; /* no constant for unicode */ 4342 getText.cb = MAX_BUF_LEN; 4343 getText.flags = GT_DEFAULT; 4344 getText.lpDefaultChar = NULL; 4345 getText.lpUsedDefChar = NULL; 4346 4347 setText.flags = ST_SELECTION; 4348 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)bufACP); 4349 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4350 ok(lstrcmpW(buf, TestItem1alt) == 0, 4351 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when" 4352 " using ST_SELECTION and non-Unicode\n"); 4353 4354 /* Test setting text using rich text format */ 4355 setText.flags = 0; 4356 setText.codepage = CP_ACP; 4357 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}"); 4358 getText.codepage = CP_ACP; 4359 getText.cb = MAX_BUF_LEN; 4360 getText.flags = GT_DEFAULT; 4361 getText.lpDefaultChar = NULL; 4362 getText.lpUsedDefChar = NULL; 4363 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4364 ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP); 4365 4366 setText.flags = 0; 4367 setText.codepage = CP_ACP; 4368 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}"); 4369 getText.codepage = CP_ACP; 4370 getText.cb = MAX_BUF_LEN; 4371 getText.flags = GT_DEFAULT; 4372 getText.lpDefaultChar = NULL; 4373 getText.lpUsedDefChar = NULL; 4374 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4375 ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP); 4376 4377 /* test for utf8 text with BOM */ 4378 setText.flags = 0; 4379 setText.codepage = CP_ACP; 4380 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM"); 4381 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4382 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result); 4383 result = strcmp(bufACP, "TestUTF8WithBOM"); 4384 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP); 4385 4386 setText.flags = 0; 4387 setText.codepage = CP_UTF8; 4388 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM"); 4389 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4390 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result); 4391 result = strcmp(bufACP, "TestUTF8WithBOM"); 4392 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP); 4393 4394 /* Test multibyte character */ 4395 if (!is_lang_japanese) 4396 skip("Skip multibyte character tests on non-Japanese platform\n"); 4397 else 4398 { 4399 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4400 setText.flags = ST_SELECTION; 4401 setText.codepage = CP_ACP; 4402 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0"); 4403 todo_wine ok(result == 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result); 4404 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4405 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4406 ok(!strcmp(bufACP, "abc\x8e\xf0"), 4407 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4408 4409 setText.flags = ST_DEFAULT; 4410 setText.codepage = CP_ACP; 4411 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0"); 4412 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result); 4413 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4414 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4415 ok(!strcmp(bufACP, "abc\x8e\xf0"), 4416 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4417 4418 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4419 setText.flags = ST_SELECTION; 4420 setText.codepage = CP_ACP; 4421 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf abc\x8e\xf0}"); 4422 todo_wine ok(result == 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result); 4423 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4424 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4425 todo_wine ok(!strcmp(bufACP, "abc\x8e\xf0"), 4426 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4427 } 4428 4429 DestroyWindow(hwndRichEdit); 4430 4431 /* Single-line richedit */ 4432 hwndRichEdit = new_richedit_with_style(NULL, 0); 4433 setText.flags = ST_DEFAULT; 4434 setText.codepage = CP_ACP; 4435 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"line1\r\nline2"); 4436 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result); 4437 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4438 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4439 ok(!strcmp(bufACP, "line1"), "EM_SETTEXTEX: Test single-line text: Result: %s\n", bufACP); 4440 DestroyWindow(hwndRichEdit); 4441 } 4442 4443 static void test_EM_LIMITTEXT(void) 4444 { 4445 int ret; 4446 4447 HWND hwndRichEdit = new_richedit(NULL); 4448 4449 /* The main purpose of this test is to demonstrate that the nonsense in MSDN 4450 * about setting the length to -1 for multiline edit controls doesn't happen. 4451 */ 4452 4453 /* Don't check default gettextlimit case. That's done in other tests */ 4454 4455 /* Set textlimit to 100 */ 4456 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 100, 0); 4457 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4458 ok (ret == 100, 4459 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret); 4460 4461 /* Set textlimit to 0 */ 4462 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 0, 0); 4463 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4464 ok (ret == 65536, 4465 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret); 4466 4467 /* Set textlimit to -1 */ 4468 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -1, 0); 4469 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4470 ok (ret == -1, 4471 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret); 4472 4473 /* Set textlimit to -2 */ 4474 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -2, 0); 4475 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4476 ok (ret == -2, 4477 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret); 4478 4479 DestroyWindow (hwndRichEdit); 4480 } 4481 4482 4483 static void test_EM_EXLIMITTEXT(void) 4484 { 4485 int i, selBegin, selEnd, len1, len2; 4486 int result; 4487 char text[1024 + 1]; 4488 char buffer[1024 + 1]; 4489 int textlimit = 0; /* multiple of 100 */ 4490 HWND hwndRichEdit = new_richedit(NULL); 4491 4492 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4493 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */ 4494 4495 textlimit = 256000; 4496 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4497 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4498 /* set higher */ 4499 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i); 4500 4501 textlimit = 1000; 4502 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4503 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4504 /* set lower */ 4505 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i); 4506 4507 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 0); 4508 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4509 /* default for WParam = 0 */ 4510 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i); 4511 4512 textlimit = sizeof(text)-1; 4513 memset(text, 'W', textlimit); 4514 text[sizeof(text)-1] = 0; 4515 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4516 /* maxed out text */ 4517 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4518 4519 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */ 4520 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4521 len1 = selEnd - selBegin; 4522 4523 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1); 4524 SendMessageA(hwndRichEdit, WM_CHAR, VK_BACK, 1); 4525 SendMessageA(hwndRichEdit, WM_KEYUP, VK_BACK, 1); 4526 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4527 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4528 len2 = selEnd - selBegin; 4529 4530 ok(len1 != len2, 4531 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4532 len1,len2,i); 4533 4534 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1); 4535 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4536 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); 4537 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4538 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4539 len1 = selEnd - selBegin; 4540 4541 ok(len1 != len2, 4542 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4543 len1,len2,i); 4544 4545 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1); 4546 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4547 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */ 4548 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4549 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4550 len2 = selEnd - selBegin; 4551 4552 ok(len1 == len2, 4553 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4554 len1,len2,i); 4555 4556 /* set text up to the limit, select all the text, then add a char */ 4557 textlimit = 5; 4558 memset(text, 'W', textlimit); 4559 text[textlimit] = 0; 4560 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4561 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4562 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4563 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4564 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4565 result = strcmp(buffer, "A"); 4566 ok(0 == result, "got string = \"%s\"\n", buffer); 4567 4568 /* WM_SETTEXT not limited */ 4569 textlimit = 10; 4570 memset(text, 'W', textlimit); 4571 text[textlimit] = 0; 4572 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5); 4573 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4574 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4575 i = strlen(buffer); 4576 ok(10 == i, "expected 10 chars\n"); 4577 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4578 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4579 4580 /* try inserting more text at end */ 4581 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4582 ok(0 == i, "WM_CHAR wasn't processed\n"); 4583 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4584 i = strlen(buffer); 4585 ok(10 == i, "expected 10 chars, got %i\n", i); 4586 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4587 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4588 4589 /* try inserting text at beginning */ 4590 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 4591 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4592 ok(0 == i, "WM_CHAR wasn't processed\n"); 4593 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4594 i = strlen(buffer); 4595 ok(10 == i, "expected 10 chars, got %i\n", i); 4596 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4597 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4598 4599 /* WM_CHAR is limited */ 4600 textlimit = 1; 4601 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4602 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */ 4603 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4604 ok(0 == i, "WM_CHAR wasn't processed\n"); 4605 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4606 ok(0 == i, "WM_CHAR wasn't processed\n"); 4607 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4608 i = strlen(buffer); 4609 ok(1 == i, "expected 1 chars, got %i instead\n", i); 4610 4611 DestroyWindow(hwndRichEdit); 4612 } 4613 4614 static void test_EM_GETLIMITTEXT(void) 4615 { 4616 int i; 4617 HWND hwndRichEdit = new_richedit(NULL); 4618 4619 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4620 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */ 4621 4622 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000); 4623 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4624 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i); 4625 4626 DestroyWindow(hwndRichEdit); 4627 } 4628 4629 static void test_WM_SETFONT(void) 4630 { 4631 /* There is no invalid input or error conditions for this function. 4632 * NULL wParam and lParam just fall back to their default values 4633 * It should be noted that even if you use a gibberish name for your fonts 4634 * here, it will still work because the name is stored. They will display as 4635 * System, but will report their name to be whatever they were created as */ 4636 4637 HWND hwndRichEdit = new_richedit(NULL); 4638 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4639 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4640 FF_DONTCARE, "Marlett"); 4641 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4642 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4643 FF_DONTCARE, "MS Sans Serif"); 4644 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4645 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4646 FF_DONTCARE, "Courier"); 4647 LOGFONTA sentLogFont; 4648 CHARFORMAT2A returnedCF2A; 4649 4650 returnedCF2A.cbSize = sizeof(returnedCF2A); 4651 4652 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x"); 4653 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0)); 4654 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4655 4656 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont); 4657 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4658 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n", 4659 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4660 4661 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0)); 4662 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4663 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont); 4664 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4665 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n", 4666 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4667 4668 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0)); 4669 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4670 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont); 4671 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4672 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n", 4673 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4674 4675 /* This last test is special since we send in NULL. We clear the variables 4676 * and just compare to "System" instead of the sent in font name. */ 4677 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A)); 4678 ZeroMemory(&sentLogFont,sizeof(sentLogFont)); 4679 returnedCF2A.cbSize = sizeof(returnedCF2A); 4680 4681 SendMessageA(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0)); 4682 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4683 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont); 4684 ok (!strcmp("System",returnedCF2A.szFaceName), 4685 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName); 4686 4687 DestroyWindow(hwndRichEdit); 4688 } 4689 4690 4691 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, 4692 LPBYTE pbBuff, 4693 LONG cb, 4694 LONG *pcb) 4695 { 4696 const char** str = (const char**)dwCookie; 4697 int size = strlen(*str); 4698 if(size > 3) /* let's make it piecemeal for fun */ 4699 size = 3; 4700 *pcb = cb; 4701 if (*pcb > size) { 4702 *pcb = size; 4703 } 4704 if (*pcb > 0) { 4705 memcpy(pbBuff, *str, *pcb); 4706 *str += *pcb; 4707 } 4708 return 0; 4709 } 4710 4711 static void test_EM_GETMODIFY(void) 4712 { 4713 HWND hwndRichEdit = new_richedit(NULL); 4714 LRESULT result; 4715 SETTEXTEX setText; 4716 WCHAR TestItem1[] = {'T', 'e', 's', 't', 4717 'S', 'o', 'm', 'e', 4718 'T', 'e', 'x', 't', 0}; 4719 WCHAR TestItem2[] = {'T', 'e', 's', 't', 4720 'S', 'o', 'm', 'e', 4721 'O', 't', 'h', 'e', 'r', 4722 'T', 'e', 'x', 't', 0}; 4723 const char* streamText = "hello world"; 4724 CHARFORMAT2A cf2; 4725 PARAFORMAT2 pf2; 4726 EDITSTREAM es; 4727 4728 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4729 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4730 FF_DONTCARE, "Courier"); 4731 4732 setText.codepage = 1200; /* no constant for unicode */ 4733 setText.flags = ST_KEEPUNDO; 4734 4735 4736 /* modify flag shouldn't be set when richedit is first created */ 4737 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4738 ok (result == 0, 4739 "EM_GETMODIFY returned non-zero, instead of zero on create\n"); 4740 4741 /* setting modify flag should actually set it */ 4742 SendMessageA(hwndRichEdit, EM_SETMODIFY, TRUE, 0); 4743 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4744 ok (result != 0, 4745 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n"); 4746 4747 /* clearing modify flag should actually clear it */ 4748 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4749 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4750 ok (result == 0, 4751 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n"); 4752 4753 /* setting font doesn't change modify flag */ 4754 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4755 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0)); 4756 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4757 ok (result == 0, 4758 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n"); 4759 4760 /* setting text should set modify flag */ 4761 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4762 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4763 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4764 ok (result != 0, 4765 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n"); 4766 4767 /* undo previous text doesn't reset modify flag */ 4768 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 4769 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4770 ok (result != 0, 4771 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n"); 4772 4773 /* set text with no flag to keep undo stack should not set modify flag */ 4774 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4775 setText.flags = 0; 4776 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4777 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4778 ok (result == 0, 4779 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n"); 4780 4781 /* WM_SETTEXT doesn't modify */ 4782 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4783 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2); 4784 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4785 ok (result == 0, 4786 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n"); 4787 4788 /* clear the text */ 4789 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4790 SendMessageA(hwndRichEdit, WM_CLEAR, 0, 0); 4791 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4792 ok (result == 0, 4793 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n"); 4794 4795 /* replace text */ 4796 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4797 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4798 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4799 SendMessageA(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2); 4800 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4801 ok (result != 0, 4802 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n"); 4803 4804 /* copy/paste text 1 */ 4805 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4806 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4807 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 4808 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 4809 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4810 ok (result != 0, 4811 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n"); 4812 4813 /* copy/paste text 2 */ 4814 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4815 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4816 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 4817 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 3); 4818 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 4819 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4820 ok (result != 0, 4821 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n"); 4822 4823 /* press char */ 4824 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4825 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 1); 4826 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4827 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4828 ok (result != 0, 4829 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n"); 4830 4831 /* press del */ 4832 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4833 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4834 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0); 4835 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4836 ok (result != 0, 4837 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n"); 4838 4839 /* set char format */ 4840 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4841 cf2.cbSize = sizeof(CHARFORMAT2A); 4842 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 4843 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 4844 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 4845 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 4846 result = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 4847 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result); 4848 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4849 ok (result != 0, 4850 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n"); 4851 4852 /* set para format */ 4853 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4854 pf2.cbSize = sizeof(PARAFORMAT2); 4855 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2); 4856 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask; 4857 pf2.wAlignment = PFA_RIGHT; 4858 SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); 4859 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4860 ok (result == 0, 4861 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n"); 4862 4863 /* EM_STREAM */ 4864 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4865 es.dwCookie = (DWORD_PTR)&streamText; 4866 es.dwError = 0; 4867 es.pfnCallback = test_EM_GETMODIFY_esCallback; 4868 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 4869 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4870 ok (result != 0, 4871 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n"); 4872 4873 DestroyWindow(hwndRichEdit); 4874 } 4875 4876 struct exsetsel_s { 4877 LONG min; 4878 LONG max; 4879 LRESULT expected_retval; 4880 int expected_getsel_start; 4881 int expected_getsel_end; 4882 BOOL todo; 4883 }; 4884 4885 static const struct exsetsel_s exsetsel_tests[] = { 4886 /* sanity tests */ 4887 {5, 10, 10, 5, 10 }, 4888 {15, 17, 17, 15, 17 }, 4889 /* test cpMax > strlen() */ 4890 {0, 100, 18, 0, 18 }, 4891 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */ 4892 {-1, 1, 17, 17, 17 }, 4893 /* test cpMin == cpMax */ 4894 {5, 5, 5, 5, 5 }, 4895 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */ 4896 {-1, 0, 5, 5, 5 }, 4897 {-1, 17, 5, 5, 5 }, 4898 {-1, 18, 5, 5, 5 }, 4899 /* test cpMin < 0 && cpMax < 0 */ 4900 {-1, -1, 17, 17, 17 }, 4901 {-4, -5, 17, 17, 17 }, 4902 /* test cpMin >=0 && cpMax < 0 (bug 6814) */ 4903 {0, -1, 18, 0, 18 }, 4904 {17, -5, 18, 17, 18 }, 4905 {18, -3, 17, 17, 17 }, 4906 /* test if cpMin > cpMax */ 4907 {15, 19, 18, 15, 18 }, 4908 {19, 15, 18, 15, 18 }, 4909 /* cpMin == strlen() && cpMax > cpMin */ 4910 {17, 18, 18, 17, 18 }, 4911 {17, 50, 18, 17, 18 }, 4912 }; 4913 4914 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 4915 CHARRANGE cr; 4916 LRESULT result; 4917 int start, end; 4918 4919 cr.cpMin = setsel->min; 4920 cr.cpMax = setsel->max; 4921 result = SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); 4922 4923 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); 4924 4925 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 4926 4927 todo_wine_if (setsel->todo) 4928 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", 4929 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end); 4930 } 4931 4932 static void test_EM_EXSETSEL(void) 4933 { 4934 HWND hwndRichEdit = new_richedit(NULL); 4935 int i; 4936 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); 4937 4938 /* sending some text to the window */ 4939 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 4940 /* 01234567890123456*/ 4941 /* 10 */ 4942 4943 for (i = 0; i < num_tests; i++) { 4944 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i); 4945 } 4946 4947 if (!is_lang_japanese) 4948 skip("Skip multibyte character tests on non-Japanese platform\n"); 4949 else 4950 { 4951 CHARRANGE cr; 4952 char bufA[MAX_BUF_LEN] = {0}; 4953 LRESULT result; 4954 4955 /* Test with multibyte character */ 4956 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 4957 /* 012345 6 78901 */ 4958 cr.cpMin = 4, cr.cpMax = 8; 4959 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4960 ok(result == 8, "EM_EXSETSEL return %ld expected 8\n", result); 4961 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA); 4962 ok(!strcmp(bufA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n"); 4963 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 4964 ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin); 4965 ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax); 4966 } 4967 4968 DestroyWindow(hwndRichEdit); 4969 } 4970 4971 static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 4972 LRESULT result; 4973 int start, end; 4974 4975 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max); 4976 4977 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); 4978 4979 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 4980 4981 todo_wine_if (setsel->todo) 4982 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", 4983 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end); 4984 } 4985 4986 static void test_EM_SETSEL(void) 4987 { 4988 char buffA[32] = {0}; 4989 HWND hwndRichEdit = new_richedit(NULL); 4990 int i; 4991 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); 4992 4993 /* sending some text to the window */ 4994 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 4995 /* 01234567890123456*/ 4996 /* 10 */ 4997 4998 for (i = 0; i < num_tests; i++) { 4999 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i); 5000 } 5001 5002 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18); 5003 buffA[0] = 123; 5004 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA); 5005 ok(buffA[0] == 0, "selection text %s\n", buffA); 5006 5007 if (!is_lang_japanese) 5008 skip("Skip multibyte character tests on non-Japanese platform\n"); 5009 else 5010 { 5011 int sel_start, sel_end; 5012 LRESULT result; 5013 5014 /* Test with multibyte character */ 5015 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 5016 /* 012345 6 78901 */ 5017 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8); 5018 ok(result == 8, "EM_SETSEL return %ld expected 8\n", result); 5019 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA); 5020 ok(!strcmp(buffA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n"); 5021 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 5022 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start); 5023 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end); 5024 } 5025 5026 DestroyWindow(hwndRichEdit); 5027 } 5028 5029 static void test_EM_REPLACESEL(int redraw) 5030 { 5031 HWND hwndRichEdit = new_richedit(NULL); 5032 char buffer[1024] = {0}; 5033 int r; 5034 GETTEXTEX getText; 5035 CHARRANGE cr; 5036 CHAR rtfstream[] = "{\\rtf1 TestSomeText}"; 5037 CHAR urtfstream[] = "{\\urtf1 TestSomeText}"; 5038 5039 /* sending some text to the window */ 5040 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 5041 /* 01234567890123456*/ 5042 /* 10 */ 5043 5044 /* FIXME add more tests */ 5045 SendMessageA(hwndRichEdit, EM_SETSEL, 7, 17); 5046 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, 0); 5047 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r); 5048 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5049 r = strcmp(buffer, "testing"); 5050 ok(0 == r, "expected %d, got %d\n", 0, r); 5051 5052 DestroyWindow(hwndRichEdit); 5053 5054 hwndRichEdit = new_richedit(NULL); 5055 5056 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw); 5057 SendMessageA(hwndRichEdit, WM_SETREDRAW, redraw, 0); 5058 5059 /* Test behavior with carriage returns and newlines */ 5060 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5061 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1"); 5062 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r); 5063 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5064 r = strcmp(buffer, "RichEdit1"); 5065 ok(0 == r, "expected %d, got %d\n", 0, r); 5066 getText.cb = 1024; 5067 getText.codepage = CP_ACP; 5068 getText.flags = GT_DEFAULT; 5069 getText.lpDefaultChar = NULL; 5070 getText.lpUsedDefChar = NULL; 5071 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5072 ok(strcmp(buffer, "RichEdit1") == 0, 5073 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n"); 5074 5075 /* Test number of lines reported after EM_REPLACESEL */ 5076 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5077 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); 5078 5079 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5080 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r"); 5081 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r); 5082 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5083 r = strcmp(buffer, "RichEdit1\r\n"); 5084 ok(0 == r, "expected %d, got %d\n", 0, r); 5085 getText.cb = 1024; 5086 getText.codepage = CP_ACP; 5087 getText.flags = GT_DEFAULT; 5088 getText.lpDefaultChar = NULL; 5089 getText.lpUsedDefChar = NULL; 5090 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5091 ok(strcmp(buffer, "RichEdit1\r") == 0, 5092 "EM_GETTEXTEX returned incorrect string\n"); 5093 5094 /* Test number of lines reported after EM_REPLACESEL */ 5095 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5096 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5097 5098 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5099 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r\n"); 5100 ok(r == 11, "EM_REPLACESEL returned %d, expected 11\n", r); 5101 5102 /* Test number of lines reported after EM_REPLACESEL */ 5103 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5104 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5105 5106 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5107 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5108 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin); 5109 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax); 5110 5111 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5112 r = strcmp(buffer, "RichEdit1\r\n"); 5113 ok(0 == r, "expected %d, got %d\n", 0, r); 5114 getText.cb = 1024; 5115 getText.codepage = CP_ACP; 5116 getText.flags = GT_DEFAULT; 5117 getText.lpDefaultChar = NULL; 5118 getText.lpUsedDefChar = NULL; 5119 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5120 ok(strcmp(buffer, "RichEdit1\r") == 0, 5121 "EM_GETTEXTEX returned incorrect string\n"); 5122 5123 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5124 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5125 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin); 5126 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax); 5127 5128 /* The following tests show that richedit should handle the special \r\r\n 5129 sequence by turning it into a single space on insertion. However, 5130 EM_REPLACESEL on WinXP returns the number of characters in the original 5131 string. 5132 */ 5133 5134 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5135 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r"); 5136 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r); 5137 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5138 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5139 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5140 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5141 5142 /* Test the actual string */ 5143 getText.cb = 1024; 5144 getText.codepage = CP_ACP; 5145 getText.flags = GT_DEFAULT; 5146 getText.lpDefaultChar = NULL; 5147 getText.lpUsedDefChar = NULL; 5148 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5149 ok(strcmp(buffer, "\r\r") == 0, 5150 "EM_GETTEXTEX returned incorrect string\n"); 5151 5152 /* Test number of lines reported after EM_REPLACESEL */ 5153 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5154 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5155 5156 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5157 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n"); 5158 ok(r == 3, "EM_REPLACESEL returned %d, expected 3\n", r); 5159 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5160 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5161 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin); 5162 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax); 5163 5164 /* Test the actual string */ 5165 getText.cb = 1024; 5166 getText.codepage = CP_ACP; 5167 getText.flags = GT_DEFAULT; 5168 getText.lpDefaultChar = NULL; 5169 getText.lpUsedDefChar = NULL; 5170 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5171 ok(strcmp(buffer, " ") == 0, 5172 "EM_GETTEXTEX returned incorrect string\n"); 5173 5174 /* Test number of lines reported after EM_REPLACESEL */ 5175 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5176 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); 5177 5178 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5179 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\r\r\r\n\r\r\r"); 5180 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r); 5181 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5182 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5183 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin); 5184 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax); 5185 5186 /* Test the actual string */ 5187 getText.cb = 1024; 5188 getText.codepage = CP_ACP; 5189 getText.flags = GT_DEFAULT; 5190 getText.lpDefaultChar = NULL; 5191 getText.lpUsedDefChar = NULL; 5192 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5193 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0, 5194 "EM_GETTEXTEX returned incorrect string\n"); 5195 5196 /* Test number of lines reported after EM_REPLACESEL */ 5197 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5198 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); 5199 5200 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5201 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\n"); 5202 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5203 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5204 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5205 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5206 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5207 5208 /* Test the actual string */ 5209 getText.cb = 1024; 5210 getText.codepage = CP_ACP; 5211 getText.flags = GT_DEFAULT; 5212 getText.lpDefaultChar = NULL; 5213 getText.lpUsedDefChar = NULL; 5214 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5215 ok(strcmp(buffer, " \r") == 0, 5216 "EM_GETTEXTEX returned incorrect string\n"); 5217 5218 /* Test number of lines reported after EM_REPLACESEL */ 5219 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5220 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5221 5222 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5223 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\r"); 5224 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5225 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5226 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5227 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin); 5228 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax); 5229 5230 /* Test the actual string */ 5231 getText.cb = 1024; 5232 getText.codepage = CP_ACP; 5233 getText.flags = GT_DEFAULT; 5234 getText.lpDefaultChar = NULL; 5235 getText.lpUsedDefChar = NULL; 5236 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5237 ok(strcmp(buffer, " \r\r") == 0, 5238 "EM_GETTEXTEX returned incorrect string\n"); 5239 5240 /* Test number of lines reported after EM_REPLACESEL */ 5241 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5242 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5243 5244 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5245 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\rX\r\n\r\r"); 5246 ok(r == 6, "EM_REPLACESEL returned %d, expected 6\n", r); 5247 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5248 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5249 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin); 5250 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax); 5251 5252 /* Test the actual string */ 5253 getText.cb = 1024; 5254 getText.codepage = CP_ACP; 5255 getText.flags = GT_DEFAULT; 5256 getText.lpDefaultChar = NULL; 5257 getText.lpUsedDefChar = NULL; 5258 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5259 ok(strcmp(buffer, "\rX\r\r\r") == 0, 5260 "EM_GETTEXTEX returned incorrect string\n"); 5261 5262 /* Test number of lines reported after EM_REPLACESEL */ 5263 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5264 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r); 5265 5266 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5267 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n"); 5268 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r); 5269 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5270 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5271 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5272 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5273 5274 /* Test the actual string */ 5275 getText.cb = 1024; 5276 getText.codepage = CP_ACP; 5277 getText.flags = GT_DEFAULT; 5278 getText.lpDefaultChar = NULL; 5279 getText.lpUsedDefChar = NULL; 5280 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5281 ok(strcmp(buffer, "\r\r") == 0, 5282 "EM_GETTEXTEX returned incorrect string\n"); 5283 5284 /* Test number of lines reported after EM_REPLACESEL */ 5285 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5286 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5287 5288 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5289 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n\n\n\r\r\r\r\n"); 5290 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r); 5291 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5292 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5293 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin); 5294 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax); 5295 5296 /* Test the actual string */ 5297 getText.cb = 1024; 5298 getText.codepage = CP_ACP; 5299 getText.flags = GT_DEFAULT; 5300 getText.lpDefaultChar = NULL; 5301 getText.lpUsedDefChar = NULL; 5302 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5303 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0, 5304 "EM_GETTEXTEX returned incorrect string\n"); 5305 5306 /* Test number of lines reported after EM_REPLACESEL */ 5307 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5308 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); 5309 5310 /* Test with multibyte character */ 5311 if (!is_lang_japanese) 5312 skip("Skip multibyte character tests on non-Japanese platform\n"); 5313 else 5314 { 5315 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5316 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"abc\x8e\xf0"); 5317 todo_wine ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5318 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5319 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r); 5320 ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin); 5321 ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax); 5322 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5323 ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n"); 5324 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5325 5326 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5327 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"{\\rtf abc\x8e\xf0}"); 5328 todo_wine ok(r == 4, "EM_REPLACESEL returned %d, expected 4\n", r); 5329 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5330 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r); 5331 todo_wine ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin); 5332 todo_wine ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax); 5333 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5334 todo_wine ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n"); 5335 todo_wine ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5336 } 5337 5338 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5339 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5340 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5341 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5342 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5343 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin); 5344 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax); 5345 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5346 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n"); 5347 5348 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5349 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urtfstream); 5350 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5351 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5352 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5353 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin); 5354 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax); 5355 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5356 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n"); 5357 5358 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Wine"); 5359 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2); 5360 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5361 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5362 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5363 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5364 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin); 5365 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax); 5366 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5367 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n"); 5368 5369 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 Wine}"); 5370 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2); 5371 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5372 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5373 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5374 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5375 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin); 5376 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax); 5377 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5378 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n"); 5379 5380 if (!redraw) 5381 /* This is needed to avoid interfering with keybd_event calls 5382 * on other tests that simulate keyboard events. */ 5383 SendMessageA(hwndRichEdit, WM_SETREDRAW, TRUE, 0); 5384 5385 DestroyWindow(hwndRichEdit); 5386 5387 /* Single-line richedit */ 5388 hwndRichEdit = new_richedit_with_style(NULL, 0); 5389 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"line1\r\nline2"); 5390 ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5391 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5392 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5393 ok(!strcmp(buffer, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buffer); 5394 DestroyWindow(hwndRichEdit); 5395 } 5396 5397 /* Native riched20 inspects the keyboard state (e.g. GetKeyState) 5398 * to test the state of the modifiers (Ctrl/Alt/Shift). 5399 * 5400 * Therefore Ctrl-<key> keystrokes need to be simulated with 5401 * keybd_event or by using SetKeyboardState to set the modifiers 5402 * and SendMessage to simulate the keystrokes. 5403 */ 5404 static LRESULT send_ctrl_key(HWND hwnd, UINT key) 5405 { 5406 LRESULT result; 5407 hold_key(VK_CONTROL); 5408 result = SendMessageA(hwnd, WM_KEYDOWN, key, 1); 5409 release_key(VK_CONTROL); 5410 return result; 5411 } 5412 5413 static void test_WM_PASTE(void) 5414 { 5415 int result; 5416 char buffer[1024] = {0}; 5417 const char* text1 = "testing paste\r"; 5418 const char* text1_step1 = "testing paste\r\ntesting paste\r\n"; 5419 const char* text1_after = "testing paste\r\n"; 5420 const char* text2 = "testing paste\r\rtesting paste"; 5421 const char* text2_after = "testing paste\r\n\r\ntesting paste"; 5422 const char* text3 = "testing paste\r\npaste\r\ntesting paste"; 5423 HWND hwndRichEdit = new_richedit(NULL); 5424 5425 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 5426 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 14); 5427 5428 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */ 5429 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14); 5430 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */ 5431 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5432 /* Pasted text should be visible at this step */ 5433 result = strcmp(text1_step1, buffer); 5434 ok(result == 0, 5435 "test paste: strcmp = %i, text='%s'\n", result, buffer); 5436 5437 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */ 5438 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5439 /* Text should be the same as before (except for \r -> \r\n conversion) */ 5440 result = strcmp(text1_after, buffer); 5441 ok(result == 0, 5442 "test paste: strcmp = %i, text='%s'\n", result, buffer); 5443 5444 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 5445 SendMessageA(hwndRichEdit, EM_SETSEL, 8, 13); 5446 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */ 5447 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14); 5448 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */ 5449 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5450 /* Pasted text should be visible at this step */ 5451 result = strcmp(text3, buffer); 5452 ok(result == 0, 5453 "test paste: strcmp = %i\n", result); 5454 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */ 5455 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5456 /* Text should be the same as before (except for \r -> \r\n conversion) */ 5457 result = strcmp(text2_after, buffer); 5458 ok(result == 0, 5459 "test paste: strcmp = %i\n", result); 5460 send_ctrl_key(hwndRichEdit, 'Y'); /* Redo */ 5461 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5462 /* Text should revert to post-paste state */ 5463 result = strcmp(buffer,text3); 5464 ok(result == 0, 5465 "test paste: strcmp = %i\n", result); 5466 5467 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5468 /* Send WM_CHAR to simulate Ctrl-V */ 5469 SendMessageA(hwndRichEdit, WM_CHAR, 22, 5470 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1); 5471 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5472 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */ 5473 result = strcmp(buffer,""); 5474 ok(result == 0, 5475 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5476 5477 /* Send keystrokes with WM_KEYDOWN after setting the modifiers 5478 * with SetKeyboard state. */ 5479 5480 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5481 /* Simulates paste (Ctrl-V) */ 5482 hold_key(VK_CONTROL); 5483 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'V', 5484 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1); 5485 release_key(VK_CONTROL); 5486 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5487 result = strcmp(buffer,"paste"); 5488 ok(result == 0, 5489 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5490 5491 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 5492 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 7); 5493 /* Simulates copy (Ctrl-C) */ 5494 hold_key(VK_CONTROL); 5495 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'C', 5496 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC) << 16) | 1); 5497 release_key(VK_CONTROL); 5498 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5499 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5500 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5501 result = strcmp(buffer,"testing"); 5502 ok(result == 0, 5503 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5504 5505 /* Cut with WM_KEYDOWN to simulate Ctrl-X */ 5506 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"cut"); 5507 /* Simulates select all (Ctrl-A) */ 5508 hold_key(VK_CONTROL); 5509 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 5510 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC) << 16) | 1); 5511 /* Simulates select cut (Ctrl-X) */ 5512 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'X', 5513 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC) << 16) | 1); 5514 release_key(VK_CONTROL); 5515 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5516 result = strcmp(buffer,""); 5517 ok(result == 0, 5518 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5519 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5520 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5521 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5522 result = strcmp(buffer,"cut\r\n"); 5523 ok(result == 0, 5524 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5525 /* Simulates undo (Ctrl-Z) */ 5526 hold_key(VK_CONTROL); 5527 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Z', 5528 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC) << 16) | 1); 5529 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5530 result = strcmp(buffer,""); 5531 ok(result == 0, 5532 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5533 /* Simulates redo (Ctrl-Y) */ 5534 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Y', 5535 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC) << 16) | 1); 5536 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5537 result = strcmp(buffer,"cut\r\n"); 5538 ok(result == 0, 5539 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5540 release_key(VK_CONTROL); 5541 5542 /* Copy multiline text to clipboard for future use */ 5543 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); 5544 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 5545 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 5546 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 5547 5548 /* Paste into read-only control */ 5549 result = SendMessageA(hwndRichEdit, EM_SETREADONLY, TRUE, 0); 5550 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5551 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5552 result = strcmp(buffer, text3); 5553 ok(result == 0, 5554 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5555 5556 /* Cut from read-only control */ 5557 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 5558 SendMessageA(hwndRichEdit, WM_CUT, 0, 0); 5559 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5560 result = strcmp(buffer, text3); 5561 ok(result == 0, 5562 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5563 5564 /* FIXME: Wine doesn't flush Ole clipboard when window is destroyed so do it manually */ 5565 OleFlushClipboard(); 5566 DestroyWindow(hwndRichEdit); 5567 5568 /* Paste multi-line text into single-line control */ 5569 hwndRichEdit = new_richedit_with_style(NULL, 0); 5570 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5571 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5572 result = strcmp(buffer, "testing paste"); 5573 ok(result == 0, 5574 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5575 DestroyWindow(hwndRichEdit); 5576 } 5577 5578 static void test_EM_FORMATRANGE(void) 5579 { 5580 int r, i, tpp_x, tpp_y; 5581 HDC hdc; 5582 HWND hwndRichEdit = new_richedit(NULL); 5583 FORMATRANGE fr; 5584 BOOL skip_non_english; 5585 static const struct { 5586 const char *string; /* The string */ 5587 int first; /* First 'pagebreak', 0 for don't care */ 5588 int second; /* Second 'pagebreak', 0 for don't care */ 5589 } fmtstrings[] = { 5590 {"WINE wine", 0, 0}, 5591 {"WINE wineWine", 0, 0}, 5592 {"WINE\r\nwine\r\nwine", 5, 10}, 5593 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14}, 5594 {"WINE\r\n\r\nwine\r\nwine", 5, 6} 5595 }; 5596 5597 skip_non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH); 5598 if (skip_non_english) 5599 skip("Skipping some tests on non-English platform\n"); 5600 5601 hdc = GetDC(hwndRichEdit); 5602 ok(hdc != NULL, "Could not get HDC\n"); 5603 5604 /* Calculate the twips per pixel */ 5605 tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX); 5606 tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY); 5607 5608 /* Test the simple case where all the text fits in the page rect. */ 5609 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 5610 fr.hdc = fr.hdcTarget = hdc; 5611 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0; 5612 fr.rc.right = fr.rcPage.right = 500 * tpp_x; 5613 fr.rc.bottom = fr.rcPage.bottom = 500 * tpp_y; 5614 fr.chrg.cpMin = 0; 5615 fr.chrg.cpMax = -1; 5616 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr); 5617 todo_wine ok(r == 2, "r=%d expected r=2\n", r); 5618 5619 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"ab"); 5620 fr.rc.bottom = fr.rcPage.bottom; 5621 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr); 5622 todo_wine ok(r == 3, "r=%d expected r=3\n", r); 5623 5624 SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0); 5625 5626 for (i = 0; i < sizeof(fmtstrings)/sizeof(fmtstrings[0]); i++) 5627 { 5628 GETTEXTLENGTHEX gtl; 5629 SIZE stringsize; 5630 int len; 5631 5632 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)fmtstrings[i].string); 5633 5634 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 5635 gtl.codepage = CP_ACP; 5636 len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 5637 5638 /* Get some size information for the string */ 5639 GetTextExtentPoint32A(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize); 5640 5641 /* Define the box to be half the width needed and a bit larger than the height. 5642 * Changes to the width means we have at least 2 pages. Changes to the height 5643 * is done so we can check the changing of fr.rc.bottom. 5644 */ 5645 fr.hdc = fr.hdcTarget = hdc; 5646 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0; 5647 fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x; 5648 fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y; 5649 5650 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); 5651 todo_wine { 5652 ok(r == len, "Expected %d, got %d\n", len, r); 5653 } 5654 5655 /* We know that the page can't hold the full string. See how many characters 5656 * are on the first one 5657 */ 5658 fr.chrg.cpMin = 0; 5659 fr.chrg.cpMax = -1; 5660 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 5661 todo_wine { 5662 if (! skip_non_english) 5663 ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom); 5664 } 5665 if (fmtstrings[i].first) 5666 todo_wine { 5667 ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r); 5668 } 5669 else 5670 ok(r < len, "Expected < %d, got %d\n", len, r); 5671 5672 /* Do another page */ 5673 fr.chrg.cpMin = r; 5674 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 5675 if (fmtstrings[i].second) 5676 todo_wine { 5677 ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r); 5678 } 5679 else if (! skip_non_english) 5680 ok (r < len, "Expected < %d, got %d\n", len, r); 5681 5682 /* There is at least on more page, but we don't care */ 5683 5684 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); 5685 todo_wine { 5686 ok(r == len, "Expected %d, got %d\n", len, r); 5687 } 5688 } 5689 5690 ReleaseDC(NULL, hdc); 5691 DestroyWindow(hwndRichEdit); 5692 } 5693 5694 static int nCallbackCount = 0; 5695 5696 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, 5697 LONG cb, LONG* pcb) 5698 { 5699 const char text[] = {'t','e','s','t'}; 5700 5701 if (sizeof(text) <= cb) 5702 { 5703 if ((int)dwCookie != nCallbackCount) 5704 { 5705 *pcb = 0; 5706 return 0; 5707 } 5708 5709 memcpy (pbBuff, text, sizeof(text)); 5710 *pcb = sizeof(text); 5711 5712 nCallbackCount++; 5713 5714 return 0; 5715 } 5716 else 5717 return 1; /* indicates callback failed */ 5718 } 5719 5720 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, 5721 LPBYTE pbBuff, 5722 LONG cb, 5723 LONG *pcb) 5724 { 5725 const char** str = (const char**)dwCookie; 5726 int size = strlen(*str); 5727 *pcb = cb; 5728 if (*pcb > size) { 5729 *pcb = size; 5730 } 5731 if (*pcb > 0) { 5732 memcpy(pbBuff, *str, *pcb); 5733 *str += *pcb; 5734 } 5735 return 0; 5736 } 5737 5738 static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie, 5739 LPBYTE pbBuff, 5740 LONG cb, 5741 LONG *pcb) 5742 { 5743 DWORD *phase = (DWORD *)dwCookie; 5744 5745 if(*phase == 0){ 5746 static const char first[] = "\xef\xbb\xbf\xc3\x96\xc3"; 5747 *pcb = sizeof(first) - 1; 5748 memcpy(pbBuff, first, *pcb); 5749 }else if(*phase == 1){ 5750 static const char second[] = "\x8f\xc3\x8b"; 5751 *pcb = sizeof(second) - 1; 5752 memcpy(pbBuff, second, *pcb); 5753 }else 5754 *pcb = 0; 5755 5756 ++*phase; 5757 5758 return 0; 5759 } 5760 5761 struct StringWithLength { 5762 int length; 5763 char *buffer; 5764 }; 5765 5766 /* This callback is used to handled the null characters in a string. */ 5767 static DWORD CALLBACK test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie, 5768 LPBYTE pbBuff, 5769 LONG cb, 5770 LONG *pcb) 5771 { 5772 struct StringWithLength* str = (struct StringWithLength*)dwCookie; 5773 int size = str->length; 5774 *pcb = cb; 5775 if (*pcb > size) { 5776 *pcb = size; 5777 } 5778 if (*pcb > 0) { 5779 memcpy(pbBuff, str->buffer, *pcb); 5780 str->buffer += *pcb; 5781 str->length -= *pcb; 5782 } 5783 return 0; 5784 } 5785 5786 static void test_EM_STREAMIN(void) 5787 { 5788 HWND hwndRichEdit = new_richedit(NULL); 5789 DWORD phase; 5790 LRESULT result; 5791 EDITSTREAM es; 5792 char buffer[1024] = {0}, tmp[16]; 5793 CHARRANGE range; 5794 PARAFORMAT2 fmt; 5795 5796 const char * streamText0 = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}"; 5797 const char * streamText0a = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}"; 5798 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; 5799 const char * ptr; 5800 5801 const char * streamText1 = 5802 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" 5803 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" 5804 "}\r\n"; 5805 5806 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */ 5807 const char * streamText2 = 5808 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" 5809 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" 5810 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " 5811 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " 5812 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " 5813 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " 5814 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; 5815 5816 const char * streamText3 = "RichEdit1"; 5817 5818 const char * streamTextUTF8BOM = "\xef\xbb\xbfTestUTF8WithBOM"; 5819 5820 const char * streamText4 = 5821 "This text just needs to be long enough to cause run to be split onto " 5822 "two separate lines and make sure the null terminating character is " 5823 "handled properly.\0"; 5824 5825 const WCHAR UTF8Split_exp[4] = {0xd6, 0xcf, 0xcb, 0}; 5826 5827 int length4 = strlen(streamText4) + 1; 5828 struct StringWithLength cookieForStream4 = { 5829 length4, 5830 (char *)streamText4, 5831 }; 5832 5833 const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' }; 5834 int length5 = sizeof(streamText5) / sizeof(WCHAR); 5835 struct StringWithLength cookieForStream5 = { 5836 sizeof(streamText5), 5837 (char *)streamText5, 5838 }; 5839 5840 /* Minimal test without \par at the end */ 5841 es.dwCookie = (DWORD_PTR)&streamText0; 5842 es.dwError = 0; 5843 es.pfnCallback = test_EM_STREAMIN_esCallback; 5844 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5845 ok(result == 12, "got %ld, expected %d\n", result, 12); 5846 5847 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5848 ok (result == 12, 5849 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result); 5850 result = strcmp (buffer,"TestSomeText"); 5851 ok (result == 0, 5852 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer); 5853 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); 5854 /* Show that para fmts are ignored */ 5855 range.cpMin = 2; 5856 range.cpMax = 2; 5857 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5858 memset(&fmt, 0xcc, sizeof(fmt)); 5859 fmt.cbSize = sizeof(fmt); 5860 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 5861 ok(fmt.dxStartIndent == 0, "got %d\n", fmt.dxStartIndent); 5862 ok(fmt.dxOffset == 0, "got %d\n", fmt.dxOffset); 5863 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment); 5864 ok((fmt.wEffects & PFE_RTLPARA) == 0, "got %x\n", fmt.wEffects); 5865 5866 /* Native richedit 2.0 ignores last \par */ 5867 ptr = streamText0a; 5868 es.dwCookie = (DWORD_PTR)&ptr; 5869 es.dwError = 0; 5870 es.pfnCallback = test_EM_STREAMIN_esCallback; 5871 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5872 ok(result == 12, "got %ld, expected %d\n", result, 12); 5873 5874 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5875 ok (result == 12, 5876 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); 5877 result = strcmp (buffer,"TestSomeText"); 5878 ok (result == 0, 5879 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); 5880 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0); 5881 /* This time para fmts are processed */ 5882 range.cpMin = 2; 5883 range.cpMax = 2; 5884 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5885 memset(&fmt, 0xcc, sizeof(fmt)); 5886 fmt.cbSize = sizeof(fmt); 5887 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 5888 ok(fmt.dxStartIndent == 300, "got %d\n", fmt.dxStartIndent); 5889 ok(fmt.dxOffset == -100, "got %d\n", fmt.dxOffset); 5890 ok(fmt.wAlignment == PFA_RIGHT, "got %d\n", fmt.wAlignment); 5891 ok((fmt.wEffects & PFE_RTLPARA) == PFE_RTLPARA, "got %x\n", fmt.wEffects); 5892 5893 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */ 5894 es.dwCookie = (DWORD_PTR)&streamText0b; 5895 es.dwError = 0; 5896 es.pfnCallback = test_EM_STREAMIN_esCallback; 5897 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5898 ok(result == 13, "got %ld, expected %d\n", result, 13); 5899 5900 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5901 ok (result == 14, 5902 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result); 5903 result = strcmp (buffer,"TestSomeText\r\n"); 5904 ok (result == 0, 5905 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer); 5906 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0); 5907 5908 /* Show that when using SFF_SELECTION the last \par is not ignored. */ 5909 ptr = streamText0a; 5910 es.dwCookie = (DWORD_PTR)&ptr; 5911 es.dwError = 0; 5912 es.pfnCallback = test_EM_STREAMIN_esCallback; 5913 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5914 ok(result == 12, "got %ld, expected %d\n", result, 12); 5915 5916 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5917 ok (result == 12, 5918 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); 5919 result = strcmp (buffer,"TestSomeText"); 5920 ok (result == 0, 5921 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); 5922 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0); 5923 5924 range.cpMin = 0; 5925 range.cpMax = -1; 5926 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5927 ok (result == 13, "got %ld\n", result); 5928 5929 ptr = streamText0a; 5930 es.dwCookie = (DWORD_PTR)&ptr; 5931 es.dwError = 0; 5932 es.pfnCallback = test_EM_STREAMIN_esCallback; 5933 5934 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SFF_SELECTION | SF_RTF, (LPARAM)&es); 5935 ok(result == 13, "got %ld, expected 13\n", result); 5936 5937 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5938 ok (result == 14, 5939 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result); 5940 result = strcmp (buffer,"TestSomeText\r\n"); 5941 ok (result == 0, 5942 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer); 5943 ok(es.dwError == 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es.dwError, 0); 5944 5945 es.dwCookie = (DWORD_PTR)&streamText1; 5946 es.dwError = 0; 5947 es.pfnCallback = test_EM_STREAMIN_esCallback; 5948 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5949 ok(result == 12, "got %ld, expected %d\n", result, 12); 5950 5951 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5952 ok (result == 12, 5953 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result); 5954 result = strcmp (buffer,"TestSomeText"); 5955 ok (result == 0, 5956 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); 5957 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0); 5958 5959 es.dwCookie = (DWORD_PTR)&streamText2; 5960 es.dwError = 0; 5961 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5962 ok(result == 0, "got %ld, expected %d\n", result, 0); 5963 5964 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5965 ok (result == 0, 5966 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result); 5967 ok(!buffer[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 5968 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16); 5969 5970 es.dwCookie = (DWORD_PTR)&streamText3; 5971 es.dwError = 0; 5972 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5973 ok(result == 0, "got %ld, expected %d\n", result, 0); 5974 5975 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5976 ok (result == 0, 5977 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result); 5978 ok(!buffer[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer); 5979 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16); 5980 5981 es.dwCookie = (DWORD_PTR)&streamTextUTF8BOM; 5982 es.dwError = 0; 5983 es.pfnCallback = test_EM_STREAMIN_esCallback; 5984 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 5985 ok(result == 18, "got %ld, expected %d\n", result, 18); 5986 5987 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5988 ok(result == 15, 5989 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result); 5990 result = strcmp (buffer,"TestUTF8WithBOM"); 5991 ok(result == 0, 5992 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer); 5993 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es.dwError, 0); 5994 5995 phase = 0; 5996 es.dwCookie = (DWORD_PTR)&phase; 5997 es.dwError = 0; 5998 es.pfnCallback = test_EM_STREAMIN_esCallback_UTF8Split; 5999 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6000 ok(result == 8, "got %ld\n", result); 6001 6002 WideCharToMultiByte(CP_ACP, 0, UTF8Split_exp, -1, tmp, sizeof(tmp), NULL, NULL); 6003 6004 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6005 ok(result == 3, 6006 "EM_STREAMIN: Test UTF8Split returned %ld\n", result); 6007 result = memcmp (buffer, tmp, 3); 6008 ok(result == 0, 6009 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer); 6010 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es.dwError, 0); 6011 6012 es.dwCookie = (DWORD_PTR)&cookieForStream4; 6013 es.dwError = 0; 6014 es.pfnCallback = test_EM_STREAMIN_esCallback2; 6015 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6016 ok(result == length4, "got %ld, expected %d\n", result, length4); 6017 6018 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6019 ok (result == length4, 6020 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result, length4); 6021 ok(es.dwError == 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es.dwError, 0); 6022 6023 es.dwCookie = (DWORD_PTR)&cookieForStream5; 6024 es.dwError = 0; 6025 es.pfnCallback = test_EM_STREAMIN_esCallback2; 6026 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM)&es); 6027 ok(result == sizeof(streamText5), "got %ld, expected %u\n", result, (UINT)sizeof(streamText5)); 6028 6029 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6030 ok (result == length5, 6031 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result, length5); 6032 ok(es.dwError == 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es.dwError, 0); 6033 6034 DestroyWindow(hwndRichEdit); 6035 6036 /* Single-line richedit */ 6037 hwndRichEdit = new_richedit_with_style(NULL, 0); 6038 ptr = "line1\r\nline2"; 6039 es.dwCookie = (DWORD_PTR)&ptr; 6040 es.dwError = 0; 6041 es.pfnCallback = test_EM_STREAMIN_esCallback; 6042 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6043 ok(result == 12, "got %ld, expected %d\n", result, 12); 6044 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6045 ok (!strcmp(buffer, "line1"), 6046 "EM_STREAMIN: Unexpected text '%s'\n", buffer); 6047 } 6048 6049 static void test_EM_StreamIn_Undo(void) 6050 { 6051 /* The purpose of this test is to determine when a EM_StreamIn should be 6052 * undoable. This is important because WM_PASTE currently uses StreamIn and 6053 * pasting should always be undoable but streaming isn't always. 6054 * 6055 * cases to test: 6056 * StreamIn plain text without SFF_SELECTION. 6057 * StreamIn plain text with SFF_SELECTION set but a zero-length selection 6058 * StreamIn plain text with SFF_SELECTION and a valid, normal selection 6059 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to) 6060 * Feel free to add tests for other text modes or StreamIn things. 6061 */ 6062 6063 6064 HWND hwndRichEdit = new_richedit(NULL); 6065 LRESULT result; 6066 EDITSTREAM es; 6067 char buffer[1024] = {0}; 6068 const char randomtext[] = "Some text"; 6069 6070 es.pfnCallback = EditStreamCallback; 6071 6072 /* StreamIn, no SFF_SELECTION */ 6073 es.dwCookie = nCallbackCount; 6074 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6075 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6076 SendMessageA(hwndRichEdit, EM_SETSEL,0,0); 6077 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6078 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6079 result = strcmp (buffer,"test"); 6080 ok (result == 0, 6081 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); 6082 6083 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6084 ok (result == FALSE, 6085 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n"); 6086 6087 /* StreamIn, SFF_SELECTION, but nothing selected */ 6088 es.dwCookie = nCallbackCount; 6089 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6090 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6091 SendMessageA(hwndRichEdit, EM_SETSEL,0,0); 6092 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es); 6093 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6094 result = strcmp (buffer,"testSome text"); 6095 ok (result == 0, 6096 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 6097 6098 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6099 ok (result == TRUE, 6100 "EM_STREAMIN with SFF_SELECTION but no selection set " 6101 "should create an undo\n"); 6102 6103 /* StreamIn, SFF_SELECTION, with a selection */ 6104 es.dwCookie = nCallbackCount; 6105 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6106 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6107 SendMessageA(hwndRichEdit, EM_SETSEL,4,5); 6108 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es); 6109 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6110 result = strcmp (buffer,"Sometesttext"); 6111 ok (result == 0, 6112 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 6113 6114 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6115 ok (result == TRUE, 6116 "EM_STREAMIN with SFF_SELECTION and selection set " 6117 "should create an undo\n"); 6118 6119 DestroyWindow(hwndRichEdit); 6120 } 6121 6122 static BOOL is_em_settextex_supported(HWND hwnd) 6123 { 6124 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; 6125 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0; 6126 } 6127 6128 static void test_unicode_conversions(void) 6129 { 6130 static const WCHAR tW[] = {'t',0}; 6131 static const WCHAR teW[] = {'t','e',0}; 6132 static const WCHAR textW[] = {'t','e','s','t',0}; 6133 static const char textA[] = "test"; 6134 char bufA[64]; 6135 WCHAR bufW[64]; 6136 HWND hwnd; 6137 int em_settextex_supported, ret; 6138 6139 #define set_textA(hwnd, wm_set_text, txt) \ 6140 do { \ 6141 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \ 6142 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ 6143 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ 6144 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \ 6145 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \ 6146 } while(0) 6147 #define expect_textA(hwnd, wm_get_text, txt) \ 6148 do { \ 6149 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ 6150 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6151 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6152 memset(bufA, 0xAA, sizeof(bufA)); \ 6153 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ 6154 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \ 6155 ret = lstrcmpA(bufA, txt); \ 6156 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \ 6157 } while(0) 6158 6159 #define set_textW(hwnd, wm_set_text, txt) \ 6160 do { \ 6161 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \ 6162 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ 6163 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ 6164 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \ 6165 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \ 6166 } while(0) 6167 #define expect_textW(hwnd, wm_get_text, txt) \ 6168 do { \ 6169 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \ 6170 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6171 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6172 memset(bufW, 0xAA, sizeof(bufW)); \ 6173 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \ 6174 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \ 6175 ret = lstrcmpW(bufW, txt); \ 6176 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \ 6177 } while(0) 6178 #define expect_empty(hwnd, wm_get_text) \ 6179 do { \ 6180 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ 6181 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6182 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6183 memset(bufA, 0xAA, sizeof(bufA)); \ 6184 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ 6185 ok(!ret, "empty richedit should return 0, got %d\n", ret); \ 6186 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \ 6187 } while(0) 6188 6189 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6190 0, 0, 200, 60, 0, 0, 0, 0); 6191 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6192 6193 ret = IsWindowUnicode(hwnd); 6194 ok(ret, "RichEdit20W should be unicode under NT\n"); 6195 6196 /* EM_SETTEXTEX is supported starting from version 3.0 */ 6197 em_settextex_supported = is_em_settextex_supported(hwnd); 6198 trace("EM_SETTEXTEX is %ssupported on this platform\n", 6199 em_settextex_supported ? "" : "NOT "); 6200 6201 expect_empty(hwnd, WM_GETTEXT); 6202 expect_empty(hwnd, EM_GETTEXTEX); 6203 6204 ret = SendMessageA(hwnd, WM_CHAR, textW[0], 0); 6205 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); 6206 expect_textA(hwnd, WM_GETTEXT, "t"); 6207 expect_textA(hwnd, EM_GETTEXTEX, "t"); 6208 expect_textW(hwnd, EM_GETTEXTEX, tW); 6209 6210 ret = SendMessageA(hwnd, WM_CHAR, textA[1], 0); 6211 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); 6212 expect_textA(hwnd, WM_GETTEXT, "te"); 6213 expect_textA(hwnd, EM_GETTEXTEX, "te"); 6214 expect_textW(hwnd, EM_GETTEXTEX, teW); 6215 6216 set_textA(hwnd, WM_SETTEXT, NULL); 6217 expect_empty(hwnd, WM_GETTEXT); 6218 expect_empty(hwnd, EM_GETTEXTEX); 6219 6220 set_textA(hwnd, WM_SETTEXT, textA); 6221 expect_textA(hwnd, WM_GETTEXT, textA); 6222 expect_textA(hwnd, EM_GETTEXTEX, textA); 6223 expect_textW(hwnd, EM_GETTEXTEX, textW); 6224 6225 if (em_settextex_supported) 6226 { 6227 set_textA(hwnd, EM_SETTEXTEX, textA); 6228 expect_textA(hwnd, WM_GETTEXT, textA); 6229 expect_textA(hwnd, EM_GETTEXTEX, textA); 6230 expect_textW(hwnd, EM_GETTEXTEX, textW); 6231 } 6232 6233 set_textW(hwnd, WM_SETTEXT, textW); 6234 expect_textW(hwnd, WM_GETTEXT, textW); 6235 expect_textA(hwnd, WM_GETTEXT, textA); 6236 expect_textW(hwnd, EM_GETTEXTEX, textW); 6237 expect_textA(hwnd, EM_GETTEXTEX, textA); 6238 6239 if (em_settextex_supported) 6240 { 6241 set_textW(hwnd, EM_SETTEXTEX, textW); 6242 expect_textW(hwnd, WM_GETTEXT, textW); 6243 expect_textA(hwnd, WM_GETTEXT, textA); 6244 expect_textW(hwnd, EM_GETTEXTEX, textW); 6245 expect_textA(hwnd, EM_GETTEXTEX, textA); 6246 } 6247 DestroyWindow(hwnd); 6248 6249 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP, 6250 0, 0, 200, 60, 0, 0, 0, 0); 6251 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6252 6253 ret = IsWindowUnicode(hwnd); 6254 ok(!ret, "RichEdit20A should NOT be unicode\n"); 6255 6256 set_textA(hwnd, WM_SETTEXT, textA); 6257 expect_textA(hwnd, WM_GETTEXT, textA); 6258 expect_textA(hwnd, EM_GETTEXTEX, textA); 6259 expect_textW(hwnd, EM_GETTEXTEX, textW); 6260 6261 if (em_settextex_supported) 6262 { 6263 set_textA(hwnd, EM_SETTEXTEX, textA); 6264 expect_textA(hwnd, WM_GETTEXT, textA); 6265 expect_textA(hwnd, EM_GETTEXTEX, textA); 6266 expect_textW(hwnd, EM_GETTEXTEX, textW); 6267 } 6268 6269 set_textW(hwnd, WM_SETTEXT, textW); 6270 expect_textW(hwnd, WM_GETTEXT, textW); 6271 expect_textA(hwnd, WM_GETTEXT, textA); 6272 expect_textW(hwnd, EM_GETTEXTEX, textW); 6273 expect_textA(hwnd, EM_GETTEXTEX, textA); 6274 6275 if (em_settextex_supported) 6276 { 6277 set_textW(hwnd, EM_SETTEXTEX, textW); 6278 expect_textW(hwnd, WM_GETTEXT, textW); 6279 expect_textA(hwnd, WM_GETTEXT, textA); 6280 expect_textW(hwnd, EM_GETTEXTEX, textW); 6281 expect_textA(hwnd, EM_GETTEXTEX, textA); 6282 } 6283 DestroyWindow(hwnd); 6284 } 6285 6286 static void test_WM_CHAR(void) 6287 { 6288 HWND hwnd; 6289 int ret; 6290 const char * char_list = "abc\rabc\r"; 6291 const char * expected_content_single = "abcabc"; 6292 const char * expected_content_multi = "abc\r\nabc\r\n"; 6293 char buffer[64] = {0}; 6294 const char * p; 6295 6296 /* single-line control must IGNORE carriage returns */ 6297 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6298 0, 0, 200, 60, 0, 0, 0, 0); 6299 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6300 6301 p = char_list; 6302 while (*p != '\0') { 6303 SendMessageA(hwnd, WM_KEYDOWN, *p, 1); 6304 ret = SendMessageA(hwnd, WM_CHAR, *p, 1); 6305 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret); 6306 SendMessageA(hwnd, WM_KEYUP, *p, 1); 6307 p++; 6308 } 6309 6310 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6311 ret = strcmp(buffer, expected_content_single); 6312 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6313 6314 DestroyWindow(hwnd); 6315 6316 /* multi-line control inserts CR normally */ 6317 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE, 6318 0, 0, 200, 60, 0, 0, 0, 0); 6319 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6320 6321 p = char_list; 6322 while (*p != '\0') { 6323 SendMessageA(hwnd, WM_KEYDOWN, *p, 1); 6324 ret = SendMessageA(hwnd, WM_CHAR, *p, 1); 6325 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret); 6326 SendMessageA(hwnd, WM_KEYUP, *p, 1); 6327 p++; 6328 } 6329 6330 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6331 ret = strcmp(buffer, expected_content_multi); 6332 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6333 6334 DestroyWindow(hwnd); 6335 } 6336 6337 static void test_EM_GETTEXTLENGTHEX(void) 6338 { 6339 HWND hwnd; 6340 GETTEXTLENGTHEX gtl; 6341 int ret; 6342 const char * base_string = "base string"; 6343 const char * test_string = "a\nb\n\n\r\n"; 6344 const char * test_string_after = "a"; 6345 const char * test_string_2 = "a\rtest\rstring"; 6346 char buffer[64] = {0}; 6347 6348 /* single line */ 6349 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6350 0, 0, 200, 60, 0, 0, 0, 0); 6351 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6352 6353 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6354 gtl.codepage = CP_ACP; 6355 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6356 ok(ret == 0, "ret %d\n",ret); 6357 6358 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6359 gtl.codepage = CP_ACP; 6360 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6361 ok(ret == 0, "ret %d\n",ret); 6362 6363 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string); 6364 6365 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6366 gtl.codepage = CP_ACP; 6367 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6368 ok(ret == strlen(base_string), "ret %d\n",ret); 6369 6370 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6371 gtl.codepage = CP_ACP; 6372 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6373 ok(ret == strlen(base_string), "ret %d\n",ret); 6374 6375 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string); 6376 6377 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6378 gtl.codepage = CP_ACP; 6379 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6380 ok(ret == 1, "ret %d\n",ret); 6381 6382 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6383 gtl.codepage = CP_ACP; 6384 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6385 ok(ret == 1, "ret %d\n",ret); 6386 6387 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6388 ret = strcmp(buffer, test_string_after); 6389 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6390 6391 DestroyWindow(hwnd); 6392 6393 /* multi line */ 6394 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE, 6395 0, 0, 200, 60, 0, 0, 0, 0); 6396 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6397 6398 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6399 gtl.codepage = CP_ACP; 6400 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6401 ok(ret == 0, "ret %d\n",ret); 6402 6403 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6404 gtl.codepage = CP_ACP; 6405 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6406 ok(ret == 0, "ret %d\n",ret); 6407 6408 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string); 6409 6410 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6411 gtl.codepage = CP_ACP; 6412 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6413 ok(ret == strlen(base_string), "ret %d\n",ret); 6414 6415 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6416 gtl.codepage = CP_ACP; 6417 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6418 ok(ret == strlen(base_string), "ret %d\n",ret); 6419 6420 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2); 6421 6422 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6423 gtl.codepage = CP_ACP; 6424 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6425 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret); 6426 6427 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6428 gtl.codepage = CP_ACP; 6429 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6430 ok(ret == strlen(test_string_2), "ret %d\n",ret); 6431 6432 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string); 6433 6434 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6435 gtl.codepage = CP_ACP; 6436 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6437 ok(ret == 10, "ret %d\n",ret); 6438 6439 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6440 gtl.codepage = CP_ACP; 6441 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6442 ok(ret == 6, "ret %d\n",ret); 6443 6444 /* Unicode/NUMCHARS/NUMBYTES */ 6445 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2); 6446 6447 gtl.flags = GTL_DEFAULT; 6448 gtl.codepage = 1200; 6449 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6450 ok(ret == lstrlenA(test_string_2), 6451 "GTL_DEFAULT gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6452 6453 gtl.flags = GTL_NUMCHARS; 6454 gtl.codepage = 1200; 6455 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6456 ok(ret == lstrlenA(test_string_2), 6457 "GTL_NUMCHARS gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6458 6459 gtl.flags = GTL_NUMBYTES; 6460 gtl.codepage = 1200; 6461 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6462 ok(ret == lstrlenA(test_string_2)*2, 6463 "GTL_NUMBYTES gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2); 6464 6465 gtl.flags = GTL_PRECISE; 6466 gtl.codepage = 1200; 6467 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6468 ok(ret == lstrlenA(test_string_2)*2, 6469 "GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2); 6470 6471 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6472 gtl.codepage = 1200; 6473 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6474 ok(ret == lstrlenA(test_string_2), 6475 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6476 6477 gtl.flags = GTL_NUMCHARS | GTL_NUMBYTES; 6478 gtl.codepage = 1200; 6479 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6480 ok(ret == E_INVALIDARG, 6481 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret, E_INVALIDARG); 6482 6483 DestroyWindow(hwnd); 6484 } 6485 6486 6487 /* globals that parent and child access when checking event masks & notifications */ 6488 static HWND eventMaskEditHwnd = 0; 6489 static int queriedEventMask; 6490 static int watchForEventMask = 0; 6491 6492 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */ 6493 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6494 { 6495 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16))) 6496 { 6497 queriedEventMask = SendMessageA(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0); 6498 } 6499 return DefWindowProcA(hwnd, message, wParam, lParam); 6500 } 6501 6502 /* test event masks in combination with WM_COMMAND */ 6503 static void test_eventMask(void) 6504 { 6505 HWND parent; 6506 int ret, style; 6507 WNDCLASSA cls; 6508 const char text[] = "foo bar\n"; 6509 int eventMask; 6510 6511 /* register class to capture WM_COMMAND */ 6512 cls.style = 0; 6513 cls.lpfnWndProc = ParentMsgCheckProcA; 6514 cls.cbClsExtra = 0; 6515 cls.cbWndExtra = 0; 6516 cls.hInstance = GetModuleHandleA(0); 6517 cls.hIcon = 0; 6518 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6519 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6520 cls.lpszMenuName = NULL; 6521 cls.lpszClassName = "EventMaskParentClass"; 6522 if(!RegisterClassA(&cls)) assert(0); 6523 6524 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6525 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6526 ok (parent != 0, "Failed to create parent window\n"); 6527 6528 eventMaskEditHwnd = new_richedit(parent); 6529 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n"); 6530 6531 eventMask = ENM_CHANGE | ENM_UPDATE; 6532 ret = SendMessageA(eventMaskEditHwnd, EM_SETEVENTMASK, 0, eventMask); 6533 ok(ret == ENM_NONE, "wrong event mask\n"); 6534 ret = SendMessageA(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0); 6535 ok(ret == eventMask, "failed to set event mask\n"); 6536 6537 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */ 6538 queriedEventMask = 0; /* initialize to something other than we expect */ 6539 watchForEventMask = EN_CHANGE; 6540 ret = SendMessageA(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM)text); 6541 ok(ret == TRUE, "failed to set text\n"); 6542 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE 6543 notification in response to WM_SETTEXT */ 6544 ok(queriedEventMask == (eventMask & ~ENM_CHANGE), 6545 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6546 6547 /* check to see if EN_CHANGE is sent when redraw is turned off */ 6548 SendMessageA(eventMaskEditHwnd, WM_CLEAR, 0, 0); 6549 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6550 SendMessageA(eventMaskEditHwnd, WM_SETREDRAW, FALSE, 0); 6551 /* redraw is disabled by making the window invisible. */ 6552 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); 6553 queriedEventMask = 0; /* initialize to something other than we expect */ 6554 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6555 ok(queriedEventMask == (eventMask & ~ENM_CHANGE), 6556 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6557 SendMessageA(eventMaskEditHwnd, WM_SETREDRAW, TRUE, 0); 6558 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6559 6560 /* check to see if EN_UPDATE is sent when the editor isn't visible */ 6561 SendMessageA(eventMaskEditHwnd, WM_CLEAR, 0, 0); 6562 style = GetWindowLongA(eventMaskEditHwnd, GWL_STYLE); 6563 SetWindowLongA(eventMaskEditHwnd, GWL_STYLE, style & ~WS_VISIBLE); 6564 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); 6565 watchForEventMask = EN_UPDATE; 6566 queriedEventMask = 0; /* initialize to something other than we expect */ 6567 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6568 ok(queriedEventMask == 0, 6569 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6570 SetWindowLongA(eventMaskEditHwnd, GWL_STYLE, style); 6571 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6572 queriedEventMask = 0; /* initialize to something other than we expect */ 6573 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6574 ok(queriedEventMask == eventMask, 6575 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6576 6577 6578 DestroyWindow(parent); 6579 } 6580 6581 static int received_WM_NOTIFY = 0; 6582 static int modify_at_WM_NOTIFY = 0; 6583 static BOOL filter_on_WM_NOTIFY = FALSE; 6584 static HWND hwndRichedit_WM_NOTIFY; 6585 6586 static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6587 { 6588 if(message == WM_NOTIFY) 6589 { 6590 received_WM_NOTIFY = 1; 6591 modify_at_WM_NOTIFY = SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETMODIFY, 0, 0); 6592 if (filter_on_WM_NOTIFY) return TRUE; 6593 } 6594 return DefWindowProcA(hwnd, message, wParam, lParam); 6595 } 6596 6597 static void test_WM_NOTIFY(void) 6598 { 6599 HWND parent; 6600 WNDCLASSA cls; 6601 CHARFORMAT2A cf2; 6602 int sel_start, sel_end; 6603 6604 /* register class to capture WM_NOTIFY */ 6605 cls.style = 0; 6606 cls.lpfnWndProc = WM_NOTIFY_ParentMsgCheckProcA; 6607 cls.cbClsExtra = 0; 6608 cls.cbWndExtra = 0; 6609 cls.hInstance = GetModuleHandleA(0); 6610 cls.hIcon = 0; 6611 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6612 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6613 cls.lpszMenuName = NULL; 6614 cls.lpszClassName = "WM_NOTIFY_ParentClass"; 6615 if(!RegisterClassA(&cls)) assert(0); 6616 6617 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6618 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6619 ok (parent != 0, "Failed to create parent window\n"); 6620 6621 hwndRichedit_WM_NOTIFY = new_richedit(parent); 6622 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n"); 6623 6624 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_SELCHANGE); 6625 6626 /* Notifications for selection change should only be sent when selection 6627 actually changes. EM_SETCHARFORMAT is one message that calls 6628 ME_CommitUndo, which should check whether message should be sent */ 6629 received_WM_NOTIFY = 0; 6630 cf2.cbSize = sizeof(CHARFORMAT2A); 6631 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 6632 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 6633 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 6634 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 6635 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); 6636 6637 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is 6638 already at 0. */ 6639 received_WM_NOTIFY = 0; 6640 modify_at_WM_NOTIFY = 0; 6641 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); 6642 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); 6643 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); 6644 6645 received_WM_NOTIFY = 0; 6646 modify_at_WM_NOTIFY = 0; 6647 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 4, 4); 6648 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6649 6650 received_WM_NOTIFY = 0; 6651 modify_at_WM_NOTIFY = 0; 6652 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); 6653 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6654 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); 6655 6656 /* Test for WM_NOTIFY messages with redraw disabled. */ 6657 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 0, 0); 6658 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, FALSE, 0); 6659 received_WM_NOTIFY = 0; 6660 SendMessageA(hwndRichedit_WM_NOTIFY, EM_REPLACESEL, FALSE, (LPARAM)"inserted"); 6661 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6662 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, TRUE, 0); 6663 6664 /* Test filtering key events. */ 6665 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 0, 0); 6666 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_KEYEVENTS); 6667 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6668 received_WM_NOTIFY = 0; 6669 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6670 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6671 ok(sel_start == 1 && sel_end == 1, 6672 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6673 filter_on_WM_NOTIFY = TRUE; 6674 received_WM_NOTIFY = 0; 6675 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6676 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6677 ok(sel_start == 1 && sel_end == 1, 6678 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6679 6680 /* test with owner set to NULL */ 6681 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY, GWLP_HWNDPARENT, 0); 6682 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6683 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6684 ok(sel_start == 1 && sel_end == 1, 6685 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6686 6687 DestroyWindow(hwndRichedit_WM_NOTIFY); 6688 DestroyWindow(parent); 6689 } 6690 6691 static ENLINK enlink; 6692 #define CURSOR_CLIENT_X 5 6693 #define CURSOR_CLIENT_Y 5 6694 #define WP_PARENT 1 6695 #define WP_CHILD 2 6696 6697 static LRESULT WINAPI EN_LINK_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6698 { 6699 if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == EN_LINK) 6700 { 6701 enlink = *(ENLINK*)lParam; 6702 } 6703 return DefWindowProcA(hwnd, message, wParam, lParam); 6704 } 6705 6706 static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent, 6707 UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies) 6708 { 6709 ENLINK junk_enlink; 6710 6711 switch (msg) 6712 { 6713 case WM_LBUTTONDBLCLK: 6714 case WM_LBUTTONDOWN: 6715 case WM_LBUTTONUP: 6716 case WM_MOUSEHOVER: 6717 case WM_MOUSEMOVE: 6718 case WM_MOUSEWHEEL: 6719 case WM_RBUTTONDBLCLK: 6720 case WM_RBUTTONDOWN: 6721 case WM_RBUTTONUP: 6722 lParam = MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y); 6723 break; 6724 case WM_SETCURSOR: 6725 if (wParam == WP_PARENT) 6726 wParam = (WPARAM)parent; 6727 else if (wParam == WP_CHILD) 6728 wParam = (WPARAM)hwnd; 6729 break; 6730 } 6731 6732 memset(&junk_enlink, 0x23, sizeof(junk_enlink)); 6733 enlink = junk_enlink; 6734 6735 SendMessageA(hwnd, msg, wParam, lParam); 6736 6737 if (notifies) 6738 { 6739 ok(enlink.nmhdr.hwndFrom == hwnd, 6740 "%s test %i: Expected hwnd %p got %p\n", desc, i, hwnd, enlink.nmhdr.hwndFrom); 6741 ok(enlink.nmhdr.idFrom == 0, 6742 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc, i, enlink.nmhdr.idFrom); 6743 ok(enlink.msg == msg, 6744 "%s test %i: Expected msg 0x%x got 0x%x\n", desc, i, msg, enlink.msg); 6745 if (msg == WM_SETCURSOR) 6746 { 6747 ok(enlink.wParam == 0, 6748 "%s test %i: Expected wParam 0 got 0x%lx\n", desc, i, enlink.wParam); 6749 } 6750 else 6751 { 6752 ok(enlink.wParam == wParam, 6753 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc, i, wParam, enlink.wParam); 6754 } 6755 ok(enlink.lParam == MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y), 6756 "%s test %i: Expected lParam 0x%lx got 0x%lx\n", 6757 desc, i, MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y), enlink.lParam); 6758 ok(enlink.chrg.cpMin == 0 && enlink.chrg.cpMax == 31, 6759 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc, i, enlink.chrg.cpMin, enlink.chrg.cpMax); 6760 } 6761 else 6762 { 6763 ok(memcmp(&enlink, &junk_enlink, sizeof(enlink)) == 0, 6764 "%s test %i: Expected enlink to remain unmodified\n", desc, i); 6765 } 6766 } 6767 6768 static void test_EN_LINK(void) 6769 { 6770 HWND hwnd, parent; 6771 WNDCLASSA cls; 6772 CHARFORMAT2A cf2; 6773 POINT orig_cursor_pos; 6774 POINT cursor_screen_pos = {CURSOR_CLIENT_X, CURSOR_CLIENT_Y}; 6775 int i; 6776 6777 static const struct 6778 { 6779 UINT msg; 6780 WPARAM wParam; 6781 LPARAM lParam; 6782 BOOL notifies; 6783 } 6784 link_notify_tests[] = 6785 { 6786 /* hold down the left button and try some messages */ 6787 { WM_LBUTTONDOWN, 0, 0, TRUE }, /* 0 */ 6788 { EM_LINESCROLL, 0, 1, FALSE }, 6789 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6790 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6791 { WM_MOUSEHOVER, 0, 0, FALSE }, 6792 { WM_MOUSEMOVE, 0, 0, FALSE }, 6793 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6794 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6795 { WM_RBUTTONDOWN, 0, 0, TRUE }, 6796 { WM_RBUTTONUP, 0, 0, TRUE }, 6797 { WM_SETCURSOR, 0, 0, FALSE }, 6798 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6799 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6800 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6801 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }, 6802 { WM_LBUTTONUP, 0, 0, TRUE }, 6803 /* hold down the right button and try some messages */ 6804 { WM_RBUTTONDOWN, 0, 0, TRUE }, /* 16 */ 6805 { EM_LINESCROLL, 0, 1, FALSE }, 6806 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6807 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6808 { WM_LBUTTONDOWN, 0, 0, TRUE }, 6809 { WM_LBUTTONUP, 0, 0, TRUE }, 6810 { WM_MOUSEHOVER, 0, 0, FALSE }, 6811 { WM_MOUSEMOVE, 0, 0, TRUE }, 6812 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6813 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6814 { WM_SETCURSOR, 0, 0, FALSE }, 6815 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6816 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6817 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6818 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }, 6819 { WM_RBUTTONUP, 0, 0, TRUE }, 6820 /* try the messages with both buttons released */ 6821 { EM_LINESCROLL, 0, 1, FALSE }, /* 32 */ 6822 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6823 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6824 { WM_LBUTTONDOWN, 0, 0, TRUE }, 6825 { WM_LBUTTONUP, 0, 0, TRUE }, 6826 { WM_MOUSEHOVER, 0, 0, FALSE }, 6827 { WM_MOUSEMOVE, 0, 0, TRUE }, 6828 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6829 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6830 { WM_RBUTTONDOWN, 0, 0, TRUE }, 6831 { WM_RBUTTONUP, 0, 0, TRUE }, 6832 { WM_SETCURSOR, 0, 0, FALSE }, 6833 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6834 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6835 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6836 { WM_VSCROLL, SB_BOTTOM, 0, FALSE } 6837 }; 6838 6839 /* register class to capture WM_NOTIFY */ 6840 cls.style = 0; 6841 cls.lpfnWndProc = EN_LINK_ParentMsgCheckProcA; 6842 cls.cbClsExtra = 0; 6843 cls.cbWndExtra = 0; 6844 cls.hInstance = GetModuleHandleA(0); 6845 cls.hIcon = 0; 6846 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6847 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6848 cls.lpszMenuName = NULL; 6849 cls.lpszClassName = "EN_LINK_ParentClass"; 6850 if(!RegisterClassA(&cls)) assert(0); 6851 6852 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6853 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6854 ok(parent != 0, "Failed to create parent window\n"); 6855 6856 hwnd = new_richedit(parent); 6857 ok(hwnd != 0, "Failed to create edit window\n"); 6858 6859 SendMessageA(hwnd, EM_SETEVENTMASK, 0, ENM_LINK); 6860 6861 cf2.cbSize = sizeof(CHARFORMAT2A); 6862 cf2.dwMask = CFM_LINK; 6863 cf2.dwEffects = CFE_LINK; 6864 SendMessageA(hwnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 6865 /* mixing letters and numbers causes runs to be split */ 6866 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"link text with at least 2 runs"); 6867 6868 GetCursorPos(&orig_cursor_pos); 6869 SetCursorPos(0, 0); 6870 6871 for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) 6872 { 6873 link_notify_test("cursor position simulated", i, hwnd, parent, 6874 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, 6875 link_notify_tests[i].msg == WM_SETCURSOR ? FALSE : link_notify_tests[i].notifies); 6876 } 6877 6878 ClientToScreen(hwnd, &cursor_screen_pos); 6879 SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y); 6880 6881 for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) 6882 { 6883 link_notify_test("cursor position set", i, hwnd, parent, 6884 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, 6885 link_notify_tests[i].notifies); 6886 } 6887 6888 SetCursorPos(orig_cursor_pos.x, orig_cursor_pos.y); 6889 DestroyWindow(hwnd); 6890 DestroyWindow(parent); 6891 } 6892 6893 static void test_undo_coalescing(void) 6894 { 6895 HWND hwnd; 6896 int result; 6897 char buffer[64] = {0}; 6898 6899 /* multi-line control inserts CR normally */ 6900 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE, 6901 0, 0, 200, 60, 0, 0, 0, 0); 6902 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6903 6904 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6905 ok (result == FALSE, "Can undo after window creation.\n"); 6906 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6907 ok (result == FALSE, "Undo operation successful with nothing to undo.\n"); 6908 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6909 ok (result == FALSE, "Can redo after window creation.\n"); 6910 result = SendMessageA(hwnd, EM_REDO, 0, 0); 6911 ok (result == FALSE, "Redo operation successful with nothing undone.\n"); 6912 6913 /* Test the effect of arrows keys during typing on undo transactions*/ 6914 simulate_typing_characters(hwnd, "one two three"); 6915 SendMessageA(hwnd, WM_KEYDOWN, VK_RIGHT, 1); 6916 SendMessageA(hwnd, WM_KEYUP, VK_RIGHT, 1); 6917 simulate_typing_characters(hwnd, " four five six"); 6918 6919 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6920 ok (result == FALSE, "Can redo before anything is undone.\n"); 6921 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6922 ok (result == TRUE, "Cannot undo typed characters.\n"); 6923 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6924 ok (result == TRUE, "EM_UNDO Failed to undo typed characters.\n"); 6925 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6926 ok (result == TRUE, "Cannot redo after undo.\n"); 6927 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6928 result = strcmp(buffer, "one two three"); 6929 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 6930 6931 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6932 ok (result == TRUE, "Cannot undo typed characters.\n"); 6933 result = SendMessageA(hwnd, WM_UNDO, 0, 0); 6934 ok (result == TRUE, "Failed to undo typed characters.\n"); 6935 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6936 result = strcmp(buffer, ""); 6937 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 6938 6939 /* Test the effect of focus changes during typing on undo transactions*/ 6940 simulate_typing_characters(hwnd, "one two three"); 6941 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6942 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n"); 6943 SendMessageA(hwnd, WM_KILLFOCUS, 0, 0); 6944 SendMessageA(hwnd, WM_SETFOCUS, 0, 0); 6945 simulate_typing_characters(hwnd, " four five six"); 6946 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6947 ok (result == TRUE, "Failed to undo typed characters.\n"); 6948 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6949 result = strcmp(buffer, "one two three"); 6950 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 6951 6952 /* Test the effect of the back key during typing on undo transactions */ 6953 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6954 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 6955 ok (result == TRUE, "Failed to clear the text.\n"); 6956 simulate_typing_characters(hwnd, "one two threa"); 6957 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6958 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n"); 6959 SendMessageA(hwnd, WM_KEYDOWN, VK_BACK, 1); 6960 SendMessageA(hwnd, WM_KEYUP, VK_BACK, 1); 6961 simulate_typing_characters(hwnd, "e four five six"); 6962 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6963 ok (result == TRUE, "Failed to undo typed characters.\n"); 6964 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6965 result = strcmp(buffer, ""); 6966 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 6967 6968 /* Test the effect of the delete key during typing on undo transactions */ 6969 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6970 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"abcd"); 6971 ok(result == TRUE, "Failed to set the text.\n"); 6972 SendMessageA(hwnd, EM_SETSEL, 1, 1); 6973 SendMessageA(hwnd, WM_KEYDOWN, VK_DELETE, 1); 6974 SendMessageA(hwnd, WM_KEYUP, VK_DELETE, 1); 6975 SendMessageA(hwnd, WM_KEYDOWN, VK_DELETE, 1); 6976 SendMessageA(hwnd, WM_KEYUP, VK_DELETE, 1); 6977 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6978 ok (result == TRUE, "Failed to undo typed characters.\n"); 6979 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6980 result = strcmp(buffer, "acd"); 6981 ok (result == 0, "expected '%s' but got '%s'\n", "acd", buffer); 6982 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6983 ok (result == TRUE, "Failed to undo typed characters.\n"); 6984 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6985 result = strcmp(buffer, "abcd"); 6986 ok (result == 0, "expected '%s' but got '%s'\n", "abcd", buffer); 6987 6988 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/ 6989 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6990 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 6991 ok (result == TRUE, "Failed to clear the text.\n"); 6992 simulate_typing_characters(hwnd, "one two three"); 6993 result = SendMessageA(hwnd, EM_STOPGROUPTYPING, 0, 0); 6994 ok (result == 0, "expected %d but got %d\n", 0, result); 6995 simulate_typing_characters(hwnd, " four five six"); 6996 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6997 ok (result == TRUE, "Failed to undo typed characters.\n"); 6998 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6999 result = strcmp(buffer, "one two three"); 7000 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 7001 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 7002 ok (result == TRUE, "Failed to undo typed characters.\n"); 7003 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 7004 result = strcmp(buffer, ""); 7005 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 7006 7007 DestroyWindow(hwnd); 7008 } 7009 7010 static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code) 7011 { 7012 int length; 7013 7014 /* MSDN lied, length is actually the number of bytes. */ 7015 length = bytes / sizeof(WCHAR); 7016 switch(code) 7017 { 7018 case WB_ISDELIMITER: 7019 return text[pos] == 'X'; 7020 case WB_LEFT: 7021 case WB_MOVEWORDLEFT: 7022 if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7023 return pos-1; 7024 return min(customWordBreakProc(text, pos, bytes, WB_LEFTBREAK)-1, 0); 7025 case WB_LEFTBREAK: 7026 pos--; 7027 while (pos > 0 && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7028 pos--; 7029 return pos; 7030 case WB_RIGHT: 7031 case WB_MOVEWORDRIGHT: 7032 if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7033 return pos+1; 7034 return min(customWordBreakProc(text, pos, bytes, WB_RIGHTBREAK)+1, length); 7035 case WB_RIGHTBREAK: 7036 pos++; 7037 while (pos < length && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7038 pos++; 7039 return pos; 7040 default: 7041 ok(FALSE, "Unexpected code %d\n", code); 7042 break; 7043 } 7044 return 0; 7045 } 7046 7047 static void test_word_movement(void) 7048 { 7049 HWND hwnd; 7050 int result; 7051 int sel_start, sel_end; 7052 const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0}; 7053 7054 /* multi-line control inserts CR normally */ 7055 hwnd = new_richedit(NULL); 7056 7057 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one two three"); 7058 ok (result == TRUE, "Failed to clear the text.\n"); 7059 SendMessageA(hwnd, EM_SETSEL, 0, 0); 7060 /* |one two three */ 7061 7062 send_ctrl_key(hwnd, VK_RIGHT); 7063 /* one |two three */ 7064 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7065 ok(sel_start == sel_end, "Selection should be empty\n"); 7066 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); 7067 7068 send_ctrl_key(hwnd, VK_RIGHT); 7069 /* one two |three */ 7070 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7071 ok(sel_start == sel_end, "Selection should be empty\n"); 7072 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7073 7074 send_ctrl_key(hwnd, VK_LEFT); 7075 /* one |two three */ 7076 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7077 ok(sel_start == sel_end, "Selection should be empty\n"); 7078 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); 7079 7080 send_ctrl_key(hwnd, VK_LEFT); 7081 /* |one two three */ 7082 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7083 ok(sel_start == sel_end, "Selection should be empty\n"); 7084 ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0); 7085 7086 SendMessageA(hwnd, EM_SETSEL, 8, 8); 7087 /* one two | three */ 7088 send_ctrl_key(hwnd, VK_RIGHT); 7089 /* one two |three */ 7090 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7091 ok(sel_start == sel_end, "Selection should be empty\n"); 7092 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7093 7094 SendMessageA(hwnd, EM_SETSEL, 11, 11); 7095 /* one two th|ree */ 7096 send_ctrl_key(hwnd, VK_LEFT); 7097 /* one two |three */ 7098 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7099 ok(sel_start == sel_end, "Selection should be empty\n"); 7100 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7101 7102 /* Test with a custom word break procedure that uses X as the delimiter. */ 7103 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree"); 7104 ok (result == TRUE, "Failed to clear the text.\n"); 7105 SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); 7106 /* |one twoXthree */ 7107 send_ctrl_key(hwnd, VK_RIGHT); 7108 /* one twoX|three */ 7109 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7110 ok(sel_start == sel_end, "Selection should be empty\n"); 7111 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); 7112 7113 DestroyWindow(hwnd); 7114 7115 /* Make sure the behaviour is the same with a unicode richedit window, 7116 * and using unicode functions. */ 7117 7118 hwnd = CreateWindowW(RICHEDIT_CLASS20W, NULL, 7119 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7120 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7121 7122 /* Test with a custom word break procedure that uses X as the delimiter. */ 7123 result = SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW); 7124 ok (result == TRUE, "Failed to clear the text.\n"); 7125 SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); 7126 /* |one twoXthree */ 7127 send_ctrl_key(hwnd, VK_RIGHT); 7128 /* one twoX|three */ 7129 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7130 ok(sel_start == sel_end, "Selection should be empty\n"); 7131 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); 7132 7133 DestroyWindow(hwnd); 7134 } 7135 7136 static void test_EM_CHARFROMPOS(void) 7137 { 7138 HWND hwnd; 7139 int result; 7140 RECT rcClient; 7141 POINTL point; 7142 point.x = 0; 7143 point.y = 40; 7144 7145 /* multi-line control inserts CR normally */ 7146 hwnd = new_richedit(NULL); 7147 result = SendMessageA(hwnd, WM_SETTEXT, 0, 7148 (LPARAM)"one two three four five six seven\reight"); 7149 ok(result == 1, "Expected 1, got %d\n", result); 7150 GetClientRect(hwnd, &rcClient); 7151 7152 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7153 ok(result == 34, "expected character index of 34 but got %d\n", result); 7154 7155 /* Test with points outside the bounds of the richedit control. */ 7156 point.x = -1; 7157 point.y = 40; 7158 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7159 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); 7160 7161 point.x = 1000; 7162 point.y = 0; 7163 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7164 todo_wine ok(result == 33, "expected character index of 33 but got %d\n", result); 7165 7166 point.x = 1000; 7167 point.y = 36; 7168 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7169 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); 7170 7171 point.x = 1000; 7172 point.y = -1; 7173 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7174 todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result); 7175 7176 point.x = 1000; 7177 point.y = rcClient.bottom + 1; 7178 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7179 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); 7180 7181 point.x = 1000; 7182 point.y = rcClient.bottom; 7183 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7184 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); 7185 7186 DestroyWindow(hwnd); 7187 } 7188 7189 static void test_word_wrap(void) 7190 { 7191 HWND hwnd; 7192 POINTL point = {0, 60}; /* This point must be below the first line */ 7193 const char *text = "Must be long enough to test line wrapping"; 7194 DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE; 7195 int res, pos, lines; 7196 7197 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping 7198 * when specified on window creation and set later. */ 7199 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle, 7200 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7201 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7202 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7203 ok(res, "WM_SETTEXT failed.\n"); 7204 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7205 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7206 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7207 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); 7208 7209 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL); 7210 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7211 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7212 DestroyWindow(hwnd); 7213 7214 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle|WS_HSCROLL, 7215 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7216 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7217 7218 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7219 ok(res, "WM_SETTEXT failed.\n"); 7220 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7221 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7222 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7223 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); 7224 7225 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7226 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7227 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7228 DestroyWindow(hwnd); 7229 7230 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle|ES_AUTOHSCROLL, 7231 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7232 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7233 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7234 ok(res, "WM_SETTEXT failed.\n"); 7235 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7236 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7237 7238 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7239 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7240 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7241 DestroyWindow(hwnd); 7242 7243 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, 7244 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL, 7245 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7246 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7247 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7248 ok(res, "WM_SETTEXT failed.\n"); 7249 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7250 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7251 7252 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7253 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7254 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7255 7256 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */ 7257 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 1); 7258 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); 7259 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7260 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7261 7262 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 0); 7263 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); 7264 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7265 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7266 DestroyWindow(hwnd); 7267 7268 /* Test to see if wrapping happens with redraw disabled. */ 7269 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle, 7270 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL); 7271 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7272 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0); 7273 res = SendMessageA(hwnd, EM_REPLACESEL, FALSE, (LPARAM)text); 7274 ok(res, "EM_REPLACESEL failed.\n"); 7275 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7276 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); 7277 MoveWindow(hwnd, 0, 0, 200, 80, FALSE); 7278 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7279 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); 7280 7281 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0); 7282 DestroyWindow(hwnd); 7283 } 7284 7285 static void test_autoscroll(void) 7286 { 7287 HWND hwnd = new_richedit(NULL); 7288 int lines, ret, redraw; 7289 POINT pt; 7290 7291 for (redraw = 0; redraw <= 1; redraw++) { 7292 trace("testing with WM_SETREDRAW=%d\n", redraw); 7293 SendMessageA(hwnd, WM_SETREDRAW, redraw, 0); 7294 SendMessageA(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8"); 7295 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7296 ok(lines == 8, "%d lines instead of 8\n", lines); 7297 ret = SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); 7298 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); 7299 ok(pt.y != 0, "Didn't scroll down after replacing text.\n"); 7300 ret = GetWindowLongA(hwnd, GWL_STYLE); 7301 ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret); 7302 7303 SendMessageA(hwnd, WM_SETTEXT, 0, 0); 7304 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7305 ok(lines == 1, "%d lines instead of 1\n", lines); 7306 ret = SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); 7307 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); 7308 ok(pt.y == 0, "y scroll position is %d after clearing text.\n", pt.y); 7309 ret = GetWindowLongA(hwnd, GWL_STYLE); 7310 ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret); 7311 } 7312 7313 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0); 7314 DestroyWindow(hwnd); 7315 7316 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set 7317 * auto vertical/horizontal scrolling options. */ 7318 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7319 WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL, 7320 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7321 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7322 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7323 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n"); 7324 ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n"); 7325 ret = GetWindowLongA(hwnd, GWL_STYLE); 7326 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); 7327 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); 7328 DestroyWindow(hwnd); 7329 7330 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7331 WS_POPUP|ES_MULTILINE, 7332 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7333 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7334 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7335 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n"); 7336 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n"); 7337 ret = GetWindowLongA(hwnd, GWL_STYLE); 7338 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); 7339 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); 7340 DestroyWindow(hwnd); 7341 } 7342 7343 7344 static void test_format_rect(void) 7345 { 7346 HWND hwnd; 7347 RECT rc, expected, clientRect; 7348 int n; 7349 DWORD options; 7350 7351 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7352 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7353 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7354 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7355 7356 GetClientRect(hwnd, &clientRect); 7357 7358 expected = clientRect; 7359 InflateRect(&expected, -1, 0); 7360 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7361 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7362 wine_dbgstr_rect(&expected)); 7363 7364 for (n = -3; n <= 3; n++) 7365 { 7366 rc = clientRect; 7367 InflateRect(&rc, -n, -n); 7368 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7369 7370 expected = rc; 7371 expected.top = max(0, rc.top); 7372 expected.left = max(0, rc.left); 7373 expected.bottom = min(clientRect.bottom, rc.bottom); 7374 expected.right = min(clientRect.right, rc.right); 7375 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7376 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc), 7377 wine_dbgstr_rect(&expected)); 7378 } 7379 7380 rc = clientRect; 7381 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7382 expected = clientRect; 7383 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7384 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7385 wine_dbgstr_rect(&expected)); 7386 7387 /* Adding the selectionbar adds the selectionbar width to the left side. */ 7388 SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_OR, ECO_SELECTIONBAR); 7389 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7390 ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n"); 7391 expected.left += 8; /* selection bar width */ 7392 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7393 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7394 wine_dbgstr_rect(&expected)); 7395 7396 rc = clientRect; 7397 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7398 expected = clientRect; 7399 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7400 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7401 wine_dbgstr_rect(&expected)); 7402 7403 /* Removing the selectionbar subtracts the selectionbar width from the left side, 7404 * even if the left side is already 0. */ 7405 SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_AND, ~ECO_SELECTIONBAR); 7406 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7407 ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n"); 7408 expected.left -= 8; /* selection bar width */ 7409 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7410 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7411 wine_dbgstr_rect(&expected)); 7412 7413 /* Set the absolute value of the formatting rectangle. */ 7414 rc = clientRect; 7415 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7416 expected = clientRect; 7417 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7418 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc), 7419 wine_dbgstr_rect(&expected)); 7420 7421 /* MSDN documents the EM_SETRECT message as using the rectangle provided in 7422 * LPARAM as being a relative offset when the WPARAM value is 1, but these 7423 * tests show that this isn't true. */ 7424 rc.top = 15; 7425 rc.left = 15; 7426 rc.bottom = clientRect.bottom - 15; 7427 rc.right = clientRect.right - 15; 7428 expected = rc; 7429 SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); 7430 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7431 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7432 wine_dbgstr_rect(&expected)); 7433 7434 /* For some reason it does not limit the values to the client rect with 7435 * a WPARAM value of 1. */ 7436 rc.top = -15; 7437 rc.left = -15; 7438 rc.bottom = clientRect.bottom + 15; 7439 rc.right = clientRect.right + 15; 7440 expected = rc; 7441 SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); 7442 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7443 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7444 wine_dbgstr_rect(&expected)); 7445 7446 /* Reset to default rect and check how the format rect adjusts to window 7447 * resize and how it copes with very small windows */ 7448 SendMessageA(hwnd, EM_SETRECT, 0, 0); 7449 7450 MoveWindow(hwnd, 0, 0, 100, 30, FALSE); 7451 GetClientRect(hwnd, &clientRect); 7452 7453 expected = clientRect; 7454 InflateRect(&expected, -1, 0); 7455 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7456 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7457 wine_dbgstr_rect(&expected)); 7458 7459 MoveWindow(hwnd, 0, 0, 0, 30, FALSE); 7460 GetClientRect(hwnd, &clientRect); 7461 7462 expected = clientRect; 7463 InflateRect(&expected, -1, 0); 7464 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7465 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7466 wine_dbgstr_rect(&expected)); 7467 7468 MoveWindow(hwnd, 0, 0, 100, 0, FALSE); 7469 GetClientRect(hwnd, &clientRect); 7470 7471 expected = clientRect; 7472 InflateRect(&expected, -1, 0); 7473 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7474 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7475 wine_dbgstr_rect(&expected)); 7476 7477 DestroyWindow(hwnd); 7478 7479 /* The extended window style affects the formatting rectangle. */ 7480 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, RICHEDIT_CLASS20A, NULL, 7481 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7482 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7483 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7484 7485 GetClientRect(hwnd, &clientRect); 7486 7487 expected = clientRect; 7488 expected.top += 1; 7489 InflateRect(&expected, -1, 0); 7490 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7491 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7492 wine_dbgstr_rect(&expected)); 7493 7494 rc = clientRect; 7495 InflateRect(&rc, -5, -5); 7496 expected = rc; 7497 expected.top -= 1; 7498 InflateRect(&expected, 1, 0); 7499 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7500 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7501 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7502 wine_dbgstr_rect(&expected)); 7503 7504 DestroyWindow(hwnd); 7505 } 7506 7507 static void test_WM_GETDLGCODE(void) 7508 { 7509 HWND hwnd; 7510 UINT res, expected; 7511 MSG msg; 7512 7513 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7514 7515 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7516 ES_MULTILINE|ES_WANTRETURN|WS_POPUP, 7517 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7518 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7519 msg.hwnd = hwnd; 7520 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, 0); 7521 expected = expected | DLGC_WANTMESSAGE; 7522 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7523 res, expected); 7524 DestroyWindow(hwnd); 7525 7526 msg.message = WM_KEYDOWN; 7527 msg.wParam = VK_RETURN; 7528 msg.lParam = (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x0001; 7529 msg.pt.x = 0; 7530 msg.pt.y = 0; 7531 msg.time = GetTickCount(); 7532 7533 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7534 ES_MULTILINE|ES_WANTRETURN|WS_POPUP, 7535 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7536 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7537 msg.hwnd = hwnd; 7538 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7539 expected = expected | DLGC_WANTMESSAGE; 7540 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7541 res, expected); 7542 DestroyWindow(hwnd); 7543 7544 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7545 ES_MULTILINE|WS_POPUP, 7546 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7547 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7548 msg.hwnd = hwnd; 7549 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7550 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7551 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7552 res, expected); 7553 DestroyWindow(hwnd); 7554 7555 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7556 ES_WANTRETURN|WS_POPUP, 7557 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7558 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7559 msg.hwnd = hwnd; 7560 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7561 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7562 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7563 res, expected); 7564 DestroyWindow(hwnd); 7565 7566 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7567 WS_POPUP, 7568 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7569 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7570 msg.hwnd = hwnd; 7571 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7572 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7573 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7574 res, expected); 7575 DestroyWindow(hwnd); 7576 7577 msg.wParam = VK_TAB; 7578 msg.lParam = (MapVirtualKeyA(VK_TAB, MAPVK_VK_TO_VSC) << 16) | 0x0001; 7579 7580 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7581 ES_MULTILINE|WS_POPUP, 7582 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7583 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7584 msg.hwnd = hwnd; 7585 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7586 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7587 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7588 res, expected); 7589 DestroyWindow(hwnd); 7590 7591 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7592 WS_POPUP, 7593 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7594 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7595 msg.hwnd = hwnd; 7596 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7597 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7598 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7599 res, expected); 7600 DestroyWindow(hwnd); 7601 7602 hold_key(VK_CONTROL); 7603 7604 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7605 ES_MULTILINE|WS_POPUP, 7606 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7607 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7608 msg.hwnd = hwnd; 7609 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7610 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7611 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7612 res, expected); 7613 DestroyWindow(hwnd); 7614 7615 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7616 WS_POPUP, 7617 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7618 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7619 msg.hwnd = hwnd; 7620 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7621 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7622 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7623 res, expected); 7624 DestroyWindow(hwnd); 7625 7626 release_key(VK_CONTROL); 7627 7628 msg.wParam = 'a'; 7629 msg.lParam = (MapVirtualKeyA('a', MAPVK_VK_TO_VSC) << 16) | 0x0001; 7630 7631 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7632 ES_MULTILINE|WS_POPUP, 7633 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7634 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7635 msg.hwnd = hwnd; 7636 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7637 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7638 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7639 res, expected); 7640 DestroyWindow(hwnd); 7641 7642 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7643 WS_POPUP, 7644 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7645 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7646 msg.hwnd = hwnd; 7647 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7648 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7649 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7650 res, expected); 7651 DestroyWindow(hwnd); 7652 7653 msg.message = WM_CHAR; 7654 7655 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7656 ES_MULTILINE|WS_POPUP, 7657 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7658 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7659 msg.hwnd = hwnd; 7660 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7661 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7662 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7663 res, expected); 7664 DestroyWindow(hwnd); 7665 7666 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7667 WS_POPUP, 7668 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7669 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7670 msg.hwnd = hwnd; 7671 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7672 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7673 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7674 res, expected); 7675 DestroyWindow(hwnd); 7676 7677 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7678 WS_POPUP|ES_SAVESEL, 7679 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7680 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7681 res = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); 7682 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS; 7683 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7684 res, expected); 7685 DestroyWindow(hwnd); 7686 } 7687 7688 static void test_zoom(void) 7689 { 7690 HWND hwnd; 7691 UINT ret; 7692 RECT rc; 7693 POINT pt; 7694 int numerator, denominator; 7695 7696 hwnd = new_richedit(NULL); 7697 GetClientRect(hwnd, &rc); 7698 pt.x = (rc.right - rc.left) / 2; 7699 pt.y = (rc.bottom - rc.top) / 2; 7700 ClientToScreen(hwnd, &pt); 7701 7702 /* Test initial zoom value */ 7703 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7704 ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator); 7705 ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator); 7706 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7707 7708 /* test scroll wheel */ 7709 hold_key(VK_CONTROL); 7710 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7711 MAKELPARAM(pt.x, pt.y)); 7712 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7713 release_key(VK_CONTROL); 7714 7715 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7716 ok(numerator == 110, "incorrect numerator is %d\n", numerator); 7717 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7718 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7719 7720 /* Test how much the mouse wheel can zoom in and out. */ 7721 ret = SendMessageA(hwnd, EM_SETZOOM, 490, 100); 7722 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7723 7724 hold_key(VK_CONTROL); 7725 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7726 MAKELPARAM(pt.x, pt.y)); 7727 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7728 release_key(VK_CONTROL); 7729 7730 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7731 ok(numerator == 500, "incorrect numerator is %d\n", numerator); 7732 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7733 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7734 7735 ret = SendMessageA(hwnd, EM_SETZOOM, 491, 100); 7736 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7737 7738 hold_key(VK_CONTROL); 7739 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7740 MAKELPARAM(pt.x, pt.y)); 7741 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7742 release_key(VK_CONTROL); 7743 7744 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7745 ok(numerator == 491, "incorrect numerator is %d\n", numerator); 7746 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7747 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7748 7749 ret = SendMessageA(hwnd, EM_SETZOOM, 20, 100); 7750 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7751 7752 hold_key(VK_CONTROL); 7753 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), 7754 MAKELPARAM(pt.x, pt.y)); 7755 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7756 release_key(VK_CONTROL); 7757 7758 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7759 ok(numerator == 10, "incorrect numerator is %d\n", numerator); 7760 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7761 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7762 7763 ret = SendMessageA(hwnd, EM_SETZOOM, 19, 100); 7764 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7765 7766 hold_key(VK_CONTROL); 7767 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), 7768 MAKELPARAM(pt.x, pt.y)); 7769 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7770 release_key(VK_CONTROL); 7771 7772 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7773 ok(numerator == 19, "incorrect numerator is %d\n", numerator); 7774 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7775 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7776 7777 /* Test how WM_SCROLLWHEEL treats our custom denominator. */ 7778 ret = SendMessageA(hwnd, EM_SETZOOM, 50, 13); 7779 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7780 7781 hold_key(VK_CONTROL); 7782 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7783 MAKELPARAM(pt.x, pt.y)); 7784 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7785 release_key(VK_CONTROL); 7786 7787 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7788 ok(numerator == 394, "incorrect numerator is %d\n", numerator); 7789 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7790 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7791 7792 /* Test bounds checking on EM_SETZOOM */ 7793 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 127); 7794 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); 7795 7796 ret = SendMessageA(hwnd, EM_SETZOOM, 127, 2); 7797 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); 7798 7799 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 128); 7800 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7801 7802 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7803 ok(numerator == 127, "incorrect numerator is %d\n", numerator); 7804 ok(denominator == 2, "incorrect denominator is %d\n", denominator); 7805 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7806 7807 ret = SendMessageA(hwnd, EM_SETZOOM, 128, 2); 7808 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7809 7810 /* See if negative numbers are accepted. */ 7811 ret = SendMessageA(hwnd, EM_SETZOOM, -100, -100); 7812 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7813 7814 /* See if negative numbers are accepted. */ 7815 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 100); 7816 ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret); 7817 7818 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7819 ok(numerator == 127, "incorrect numerator is %d\n", numerator); 7820 ok(denominator == 2, "incorrect denominator is %d\n", denominator); 7821 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7822 7823 /* Reset the zoom value */ 7824 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 0); 7825 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7826 7827 DestroyWindow(hwnd); 7828 } 7829 7830 struct dialog_mode_messages 7831 { 7832 int wm_getdefid, wm_close, wm_nextdlgctl; 7833 }; 7834 7835 static struct dialog_mode_messages dm_messages; 7836 7837 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \ 7838 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \ 7839 "got %d\n", wmclose, dm_messages.wm_close); \ 7840 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \ 7841 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\ 7842 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \ 7843 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl) 7844 7845 static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 7846 { 7847 switch (iMsg) 7848 { 7849 case DM_GETDEFID: 7850 dm_messages.wm_getdefid++; 7851 return MAKELONG(ID_RICHEDITTESTDBUTTON, DC_HASDEFID); 7852 case WM_NEXTDLGCTL: 7853 dm_messages.wm_nextdlgctl++; 7854 break; 7855 case WM_CLOSE: 7856 dm_messages.wm_close++; 7857 break; 7858 } 7859 7860 return DefWindowProcA(hwnd, iMsg, wParam, lParam); 7861 } 7862 7863 static void test_dialogmode(void) 7864 { 7865 HWND hwRichEdit, hwParent, hwButton; 7866 MSG msg= {0}; 7867 int lcount, r; 7868 WNDCLASSA cls; 7869 7870 cls.style = 0; 7871 cls.lpfnWndProc = dialog_mode_wnd_proc; 7872 cls.cbClsExtra = 0; 7873 cls.cbWndExtra = 0; 7874 cls.hInstance = GetModuleHandleA(0); 7875 cls.hIcon = 0; 7876 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 7877 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 7878 cls.lpszMenuName = NULL; 7879 cls.lpszClassName = "DialogModeParentClass"; 7880 if(!RegisterClassA(&cls)) assert(0); 7881 7882 hwParent = CreateWindowA("DialogModeParentClass", NULL, WS_OVERLAPPEDWINDOW, 7883 CW_USEDEFAULT, 0, 200, 120, NULL, NULL, GetModuleHandleA(0), NULL); 7884 7885 /* Test richedit(ES_MULTILINE) */ 7886 7887 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7888 7889 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7890 ok(0 == r, "expected 0, got %d\n", r); 7891 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7892 ok(2 == lcount, "expected 2, got %d\n", lcount); 7893 7894 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, 0); 7895 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7896 7897 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7898 ok(0 == r, "expected 0, got %d\n", r); 7899 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7900 ok(3 == lcount, "expected 3, got %d\n", lcount); 7901 7902 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7903 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7904 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7905 ok(0 == r, "expected 0, got %d\n", r); 7906 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7907 ok(3 == lcount, "expected 3, got %d\n", lcount); 7908 7909 DestroyWindow(hwRichEdit); 7910 7911 /* Test standalone richedit(ES_MULTILINE) */ 7912 7913 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, NULL); 7914 7915 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7916 ok(0 == r, "expected 0, got %d\n", r); 7917 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7918 ok(2 == lcount, "expected 2, got %d\n", lcount); 7919 7920 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7921 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7922 7923 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7924 ok(0 == r, "expected 0, got %d\n", r); 7925 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7926 ok(2 == lcount, "expected 2, got %d\n", lcount); 7927 7928 DestroyWindow(hwRichEdit); 7929 7930 /* Check a destination for messages */ 7931 7932 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7933 7934 SetWindowLongA(hwRichEdit, GWL_STYLE, GetWindowLongA(hwRichEdit, GWL_STYLE)& ~WS_POPUP); 7935 SetParent( hwRichEdit, NULL); 7936 7937 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7938 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7939 7940 memset(&dm_messages, 0, sizeof(dm_messages)); 7941 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7942 ok(0 == r, "expected 0, got %d\n", r); 7943 test_dm_messages(0, 1, 0); 7944 7945 memset(&dm_messages, 0, sizeof(dm_messages)); 7946 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7947 ok(0 == r, "expected 0, got %d\n", r); 7948 test_dm_messages(0, 0, 1); 7949 7950 DestroyWindow(hwRichEdit); 7951 7952 /* Check messages from richedit(ES_MULTILINE) */ 7953 7954 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7955 7956 memset(&dm_messages, 0, sizeof(dm_messages)); 7957 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7958 ok(0 == r, "expected 0, got %d\n", r); 7959 test_dm_messages(0, 0, 0); 7960 7961 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7962 ok(2 == lcount, "expected 2, got %d\n", lcount); 7963 7964 memset(&dm_messages, 0, sizeof(dm_messages)); 7965 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 7966 ok(0 == r, "expected 0, got %d\n", r); 7967 test_dm_messages(0, 0, 0); 7968 7969 memset(&dm_messages, 0, sizeof(dm_messages)); 7970 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7971 ok(0 == r, "expected 0, got %d\n", r); 7972 test_dm_messages(0, 0, 0); 7973 7974 memset(&dm_messages, 0, sizeof(dm_messages)); 7975 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7976 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7977 test_dm_messages(0, 0, 0); 7978 7979 memset(&dm_messages, 0, sizeof(dm_messages)); 7980 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7981 ok(0 == r, "expected 0, got %d\n", r); 7982 test_dm_messages(0, 1, 0); 7983 7984 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7985 ok(2 == lcount, "expected 2, got %d\n", lcount); 7986 7987 memset(&dm_messages, 0, sizeof(dm_messages)); 7988 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 7989 ok(0 == r, "expected 0, got %d\n", r); 7990 test_dm_messages(0, 0, 0); 7991 7992 memset(&dm_messages, 0, sizeof(dm_messages)); 7993 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7994 ok(0 == r, "expected 0, got %d\n", r); 7995 test_dm_messages(0, 0, 1); 7996 7997 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 7998 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 7999 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8000 8001 memset(&dm_messages, 0, sizeof(dm_messages)); 8002 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8003 ok(0 == r, "expected 0, got %d\n", r); 8004 test_dm_messages(0, 1, 1); 8005 8006 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8007 ok(2 == lcount, "expected 2, got %d\n", lcount); 8008 8009 DestroyWindow(hwButton); 8010 DestroyWindow(hwRichEdit); 8011 8012 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */ 8013 8014 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_WANTRETURN, hwParent); 8015 8016 memset(&dm_messages, 0, sizeof(dm_messages)); 8017 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8018 ok(0 == r, "expected 0, got %d\n", r); 8019 test_dm_messages(0, 0, 0); 8020 8021 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8022 ok(2 == lcount, "expected 2, got %d\n", lcount); 8023 8024 memset(&dm_messages, 0, sizeof(dm_messages)); 8025 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8026 ok(0 == r, "expected 0, got %d\n", r); 8027 test_dm_messages(0, 0, 0); 8028 8029 memset(&dm_messages, 0, sizeof(dm_messages)); 8030 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8031 ok(0 == r, "expected 0, got %d\n", r); 8032 test_dm_messages(0, 0, 0); 8033 8034 memset(&dm_messages, 0, sizeof(dm_messages)); 8035 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8036 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 8037 test_dm_messages(0, 0, 0); 8038 8039 memset(&dm_messages, 0, sizeof(dm_messages)); 8040 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8041 ok(0 == r, "expected 0, got %d\n", r); 8042 test_dm_messages(0, 0, 0); 8043 8044 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8045 ok(3 == lcount, "expected 3, got %d\n", lcount); 8046 8047 memset(&dm_messages, 0, sizeof(dm_messages)); 8048 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8049 ok(0 == r, "expected 0, got %d\n", r); 8050 test_dm_messages(0, 0, 0); 8051 8052 memset(&dm_messages, 0, sizeof(dm_messages)); 8053 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8054 ok(0 == r, "expected 0, got %d\n", r); 8055 test_dm_messages(0, 0, 1); 8056 8057 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8058 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8059 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8060 8061 memset(&dm_messages, 0, sizeof(dm_messages)); 8062 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8063 ok(0 == r, "expected 0, got %d\n", r); 8064 test_dm_messages(0, 0, 0); 8065 8066 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8067 ok(4 == lcount, "expected 4, got %d\n", lcount); 8068 8069 DestroyWindow(hwButton); 8070 DestroyWindow(hwRichEdit); 8071 8072 /* Check messages from richedit(0) */ 8073 8074 hwRichEdit = new_window(RICHEDIT_CLASS20A, 0, hwParent); 8075 8076 memset(&dm_messages, 0, sizeof(dm_messages)); 8077 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8078 ok(0 == r, "expected 0, got %d\n", r); 8079 test_dm_messages(0, 0, 0); 8080 8081 memset(&dm_messages, 0, sizeof(dm_messages)); 8082 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8083 ok(0 == r, "expected 0, got %d\n", r); 8084 test_dm_messages(0, 0, 0); 8085 8086 memset(&dm_messages, 0, sizeof(dm_messages)); 8087 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8088 ok(0 == r, "expected 0, got %d\n", r); 8089 test_dm_messages(0, 0, 0); 8090 8091 memset(&dm_messages, 0, sizeof(dm_messages)); 8092 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8093 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r); 8094 test_dm_messages(0, 0, 0); 8095 8096 memset(&dm_messages, 0, sizeof(dm_messages)); 8097 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8098 ok(0 == r, "expected 0, got %d\n", r); 8099 test_dm_messages(0, 1, 0); 8100 8101 memset(&dm_messages, 0, sizeof(dm_messages)); 8102 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8103 ok(0 == r, "expected 0, got %d\n", r); 8104 test_dm_messages(0, 0, 0); 8105 8106 memset(&dm_messages, 0, sizeof(dm_messages)); 8107 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8108 ok(0 == r, "expected 0, got %d\n", r); 8109 test_dm_messages(0, 0, 1); 8110 8111 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8112 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8113 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8114 8115 memset(&dm_messages, 0, sizeof(dm_messages)); 8116 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8117 ok(0 == r, "expected 0, got %d\n", r); 8118 test_dm_messages(0, 1, 1); 8119 8120 DestroyWindow(hwRichEdit); 8121 8122 /* Check messages from richedit(ES_WANTRETURN) */ 8123 8124 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_WANTRETURN, hwParent); 8125 8126 memset(&dm_messages, 0, sizeof(dm_messages)); 8127 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8128 ok(0 == r, "expected 0, got %d\n", r); 8129 test_dm_messages(0, 0, 0); 8130 8131 memset(&dm_messages, 0, sizeof(dm_messages)); 8132 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8133 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r); 8134 test_dm_messages(0, 0, 0); 8135 8136 memset(&dm_messages, 0, sizeof(dm_messages)); 8137 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8138 ok(0 == r, "expected 0, got %d\n", r); 8139 test_dm_messages(0, 0, 0); 8140 8141 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8142 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8143 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8144 8145 memset(&dm_messages, 0, sizeof(dm_messages)); 8146 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8147 ok(0 == r, "expected 0, got %d\n", r); 8148 test_dm_messages(0, 0, 0); 8149 8150 DestroyWindow(hwRichEdit); 8151 DestroyWindow(hwParent); 8152 } 8153 8154 static void test_EM_FINDWORDBREAK_W(void) 8155 { 8156 static const struct { 8157 WCHAR c; 8158 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */ 8159 } delimiter_tests[] = { 8160 {0x0a, FALSE}, /* newline */ 8161 {0x0b, FALSE}, /* vertical tab */ 8162 {0x0c, FALSE}, /* form feed */ 8163 {0x0d, FALSE}, /* carriage return */ 8164 {0x20, TRUE}, /* space */ 8165 {0x61, FALSE}, /* capital letter a */ 8166 {0xa0, FALSE}, /* no-break space */ 8167 {0x2000, FALSE}, /* en quad */ 8168 {0x3000, FALSE}, /* Ideographic space */ 8169 {0x1100, FALSE}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/ 8170 {0x11ff, FALSE}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/ 8171 {0x115f, FALSE}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */ 8172 {0xac00, FALSE}, /* Hangul character GA*/ 8173 {0xd7af, FALSE}, /* End of Hangul character chart */ 8174 {0xf020, TRUE}, /* MS private for CP_SYMBOL round trip?, see kb897872 */ 8175 {0xff20, FALSE}, /* fullwidth commercial @ */ 8176 {WCH_EMBEDDING, FALSE}, /* object replacement character*/ 8177 }; 8178 int i; 8179 HWND hwndRichEdit = new_richeditW(NULL); 8180 ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n"); 8181 for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) 8182 { 8183 WCHAR wbuf[2]; 8184 int result; 8185 8186 wbuf[0] = delimiter_tests[i].c; 8187 wbuf[1] = 0; 8188 SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)wbuf); 8189 result = SendMessageW(hwndRichEdit, EM_FINDWORDBREAK, WB_ISDELIMITER,0); 8190 todo_wine_if (wbuf[0] == 0x20 || wbuf[0] == 0xf020) 8191 ok(result == delimiter_tests[i].isdelimiter, 8192 "wanted ISDELIMITER_W(0x%x) %d, got %d\n", 8193 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result); 8194 } 8195 DestroyWindow(hwndRichEdit); 8196 } 8197 8198 static void test_EM_FINDWORDBREAK_A(void) 8199 { 8200 static const struct { 8201 WCHAR c; 8202 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */ 8203 } delimiter_tests[] = { 8204 {0x0a, FALSE}, /* newline */ 8205 {0x0b, FALSE}, /* vertical tab */ 8206 {0x0c, FALSE}, /* form feed */ 8207 {0x0d, FALSE}, /* carriage return */ 8208 {0x20, TRUE}, /* space */ 8209 {0x61, FALSE}, /* capital letter a */ 8210 }; 8211 int i; 8212 HWND hwndRichEdit = new_richedit(NULL); 8213 8214 ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n"); 8215 for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) 8216 { 8217 int result; 8218 char buf[2]; 8219 buf[0] = delimiter_tests[i].c; 8220 buf[1] = 0; 8221 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buf); 8222 result = SendMessageA(hwndRichEdit, EM_FINDWORDBREAK, WB_ISDELIMITER, 0); 8223 todo_wine_if (buf[0] == 0x20) 8224 ok(result == delimiter_tests[i].isdelimiter, 8225 "wanted ISDELIMITER_A(0x%x) %d, got %d\n", 8226 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result); 8227 } 8228 DestroyWindow(hwndRichEdit); 8229 } 8230 8231 /* 8232 * This test attempts to show the effect of enter on a richedit 8233 * control v1.0 inserts CRLF whereas for higher versions it only 8234 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT 8235 * and also shows that GT_USECRLF has no effect in richedit 1.0, but 8236 * does for higher. The same test is cloned in riched32 and riched20. 8237 */ 8238 static void test_enter(void) 8239 { 8240 static const struct { 8241 const char *initialtext; 8242 const int cursor; 8243 const char *expectedwmtext; 8244 const char *expectedemtext; 8245 const char *expectedemtextcrlf; 8246 } testenteritems[] = { 8247 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"}, 8248 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"}, 8249 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"}, 8250 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}, 8251 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"} 8252 }; 8253 8254 char expectedbuf[1024]; 8255 char resultbuf[1024]; 8256 HWND hwndRichEdit = new_richedit(NULL); 8257 UINT i,j; 8258 8259 for (i = 0; i < sizeof(testenteritems)/sizeof(testenteritems[0]); i++) { 8260 8261 char buf[1024] = {0}; 8262 LRESULT result; 8263 GETTEXTEX getText; 8264 const char *expected; 8265 8266 /* Set the text to the initial text */ 8267 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext); 8268 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result); 8269 8270 /* Send Enter */ 8271 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor); 8272 simulate_typing_characters(hwndRichEdit, "\r"); 8273 8274 /* 1. Retrieve with WM_GETTEXT */ 8275 buf[0] = 0x00; 8276 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 8277 expected = testenteritems[i].expectedwmtext; 8278 8279 resultbuf[0]=0x00; 8280 for (j = 0; j < (UINT)result; j++) 8281 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8282 expectedbuf[0] = '\0'; 8283 for (j = 0; j < strlen(expected); j++) 8284 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8285 8286 result = strcmp(expected, buf); 8287 ok (result == 0, 8288 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n", 8289 i, resultbuf, expectedbuf); 8290 8291 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */ 8292 getText.cb = sizeof(buf); 8293 getText.flags = GT_DEFAULT; 8294 getText.codepage = CP_ACP; 8295 getText.lpDefaultChar = NULL; 8296 getText.lpUsedDefChar = NULL; 8297 buf[0] = 0x00; 8298 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 8299 expected = testenteritems[i].expectedemtext; 8300 8301 resultbuf[0]=0x00; 8302 for (j = 0; j < (UINT)result; j++) 8303 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8304 expectedbuf[0] = '\0'; 8305 for (j = 0; j < strlen(expected); j++) 8306 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8307 8308 result = strcmp(expected, buf); 8309 ok (result == 0, 8310 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", 8311 i, resultbuf, expectedbuf); 8312 8313 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */ 8314 getText.cb = sizeof(buf); 8315 getText.flags = GT_USECRLF; 8316 getText.codepage = CP_ACP; 8317 getText.lpDefaultChar = NULL; 8318 getText.lpUsedDefChar = NULL; 8319 buf[0] = 0x00; 8320 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 8321 expected = testenteritems[i].expectedemtextcrlf; 8322 8323 resultbuf[0]=0x00; 8324 for (j = 0; j < (UINT)result; j++) 8325 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8326 expectedbuf[0] = '\0'; 8327 for (j = 0; j < strlen(expected); j++) 8328 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8329 8330 result = strcmp(expected, buf); 8331 ok (result == 0, 8332 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n", 8333 i, resultbuf, expectedbuf); 8334 } 8335 8336 DestroyWindow(hwndRichEdit); 8337 } 8338 8339 static void test_WM_CREATE(void) 8340 { 8341 static const WCHAR titleW[] = {'l','i','n','e','1','\n','l','i','n','e','2',0}; 8342 static const char title[] = "line1\nline2"; 8343 8344 HWND rich_edit; 8345 LRESULT res; 8346 char buf[64]; 8347 int len; 8348 8349 rich_edit = CreateWindowA(RICHEDIT_CLASS20A, title, WS_POPUP|WS_VISIBLE, 8350 0, 0, 200, 80, NULL, NULL, NULL, NULL); 8351 ok(rich_edit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 8352 8353 len = GetWindowTextA(rich_edit, buf, sizeof(buf)); 8354 ok(len == 5, "GetWindowText returned %d\n", len); 8355 ok(!strcmp(buf, "line1"), "buf = %s\n", buf); 8356 8357 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0); 8358 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res); 8359 8360 DestroyWindow(rich_edit); 8361 8362 rich_edit = CreateWindowW(RICHEDIT_CLASS20W, titleW, WS_POPUP|WS_VISIBLE|ES_MULTILINE, 8363 0, 0, 200, 80, NULL, NULL, NULL, NULL); 8364 ok(rich_edit != NULL, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W), (int) GetLastError()); 8365 8366 len = GetWindowTextA(rich_edit, buf, sizeof(buf)); 8367 ok(len == 12, "GetWindowText returned %d\n", len); 8368 ok(!strcmp(buf, "line1\r\nline2"), "buf = %s\n", buf); 8369 8370 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0); 8371 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res); 8372 8373 DestroyWindow(rich_edit); 8374 } 8375 8376 /******************************************************************* 8377 * Test that after deleting all of the text, the first paragraph 8378 * format reverts to the default. 8379 */ 8380 static void test_reset_default_para_fmt( void ) 8381 { 8382 HWND richedit = new_richeditW( NULL ); 8383 PARAFORMAT2 fmt; 8384 WORD def_align, new_align; 8385 8386 memset( &fmt, 0, sizeof(fmt) ); 8387 fmt.cbSize = sizeof(PARAFORMAT2); 8388 fmt.dwMask = -1; 8389 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8390 def_align = fmt.wAlignment; 8391 new_align = (def_align == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT; 8392 8393 simulate_typing_characters( richedit, "123" ); 8394 8395 SendMessageA( richedit, EM_SETSEL, 0, -1 ); 8396 fmt.dwMask = PFM_ALIGNMENT; 8397 fmt.wAlignment = new_align; 8398 SendMessageA( richedit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt ); 8399 8400 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8401 ok( fmt.wAlignment == new_align, "got %d expect %d\n", fmt.wAlignment, new_align ); 8402 8403 SendMessageA( richedit, EM_SETSEL, 0, -1 ); 8404 SendMessageA( richedit, WM_CUT, 0, 0 ); 8405 8406 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8407 ok( fmt.wAlignment == def_align, "got %d expect %d\n", fmt.wAlignment, def_align ); 8408 8409 DestroyWindow( richedit ); 8410 } 8411 8412 static void test_EM_SETREADONLY(void) 8413 { 8414 HWND richedit = new_richeditW(NULL); 8415 DWORD dwStyle; 8416 LRESULT res; 8417 8418 res = SendMessageA(richedit, EM_SETREADONLY, TRUE, 0); 8419 ok(res == 1, "EM_SETREADONLY\n"); 8420 dwStyle = GetWindowLongA(richedit, GWL_STYLE); 8421 ok(dwStyle & ES_READONLY, "got wrong value: 0x%x\n", dwStyle); 8422 8423 res = SendMessageA(richedit, EM_SETREADONLY, FALSE, 0); 8424 ok(res == 1, "EM_SETREADONLY\n"); 8425 dwStyle = GetWindowLongA(richedit, GWL_STYLE); 8426 ok(!(dwStyle & ES_READONLY), "got wrong value: 0x%x\n", dwStyle); 8427 8428 DestroyWindow(richedit); 8429 } 8430 8431 static inline LONG twips2points(LONG value) 8432 { 8433 return value / 20; 8434 } 8435 8436 #define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \ 8437 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo) 8438 static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size, 8439 LRESULT expected_res, BOOL expected_undo) 8440 { 8441 CHARFORMAT2A cf; 8442 LRESULT res; 8443 BOOL isundo; 8444 8445 cf.cbSize = sizeof(cf); 8446 cf.dwMask = CFM_SIZE; 8447 8448 res = SendMessageA(hwnd, EM_SETFONTSIZE, size, 0); 8449 SendMessageA(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); 8450 isundo = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 8451 ok_(__FILE__,line)(res == expected_res, "EM_SETFONTSIZE unexpected return value: %lx.\n", res); 8452 ok_(__FILE__,line)(twips2points(cf.yHeight) == expected_size, "got wrong font size: %d, expected: %d\n", 8453 twips2points(cf.yHeight), expected_size); 8454 ok_(__FILE__,line)(isundo == expected_undo, "get wrong undo mark: %d, expected: %d.\n", 8455 isundo, expected_undo); 8456 } 8457 8458 static void test_EM_SETFONTSIZE(void) 8459 { 8460 HWND richedit = new_richedit(NULL); 8461 CHAR text[] = "wine"; 8462 CHARFORMAT2A tmp_cf; 8463 LONG default_size; 8464 8465 tmp_cf.cbSize = sizeof(tmp_cf); 8466 tmp_cf.dwMask = CFM_SIZE; 8467 tmp_cf.yHeight = 9 * 20.0; 8468 SendMessageA(richedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf); 8469 8470 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)text); 8471 8472 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0); 8473 /* without selection */ 8474 TEST_EM_SETFONTSIZE(richedit, 1, 10, TRUE, FALSE); /* 9 + 1 -> 10 */ 8475 SendMessageA(richedit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf); 8476 default_size = twips2points(tmp_cf.yHeight); 8477 ok(default_size == 9, "Default font size should not be changed.\n"); 8478 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n"); 8479 8480 SendMessageA(richedit, EM_SETSEL, 0, 2); 8481 8482 TEST_EM_SETFONTSIZE(richedit, 0, 9, TRUE, TRUE); /* 9 + 0 -> 9 */ 8483 8484 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0); 8485 TEST_EM_SETFONTSIZE(richedit, 3, 12, TRUE, TRUE); /* 9 + 3 -> 12 */ 8486 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n"); 8487 8488 TEST_EM_SETFONTSIZE(richedit, 1, 14, TRUE, TRUE); /* 12 + 1 + 1 -> 14 */ 8489 TEST_EM_SETFONTSIZE(richedit, -1, 12, TRUE, TRUE); /* 14 - 1 - 1 -> 12 */ 8490 TEST_EM_SETFONTSIZE(richedit, 4, 16, TRUE, TRUE); /* 12 + 4 -> 16 */ 8491 TEST_EM_SETFONTSIZE(richedit, 3, 20, TRUE, TRUE); /* 16 + 3 + 1 -> 20 */ 8492 TEST_EM_SETFONTSIZE(richedit, 0, 20, TRUE, TRUE); /* 20 + 0 -> 20 */ 8493 TEST_EM_SETFONTSIZE(richedit, 8, 28, TRUE, TRUE); /* 20 + 8 -> 28 */ 8494 TEST_EM_SETFONTSIZE(richedit, 0, 28, TRUE, TRUE); /* 28 + 0 -> 28 */ 8495 TEST_EM_SETFONTSIZE(richedit, 1, 36, TRUE, TRUE); /* 28 + 1 -> 36 */ 8496 TEST_EM_SETFONTSIZE(richedit, 0, 36, TRUE, TRUE); /* 36 + 0 -> 36 */ 8497 TEST_EM_SETFONTSIZE(richedit, 1, 48, TRUE, TRUE); /* 36 + 1 -> 48 */ 8498 TEST_EM_SETFONTSIZE(richedit, 0, 48, TRUE, TRUE); /* 48 + 0 -> 48 */ 8499 TEST_EM_SETFONTSIZE(richedit, 1, 72, TRUE, TRUE); /* 48 + 1 -> 72 */ 8500 TEST_EM_SETFONTSIZE(richedit, 0, 72, TRUE, TRUE); /* 72 + 0 -> 72 */ 8501 TEST_EM_SETFONTSIZE(richedit, 1, 80, TRUE, TRUE); /* 72 + 1 -> 80 */ 8502 TEST_EM_SETFONTSIZE(richedit, 0, 80, TRUE, TRUE); /* 80 + 0 -> 80 */ 8503 TEST_EM_SETFONTSIZE(richedit, 1, 90, TRUE, TRUE); /* 80 + 1 -> 90 */ 8504 TEST_EM_SETFONTSIZE(richedit, 0, 90, TRUE, TRUE); /* 90 + 0 -> 90 */ 8505 TEST_EM_SETFONTSIZE(richedit, 1, 100, TRUE, TRUE); /* 90 + 1 -> 100 */ 8506 TEST_EM_SETFONTSIZE(richedit, 25, 130, TRUE, TRUE); /* 100 + 25 -> 130 */ 8507 TEST_EM_SETFONTSIZE(richedit, -1, 120, TRUE, TRUE); /* 130 - 1 -> 120 */ 8508 TEST_EM_SETFONTSIZE(richedit, -35, 80, TRUE, TRUE); /* 120 - 35 -> 80 */ 8509 TEST_EM_SETFONTSIZE(richedit, -7, 72, TRUE, TRUE); /* 80 - 7 -> 72 */ 8510 TEST_EM_SETFONTSIZE(richedit, -42, 28, TRUE, TRUE); /* 72 - 42 -> 28 */ 8511 TEST_EM_SETFONTSIZE(richedit, -16, 12, TRUE, TRUE); /* 28 - 16 -> 12 */ 8512 TEST_EM_SETFONTSIZE(richedit, -3, 9, TRUE, TRUE); /* 12 - 3 -> 9 */ 8513 TEST_EM_SETFONTSIZE(richedit, -8, 1, TRUE, TRUE); /* 9 - 8 -> 1 */ 8514 TEST_EM_SETFONTSIZE(richedit, -111, 1, TRUE, TRUE); /* 1 - 111 -> 1 */ 8515 TEST_EM_SETFONTSIZE(richedit, 10086, 1638, TRUE, TRUE); /* 1 + 10086 -> 1638 */ 8516 8517 /* return FALSE when richedit is TM_PLAINTEXT mode */ 8518 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)""); 8519 SendMessageA(richedit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 8520 TEST_EM_SETFONTSIZE(richedit, 0, 9, FALSE, FALSE); 8521 8522 DestroyWindow(richedit); 8523 } 8524 8525 static void test_alignment_style(void) 8526 { 8527 HWND richedit = NULL; 8528 PARAFORMAT2 pf; 8529 DWORD align_style[] = {ES_LEFT, ES_CENTER, ES_RIGHT, ES_RIGHT | ES_CENTER, 8530 ES_LEFT | ES_CENTER, ES_LEFT | ES_RIGHT, 8531 ES_LEFT | ES_RIGHT | ES_CENTER}; 8532 DWORD align_mask[] = {PFA_LEFT, PFA_CENTER, PFA_RIGHT, PFA_CENTER, PFA_CENTER, 8533 PFA_RIGHT, PFA_CENTER}; 8534 const char * streamtext = 8535 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" 8536 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" 8537 "}\r\n"; 8538 EDITSTREAM es; 8539 int i; 8540 8541 for (i = 0; i < sizeof(align_style) / sizeof(align_style[0]); i++) 8542 { 8543 DWORD dwStyle, new_align; 8544 8545 richedit = new_windowW(RICHEDIT_CLASS20W, align_style[i], NULL); 8546 memset(&pf, 0, sizeof(pf)); 8547 pf.cbSize = sizeof(PARAFORMAT2); 8548 pf.dwMask = -1; 8549 8550 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8551 ok(pf.wAlignment == align_mask[i], "(i = %d) got %d expected %d\n", 8552 i, pf.wAlignment, align_mask[i]); 8553 dwStyle = GetWindowLongW(richedit, GWL_STYLE); 8554 ok((i ? (dwStyle & align_style[i]) : (!(dwStyle & 0x0000000f))) , 8555 "(i = %d) didn't set right align style: 0x%x\n", i, dwStyle); 8556 8557 8558 /* Based on test_reset_default_para_fmt() */ 8559 new_align = (align_mask[i] == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT; 8560 simulate_typing_characters(richedit, "123"); 8561 8562 SendMessageW(richedit, EM_SETSEL, 0, -1); 8563 pf.dwMask = PFM_ALIGNMENT; 8564 pf.wAlignment = new_align; 8565 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); 8566 8567 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8568 ok(pf.wAlignment == new_align, "got %d expect %d\n", pf.wAlignment, new_align); 8569 8570 SendMessageW(richedit, EM_SETSEL, 0, -1); 8571 SendMessageW(richedit, WM_CUT, 0, 0); 8572 8573 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8574 ok(pf.wAlignment == align_mask[i], "got %d expect %d\n", pf.wAlignment, align_mask[i]); 8575 8576 DestroyWindow(richedit); 8577 } 8578 8579 /* test with EM_STREAMIN */ 8580 richedit = new_windowW(RICHEDIT_CLASS20W, ES_CENTER, NULL); 8581 simulate_typing_characters(richedit, "abc"); 8582 es.dwCookie = (DWORD_PTR)&streamtext; 8583 es.dwError = 0; 8584 es.pfnCallback = test_EM_STREAMIN_esCallback; 8585 SendMessageW(richedit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 8586 SendMessageW(richedit, EM_SETSEL, 0, -1); 8587 memset(&pf, 0, sizeof(pf)); 8588 pf.cbSize = sizeof(PARAFORMAT2); 8589 pf.dwMask = -1; 8590 SendMessageW(richedit, EM_GETPARAFORMAT, SCF_SELECTION, (LPARAM)&pf); 8591 ok(pf.wAlignment == PFA_LEFT, "got %d expected PFA_LEFT\n", pf.wAlignment); 8592 DestroyWindow(richedit); 8593 } 8594 8595 static void test_WM_GETTEXTLENGTH(void) 8596 { 8597 HWND hwndRichEdit = new_richedit(NULL); 8598 static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee"; 8599 static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n"; 8600 static const char text3[] = "abcdef\x8e\xf0"; 8601 int result; 8602 8603 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 8604 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8605 ok(result == lstrlenA(text1), "WM_GETTEXTLENGTH returned %d, expected %d\n", 8606 result, lstrlenA(text1)); 8607 8608 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 8609 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8610 ok(result == lstrlenA(text2), "WM_GETTEXTLENGTH returned %d, expected %d\n", 8611 result, lstrlenA(text2)); 8612 8613 /* Test with multibyte character */ 8614 if (!is_lang_japanese) 8615 skip("Skip multibyte character tests on non-Japanese platform\n"); 8616 else 8617 { 8618 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); 8619 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8620 todo_wine ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result); 8621 } 8622 8623 DestroyWindow(hwndRichEdit); 8624 } 8625 8626 static void test_rtf(void) 8627 { 8628 const char *specials = "{\\rtf1\\emspace\\enspace\\bullet\\lquote" 8629 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}"; 8630 const WCHAR expect_specials[] = {' ',' ',0x2022,0x2018,0x2019,0x201c, 8631 0x201d,0x200e,0x200f,0x200d,0x200c}; 8632 const char *pard = "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}"; 8633 const char *highlight = "{\\rtf1{\\colortbl;\\red0\\green0\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\\cf2\\highlight3 foo\\par}"; 8634 8635 HWND edit = new_richeditW( NULL ); 8636 EDITSTREAM es; 8637 WCHAR buf[80]; 8638 LRESULT result; 8639 PARAFORMAT2 fmt; 8640 CHARFORMAT2W cf; 8641 8642 /* Test rtf specials */ 8643 es.dwCookie = (DWORD_PTR)&specials; 8644 es.dwError = 0; 8645 es.pfnCallback = test_EM_STREAMIN_esCallback; 8646 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8647 ok( result == 11, "got %ld\n", result ); 8648 8649 result = SendMessageW( edit, WM_GETTEXT, sizeof(buf)/sizeof(buf[0]), (LPARAM)buf ); 8650 ok( result == sizeof(expect_specials)/sizeof(expect_specials[0]), "got %ld\n", result ); 8651 ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) ); 8652 8653 /* Show that \rtlpar propagates to the second paragraph and is 8654 reset by \pard in the third. */ 8655 es.dwCookie = (DWORD_PTR)&pard; 8656 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8657 ok( result == 11, "got %ld\n", result ); 8658 8659 fmt.cbSize = sizeof(fmt); 8660 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8661 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8662 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8663 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" ); 8664 SendMessageW( edit, EM_SETSEL, 5, 5 ); 8665 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8666 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8667 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" ); 8668 SendMessageW( edit, EM_SETSEL, 9, 9 ); 8669 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8670 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8671 ok( !(fmt.wEffects & PFE_RTLPARA), "rtl para set\n" ); 8672 8673 /* Test \highlight */ 8674 es.dwCookie = (DWORD_PTR)&highlight; 8675 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8676 ok( result == 3, "got %ld\n", result ); 8677 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8678 memset( &cf, 0, sizeof(cf) ); 8679 cf.cbSize = sizeof(cf); 8680 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8681 ok( (cf.dwEffects & (CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)) == 0, "got %08x\n", cf.dwEffects ); 8682 ok( cf.crTextColor == RGB(128,128,128), "got %08x\n", cf.crTextColor ); 8683 ok( cf.crBackColor == RGB(192,192,192), "got %08x\n", cf.crBackColor ); 8684 8685 DestroyWindow( edit ); 8686 } 8687 8688 static void test_background(void) 8689 { 8690 HWND hwndRichEdit = new_richedit(NULL); 8691 8692 /* set the background color to black */ 8693 ValidateRect(hwndRichEdit, NULL); 8694 SendMessageA(hwndRichEdit, EM_SETBKGNDCOLOR, FALSE, RGB(0, 0, 0)); 8695 ok(GetUpdateRect(hwndRichEdit, NULL, FALSE), "Update rectangle is empty!\n"); 8696 8697 DestroyWindow(hwndRichEdit); 8698 } 8699 8700 static void test_eop_char_fmt(void) 8701 { 8702 HWND edit = new_richedit( NULL ); 8703 const char *rtf = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}" 8704 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par" 8705 "\\f0\\fs25 Second\\par" 8706 "{\\f0\\fs26 Third}\\par" 8707 "{\\f0\\fs22 Fourth}\\par}}}"; 8708 EDITSTREAM es; 8709 CHARFORMAT2W cf; 8710 int i, num, expect_height; 8711 8712 es.dwCookie = (DWORD_PTR)&rtf; 8713 es.dwError = 0; 8714 es.pfnCallback = test_EM_STREAMIN_esCallback; 8715 num = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8716 ok( num == 25, "got %d\n", num ); 8717 8718 for (i = 0; i <= num; i++) 8719 { 8720 SendMessageW( edit, EM_SETSEL, i, i + 1 ); 8721 cf.cbSize = sizeof(cf); 8722 cf.dwMask = CFM_SIZE; 8723 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8724 ok( cf.dwMask & CFM_SIZE, "%d: got %08x\n", i, cf.dwMask ); 8725 if (i < 6) expect_height = 160; 8726 else if (i < 13) expect_height = 250; 8727 else if (i < 18) expect_height = 260; 8728 else if (i == 18 || i == 25) expect_height = 250; 8729 else expect_height = 220; 8730 ok( cf.yHeight == expect_height, "%d: got %d\n", i, cf.yHeight ); 8731 } 8732 8733 DestroyWindow( edit ); 8734 } 8735 8736 static void test_para_numbering(void) 8737 { 8738 HWND edit = new_richeditW( NULL ); 8739 const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}" 8740 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}" 8741 "\\fs20\\fi200\\li360\\f0 First\\par" 8742 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par" 8743 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}"; 8744 const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0}; 8745 EDITSTREAM es; 8746 WCHAR buf[80]; 8747 LRESULT result; 8748 PARAFORMAT2 fmt, fmt2; 8749 GETTEXTEX get_text; 8750 CHARFORMAT2W cf; 8751 8752 get_text.cb = sizeof(buf); 8753 get_text.flags = GT_RAWTEXT; 8754 get_text.codepage = 1200; 8755 get_text.lpDefaultChar = NULL; 8756 get_text.lpUsedDefChar = NULL; 8757 8758 es.dwCookie = (DWORD_PTR)&numbers; 8759 es.dwError = 0; 8760 es.pfnCallback = test_EM_STREAMIN_esCallback; 8761 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8762 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result ); 8763 8764 result = SendMessageW( edit, EM_GETTEXTEX, (WPARAM)&get_text, (LPARAM)buf ); 8765 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result ); 8766 ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) ); 8767 8768 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8769 memset( &fmt, 0, sizeof(fmt) ); 8770 fmt.cbSize = sizeof(fmt); 8771 fmt.dwMask = PFM_ALL2; 8772 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8773 ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering ); 8774 ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart ); 8775 ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle ); 8776 ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab ); 8777 ok( fmt.dxStartIndent == 560, "got %d\n", fmt.dxStartIndent ); 8778 ok( fmt.dxOffset == -200, "got %d\n", fmt.dxOffset ); 8779 8780 /* Second para should have identical fmt */ 8781 SendMessageW( edit, EM_SETSEL, 10, 10 ); 8782 memset( &fmt2, 0, sizeof(fmt2) ); 8783 fmt2.cbSize = sizeof(fmt2); 8784 fmt2.dwMask = PFM_ALL2; 8785 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 ); 8786 ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" ); 8787 8788 /* Check the eop heights - this determines the label height */ 8789 SendMessageW( edit, EM_SETSEL, 12, 13 ); 8790 cf.cbSize = sizeof(cf); 8791 cf.dwMask = CFM_SIZE; 8792 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8793 ok( cf.yHeight == 200, "got %d\n", cf.yHeight ); 8794 8795 SendMessageW( edit, EM_SETSEL, 18, 19 ); 8796 cf.cbSize = sizeof(cf); 8797 cf.dwMask = CFM_SIZE; 8798 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8799 ok( cf.yHeight == 200, "got %d\n", cf.yHeight ); 8800 8801 DestroyWindow( edit ); 8802 } 8803 8804 static void fill_reobject_struct(REOBJECT *reobj, LONG cp, LPOLEOBJECT poleobj, 8805 LPSTORAGE pstg, LPOLECLIENTSITE polesite, LONG sizel_cx, 8806 LONG sizel_cy, DWORD aspect, DWORD flags, DWORD user) 8807 { 8808 reobj->cbStruct = sizeof(*reobj); 8809 reobj->clsid = CLSID_NULL; 8810 reobj->cp = cp; 8811 reobj->poleobj = poleobj; 8812 reobj->pstg = pstg; 8813 reobj->polesite = polesite; 8814 reobj->sizel.cx = sizel_cx; 8815 reobj->sizel.cy = sizel_cy; 8816 reobj->dvaspect = aspect; 8817 reobj->dwFlags = flags; 8818 reobj->dwUser = user; 8819 } 8820 8821 static void test_EM_SELECTIONTYPE(void) 8822 { 8823 HWND hwnd = new_richedit(NULL); 8824 IRichEditOle *reole = NULL; 8825 static const char text1[] = "abcdefg\n"; 8826 int result; 8827 REOBJECT reo1, reo2; 8828 IOleClientSite *clientsite; 8829 HRESULT hr; 8830 8831 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text1); 8832 SendMessageA(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&reole); 8833 8834 SendMessageA(hwnd, EM_SETSEL, 1, 1); 8835 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8836 ok(result == SEL_EMPTY, "got wrong selection type: %x.\n", result); 8837 8838 SendMessageA(hwnd, EM_SETSEL, 1, 2); 8839 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8840 ok(result == SEL_TEXT, "got wrong selection type: %x.\n", result); 8841 8842 SendMessageA(hwnd, EM_SETSEL, 2, 5); 8843 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8844 ok(result == (SEL_TEXT | SEL_MULTICHAR), "got wrong selection type: %x.\n", result); 8845 8846 SendMessageA(hwnd, EM_SETSEL, 0, 1); 8847 hr = IRichEditOle_GetClientSite(reole, &clientsite); 8848 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr); 8849 fill_reobject_struct(&reo1, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10, 8850 DVASPECT_CONTENT, 0, 1); 8851 hr = IRichEditOle_InsertObject(reole, &reo1); 8852 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr); 8853 IOleClientSite_Release(clientsite); 8854 8855 SendMessageA(hwnd, EM_SETSEL, 0, 1); 8856 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8857 ok(result == SEL_OBJECT, "got wrong selection type: %x.\n", result); 8858 8859 SendMessageA(hwnd, EM_SETSEL, 0, 2); 8860 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8861 ok(result == (SEL_TEXT | SEL_OBJECT), "got wrong selection type: %x.\n", result); 8862 8863 SendMessageA(hwnd, EM_SETSEL, 0, 3); 8864 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8865 ok(result == (SEL_TEXT | SEL_MULTICHAR | SEL_OBJECT), "got wrong selection type: %x.\n", result); 8866 8867 SendMessageA(hwnd, EM_SETSEL, 2, 3); 8868 hr = IRichEditOle_GetClientSite(reole, &clientsite); 8869 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr); 8870 fill_reobject_struct(&reo2, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10, 8871 DVASPECT_CONTENT, 0, 2); 8872 hr = IRichEditOle_InsertObject(reole, &reo2); 8873 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr); 8874 IOleClientSite_Release(clientsite); 8875 8876 SendMessageA(hwnd, EM_SETSEL, 0, 2); 8877 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8878 ok(result == (SEL_OBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result); 8879 8880 SendMessageA(hwnd, EM_SETSEL, 0, 3); 8881 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8882 ok(result == (SEL_OBJECT | SEL_MULTIOBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result); 8883 8884 SendMessageA(hwnd, EM_SETSEL, 0, 4); 8885 result = SendMessageA(hwnd, EM_SELECTIONTYPE, 0, 0); 8886 ok(result == (SEL_TEXT| SEL_MULTICHAR | SEL_OBJECT | SEL_MULTIOBJECT), "got wrong selection type: %x.\n", result); 8887 8888 IRichEditOle_Release(reole); 8889 DestroyWindow(hwnd); 8890 } 8891 8892 static void test_window_classes(void) 8893 { 8894 static const struct 8895 { 8896 const char *class; 8897 BOOL success; 8898 } test[] = 8899 { 8900 { "RichEdit", FALSE }, 8901 { "RichEdit20A", TRUE }, 8902 { "RichEdit20W", TRUE }, 8903 { "RichEdit50A", FALSE }, 8904 { "RichEdit50W", FALSE } 8905 }; 8906 int i; 8907 HWND hwnd; 8908 8909 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++) 8910 { 8911 SetLastError(0xdeadbeef); 8912 hwnd = CreateWindowExA(0, test[i].class, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL); 8913 todo_wine_if(!strcmp(test[i].class, "RichEdit50A") || !strcmp(test[i].class, "RichEdit50W")) 8914 ok(!hwnd == !test[i].success, "CreateWindow(%s) should %s\n", 8915 test[i].class, test[i].success ? "succeed" : "fail"); 8916 if (!hwnd) 8917 todo_wine 8918 ok(GetLastError() == ERROR_CANNOT_FIND_WND_CLASS, "got %d\n", GetLastError()); 8919 else 8920 DestroyWindow(hwnd); 8921 } 8922 } 8923 8924 START_TEST( editor ) 8925 { 8926 BOOL ret; 8927 /* Must explicitly LoadLibrary(). The test has no references to functions in 8928 * RICHED20.DLL, so the linker doesn't actually link to it. */ 8929 hmoduleRichEdit = LoadLibraryA("riched20.dll"); 8930 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); 8931 is_lang_japanese = (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE); 8932 8933 test_window_classes(); 8934 test_WM_CHAR(); 8935 test_EM_FINDTEXT(FALSE); 8936 test_EM_FINDTEXT(TRUE); 8937 test_EM_GETLINE(); 8938 test_EM_POSFROMCHAR(); 8939 test_EM_SCROLLCARET(); 8940 test_EM_SCROLL(); 8941 test_scrollbar_visibility(); 8942 test_WM_SETTEXT(); 8943 test_EM_LINELENGTH(); 8944 test_EM_SETCHARFORMAT(); 8945 test_EM_SETTEXTMODE(); 8946 test_TM_PLAINTEXT(); 8947 test_EM_SETOPTIONS(); 8948 test_WM_GETTEXT(); 8949 test_EM_GETTEXTRANGE(); 8950 test_EM_GETSELTEXT(); 8951 test_EM_SETUNDOLIMIT(); 8952 test_ES_PASSWORD(); 8953 test_EM_SETTEXTEX(); 8954 test_EM_LIMITTEXT(); 8955 test_EM_EXLIMITTEXT(); 8956 test_EM_GETLIMITTEXT(); 8957 test_WM_SETFONT(); 8958 test_EM_GETMODIFY(); 8959 test_EM_SETSEL(); 8960 test_EM_EXSETSEL(); 8961 test_WM_PASTE(); 8962 test_EM_STREAMIN(); 8963 test_EM_STREAMOUT(); 8964 test_EM_STREAMOUT_FONTTBL(); 8965 test_EM_STREAMOUT_empty_para(); 8966 test_EM_StreamIn_Undo(); 8967 test_EM_FORMATRANGE(); 8968 test_unicode_conversions(); 8969 test_EM_GETTEXTLENGTHEX(); 8970 test_WM_GETTEXTLENGTH(); 8971 test_EM_REPLACESEL(1); 8972 test_EM_REPLACESEL(0); 8973 test_WM_NOTIFY(); 8974 test_EN_LINK(); 8975 test_EM_AUTOURLDETECT(); 8976 test_eventMask(); 8977 test_undo_coalescing(); 8978 test_word_movement(); 8979 test_EM_CHARFROMPOS(); 8980 test_SETPARAFORMAT(); 8981 test_word_wrap(); 8982 test_autoscroll(); 8983 test_format_rect(); 8984 test_WM_GETDLGCODE(); 8985 test_zoom(); 8986 test_dialogmode(); 8987 test_EM_FINDWORDBREAK_W(); 8988 test_EM_FINDWORDBREAK_A(); 8989 test_enter(); 8990 test_WM_CREATE(); 8991 test_reset_default_para_fmt(); 8992 test_EM_SETREADONLY(); 8993 test_EM_SETFONTSIZE(); 8994 test_alignment_style(); 8995 test_rtf(); 8996 test_background(); 8997 test_eop_char_fmt(); 8998 test_para_numbering(); 8999 test_EM_SELECTIONTYPE(); 9000 9001 /* Set the environment variable WINETEST_RICHED20 to keep windows 9002 * responsive and open for 30 seconds. This is useful for debugging. 9003 */ 9004 if (getenv( "WINETEST_RICHED20" )) { 9005 keep_responsive(30); 9006 } 9007 9008 OleFlushClipboard(); 9009 ret = FreeLibrary(hmoduleRichEdit); 9010 ok(ret, "error: %d\n", (int) GetLastError()); 9011 } 9012