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 #include <stdarg.h> 24 #include <stdio.h> 25 #include <assert.h> 26 #include <windef.h> 27 #include <winbase.h> 28 #include <wingdi.h> 29 #include <winuser.h> 30 #include <winnls.h> 31 #include <ole2.h> 32 #include <richedit.h> 33 #include <commdlg.h> 34 #include <time.h> 35 #include <wine/test.h> 36 37 #define ID_RICHEDITTESTDBUTTON 0x123 38 39 static CHAR string1[MAX_PATH], string2[MAX_PATH], string3[MAX_PATH]; 40 41 #define ok_w3(format, szString1, szString2, szString3) \ 42 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ 43 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ 44 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \ 45 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \ 46 format, string1, string2, string3); 47 48 static HMODULE hmoduleRichEdit; 49 static BOOL is_lang_japanese; 50 51 static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent) { 52 HWND hwnd; 53 hwnd = CreateWindowA(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL 54 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL, 55 hmoduleRichEdit, NULL); 56 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError()); 57 return hwnd; 58 } 59 60 static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent) { 61 HWND hwnd; 62 hwnd = CreateWindowW(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL 63 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL, 64 hmoduleRichEdit, NULL); 65 ok(hwnd != NULL, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName), (int) GetLastError()); 66 return hwnd; 67 } 68 69 static HWND new_richedit(HWND parent) { 70 return new_window(RICHEDIT_CLASS20A, ES_MULTILINE, parent); 71 } 72 73 static HWND new_richedit_with_style(HWND parent, DWORD style) { 74 return new_window(RICHEDIT_CLASS20A, style, parent); 75 } 76 77 static HWND new_richeditW(HWND parent) { 78 return new_windowW(RICHEDIT_CLASS20W, ES_MULTILINE, parent); 79 } 80 81 /* Keeps the window reponsive for the deley_time in seconds. 82 * This is useful for debugging a test to see what is happening. */ 83 static void keep_responsive(time_t delay_time) 84 { 85 MSG msg; 86 time_t end; 87 88 /* The message pump uses PeekMessage() to empty the queue and then 89 * sleeps for 50ms before retrying the queue. */ 90 end = time(NULL) + delay_time; 91 while (time(NULL) < end) { 92 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { 93 TranslateMessage(&msg); 94 DispatchMessageA(&msg); 95 } else { 96 Sleep(50); 97 } 98 } 99 } 100 101 static void simulate_typing_characters(HWND hwnd, const char* szChars) 102 { 103 int ret; 104 105 while (*szChars != '\0') { 106 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1); 107 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1); 108 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret); 109 SendMessageA(hwnd, WM_KEYUP, *szChars, 1); 110 szChars++; 111 } 112 } 113 114 static BOOL hold_key(int vk) 115 { 116 BYTE key_state[256]; 117 BOOL result; 118 119 result = GetKeyboardState(key_state); 120 ok(result, "GetKeyboardState failed.\n"); 121 if (!result) return FALSE; 122 key_state[vk] |= 0x80; 123 result = SetKeyboardState(key_state); 124 ok(result, "SetKeyboardState failed.\n"); 125 return result != 0; 126 } 127 128 static BOOL release_key(int vk) 129 { 130 BYTE key_state[256]; 131 BOOL result; 132 133 result = GetKeyboardState(key_state); 134 ok(result, "GetKeyboardState failed.\n"); 135 if (!result) return FALSE; 136 key_state[vk] &= ~0x80; 137 result = SetKeyboardState(key_state); 138 ok(result, "SetKeyboardState failed.\n"); 139 return result != 0; 140 } 141 142 static const char haystack[] = "WINEWine wineWine wine WineWine"; 143 /* ^0 ^10 ^20 ^30 */ 144 145 struct find_s { 146 int start; 147 int end; 148 const char *needle; 149 int flags; 150 int expected_loc; 151 }; 152 153 154 static struct find_s find_tests[] = { 155 /* Find in empty text */ 156 {0, -1, "foo", FR_DOWN, -1}, 157 {0, -1, "foo", 0, -1}, 158 {0, -1, "", FR_DOWN, -1}, 159 {20, 5, "foo", FR_DOWN, -1}, 160 {5, 20, "foo", FR_DOWN, -1} 161 }; 162 163 static struct find_s find_tests2[] = { 164 /* No-result find */ 165 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1}, 166 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1}, 167 168 /* Subsequent finds */ 169 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4}, 170 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13}, 171 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, 172 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 173 174 /* Find backwards */ 175 {19, 20, "Wine", FR_MATCHCASE, 13}, 176 {10, 20, "Wine", FR_MATCHCASE, 4}, 177 {20, 10, "Wine", FR_MATCHCASE, 13}, 178 179 /* Case-insensitive */ 180 {1, 31, "wInE", FR_DOWN, 4}, 181 {1, 31, "Wine", FR_DOWN, 4}, 182 183 /* High-to-low ranges */ 184 {20, 5, "Wine", FR_DOWN, -1}, 185 {2, 1, "Wine", FR_DOWN, -1}, 186 {30, 29, "Wine", FR_DOWN, -1}, 187 {20, 5, "Wine", 0, 13}, 188 189 /* Find nothing */ 190 {5, 10, "", FR_DOWN, -1}, 191 {10, 5, "", FR_DOWN, -1}, 192 {0, -1, "", FR_DOWN, -1}, 193 {10, 5, "", 0, -1}, 194 195 /* Whole-word search */ 196 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, 197 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1}, 198 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, 199 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0}, 200 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23}, 201 {11, -1, "winewine", FR_WHOLEWORD, 0}, 202 {31, -1, "winewine", FR_WHOLEWORD, 23}, 203 204 /* Bad ranges */ 205 {5, 200, "XXX", FR_DOWN, -1}, 206 {-20, 20, "Wine", FR_DOWN, -1}, 207 {-20, 20, "Wine", FR_DOWN, -1}, 208 {-15, -20, "Wine", FR_DOWN, -1}, 209 {1<<12, 1<<13, "Wine", FR_DOWN, -1}, 210 211 /* Check the case noted in bug 4479 where matches at end aren't recognized */ 212 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, 213 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 214 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27}, 215 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, 216 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, 217 218 /* The backwards case of bug 4479; bounds look right 219 * Fails because backward find is wrong */ 220 {19, 20, "WINE", FR_MATCHCASE, 0}, 221 {0, 20, "WINE", FR_MATCHCASE, -1}, 222 223 {0, -1, "wineWine wine", 0, -1}, 224 }; 225 226 static WCHAR *atowstr(const char *str) 227 { 228 WCHAR *ret; 229 DWORD len; 230 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 231 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 232 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 233 return ret; 234 } 235 236 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode) 237 { 238 int findloc; 239 240 if(unicode){ 241 FINDTEXTW ftw; 242 memset(&ftw, 0, sizeof(ftw)); 243 ftw.chrg.cpMin = f->start; 244 ftw.chrg.cpMax = f->end; 245 ftw.lpstrText = atowstr(f->needle); 246 247 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ftw); 248 ok(findloc == f->expected_loc, 249 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 250 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 251 252 findloc = SendMessageA(hwnd, EM_FINDTEXTW, f->flags, (LPARAM)&ftw); 253 ok(findloc == f->expected_loc, 254 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 255 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 256 257 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText); 258 }else{ 259 FINDTEXTA fta; 260 memset(&fta, 0, sizeof(fta)); 261 fta.chrg.cpMin = f->start; 262 fta.chrg.cpMax = f->end; 263 fta.lpstrText = f->needle; 264 265 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&fta); 266 ok(findloc == f->expected_loc, 267 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", 268 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); 269 } 270 } 271 272 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, 273 int id, BOOL unicode) 274 { 275 int findloc; 276 int expected_end_loc; 277 278 if(unicode){ 279 FINDTEXTEXW ftw; 280 memset(&ftw, 0, sizeof(ftw)); 281 ftw.chrg.cpMin = f->start; 282 ftw.chrg.cpMax = f->end; 283 ftw.lpstrText = atowstr(f->needle); 284 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ftw); 285 ok(findloc == f->expected_loc, 286 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 287 name, id, f->needle, f->start, f->end, f->flags, findloc); 288 ok(ftw.chrgText.cpMin == 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, ftw.chrgText.cpMin); 291 expected_end_loc = ((f->expected_loc == -1) ? -1 292 : f->expected_loc + strlen(f->needle)); 293 ok(ftw.chrgText.cpMax == expected_end_loc, 294 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n", 295 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMax, expected_end_loc); 296 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText); 297 }else{ 298 FINDTEXTEXA fta; 299 memset(&fta, 0, sizeof(fta)); 300 fta.chrg.cpMin = f->start; 301 fta.chrg.cpMax = f->end; 302 fta.lpstrText = f->needle; 303 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&fta); 304 ok(findloc == f->expected_loc, 305 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", 306 name, id, f->needle, f->start, f->end, f->flags, findloc); 307 ok(fta.chrgText.cpMin == 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, fta.chrgText.cpMin); 310 expected_end_loc = ((f->expected_loc == -1) ? -1 311 : f->expected_loc + strlen(f->needle)); 312 ok(fta.chrgText.cpMax == expected_end_loc, 313 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n", 314 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMax, expected_end_loc); 315 } 316 } 317 318 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, 319 int num_tests, BOOL unicode) 320 { 321 int i; 322 323 for (i = 0; i < num_tests; i++) { 324 check_EM_FINDTEXT(hwnd, name, &find[i], i, unicode); 325 check_EM_FINDTEXTEX(hwnd, name, &find[i], i, unicode); 326 } 327 } 328 329 static void test_EM_FINDTEXT(BOOL unicode) 330 { 331 HWND hwndRichEdit; 332 CHARFORMAT2A cf2; 333 334 if(unicode) 335 hwndRichEdit = new_richeditW(NULL); 336 else 337 hwndRichEdit = new_richedit(NULL); 338 339 /* Empty rich edit control */ 340 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, 341 sizeof(find_tests)/sizeof(struct find_s), unicode); 342 343 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack); 344 345 /* Haystack text */ 346 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, 347 sizeof(find_tests2)/sizeof(struct find_s), unicode); 348 349 /* Setting a format on an arbitrary range should have no effect in search 350 results. This tests correct offset reporting across runs. */ 351 cf2.cbSize = sizeof(CHARFORMAT2A); 352 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 353 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 354 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 355 SendMessageA(hwndRichEdit, EM_SETSEL, 6, 20); 356 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 357 358 /* Haystack text, again */ 359 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, 360 sizeof(find_tests2)/sizeof(struct find_s), unicode); 361 362 /* Yet another range */ 363 cf2.dwMask = CFM_BOLD | cf2.dwMask; 364 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects; 365 SendMessageA(hwndRichEdit, EM_SETSEL, 11, 15); 366 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 367 368 /* Haystack text, again */ 369 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, 370 sizeof(find_tests2)/sizeof(struct find_s), unicode); 371 372 DestroyWindow(hwndRichEdit); 373 } 374 375 static const struct getline_s { 376 int line; 377 size_t buffer_len; 378 const char *text; 379 } gl[] = { 380 {0, 10, "foo bar\r"}, 381 {1, 10, "\r"}, 382 {2, 10, "bar\r"}, 383 {3, 10, "\r"}, 384 385 /* Buffer smaller than line length */ 386 {0, 2, "foo bar\r"}, 387 {0, 1, "foo bar\r"}, 388 {0, 0, "foo bar\r"} 389 }; 390 391 static void test_EM_GETLINE(void) 392 { 393 int i; 394 HWND hwndRichEdit = new_richedit(NULL); 395 static const int nBuf = 1024; 396 char dest[1024], origdest[1024]; 397 const char text[] = "foo bar\n" 398 "\n" 399 "bar\n"; 400 401 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 402 403 memset(origdest, 0xBB, nBuf); 404 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++) 405 { 406 int nCopied; 407 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text)); 408 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text)); 409 memset(dest, 0xBB, nBuf); 410 *(WORD *) dest = gl[i].buffer_len; 411 412 /* EM_GETLINE appends a "\r\0" to the end of the line 413 * nCopied counts up to and including the '\r' */ 414 nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest); 415 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, 416 expected_nCopied); 417 /* two special cases since a parameter is passed via dest */ 418 if (gl[i].buffer_len == 0) 419 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2), 420 "buffer_len=0\n"); 421 else if (gl[i].buffer_len == 1) 422 ok(dest[0] == gl[i].text[0] && !dest[1] && 423 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n"); 424 else 425 { 426 /* Prepare hex strings of buffers to dump on failure. */ 427 char expectedbuf[1024]; 428 char resultbuf[1024]; 429 int j; 430 resultbuf[0] = '\0'; 431 for (j = 0; j < 32; j++) 432 sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF); 433 expectedbuf[0] = '\0'; 434 for (j = 0; j < expected_bytes_written; j++) /* Written bytes */ 435 sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF); 436 for (; j < gl[i].buffer_len; j++) /* Ignored bytes */ 437 sprintf(expectedbuf+strlen(expectedbuf), "??"); 438 for (; j < 32; j++) /* Bytes after declared buffer size */ 439 sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF); 440 441 /* Test the part of the buffer that is expected to be written according 442 * to the MSDN documentation fo EM_GETLINE, which does not state that 443 * a NULL terminating character will be added unless no text is copied. 444 * 445 * Windows NT does not append a NULL terminating character, but 446 * Windows 2000 and up do append a NULL terminating character if there 447 * is space in the buffer. The test will ignore this difference. */ 448 ok(!strncmp(dest, gl[i].text, expected_bytes_written), 449 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", 450 i, expected_bytes_written, expectedbuf, resultbuf); 451 /* Test the part of the buffer after the declared length to make sure 452 * there are no buffer overruns. */ 453 ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len, 454 nBuf - gl[i].buffer_len), 455 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", 456 i, expected_bytes_written, expectedbuf, resultbuf); 457 } 458 } 459 460 DestroyWindow(hwndRichEdit); 461 } 462 463 static void test_EM_LINELENGTH(void) 464 { 465 HWND hwndRichEdit = new_richedit(NULL); 466 const char * text = 467 "richedit1\r" 468 "richedit1\n" 469 "richedit1\r\n" 470 "richedit1"; 471 int offset_test[10][2] = { 472 {0, 9}, 473 {5, 9}, 474 {10, 9}, 475 {15, 9}, 476 {20, 9}, 477 {25, 9}, 478 {30, 9}, 479 {35, 9}, 480 {40, 0}, 481 {45, 0}, 482 }; 483 int i; 484 LRESULT result; 485 486 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 487 488 for (i = 0; i < 10; i++) { 489 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0); 490 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n", 491 offset_test[i][0], result, offset_test[i][1]); 492 } 493 494 /* Test with multibyte character */ 495 if (!is_lang_japanese) 496 skip("Skip multibyte character tests on non-Japanese platform\n"); 497 else 498 { 499 const char *text1 = 500 "wine\n" 501 "richedit\x8e\xf0\n" 502 "wine"; 503 int offset_test1[3][2] = { 504 {0, 4}, /* Line 1: |wine\n */ 505 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */ 506 {15, 4}, /* Line 3: |wine */ 507 }; 508 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 509 for (i = 0; i < sizeof(offset_test1)/sizeof(offset_test1[0]); i++) { 510 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0); 511 ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n", 512 offset_test1[i][0], result, offset_test1[i][1]); 513 } 514 } 515 516 DestroyWindow(hwndRichEdit); 517 } 518 519 static int get_scroll_pos_y(HWND hwnd) 520 { 521 POINT p = {-1, -1}; 522 SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&p); 523 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y); 524 return p.y; 525 } 526 527 static void move_cursor(HWND hwnd, LONG charindex) 528 { 529 CHARRANGE cr; 530 cr.cpMax = charindex; 531 cr.cpMin = charindex; 532 SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); 533 } 534 535 static void line_scroll(HWND hwnd, int amount) 536 { 537 SendMessageA(hwnd, EM_LINESCROLL, 0, amount); 538 } 539 540 static void test_EM_SCROLLCARET(void) 541 { 542 int prevY, curY; 543 const char text[] = "aa\n" 544 "this is a long line of text that should be longer than the " 545 "control's width\n" 546 "cc\n" 547 "dd\n" 548 "ee\n" 549 "ff\n" 550 "gg\n" 551 "hh\n"; 552 /* The richedit window height needs to be large enough vertically to fit in 553 * more than two lines of text, so the new_richedit function can't be used 554 * since a height of 60 was not large enough on some systems. 555 */ 556 HWND hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, 557 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 558 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 559 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 560 561 /* Can't verify this */ 562 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 563 564 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 565 566 /* Caret above visible window */ 567 line_scroll(hwndRichEdit, 3); 568 prevY = get_scroll_pos_y(hwndRichEdit); 569 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 570 curY = get_scroll_pos_y(hwndRichEdit); 571 ok(prevY != curY, "%d == %d\n", prevY, curY); 572 573 /* Caret below visible window */ 574 move_cursor(hwndRichEdit, sizeof(text) - 1); 575 line_scroll(hwndRichEdit, -3); 576 prevY = get_scroll_pos_y(hwndRichEdit); 577 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 578 curY = get_scroll_pos_y(hwndRichEdit); 579 ok(prevY != curY, "%d == %d\n", prevY, curY); 580 581 /* Caret in visible window */ 582 move_cursor(hwndRichEdit, sizeof(text) - 2); 583 prevY = get_scroll_pos_y(hwndRichEdit); 584 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 585 curY = get_scroll_pos_y(hwndRichEdit); 586 ok(prevY == curY, "%d != %d\n", prevY, curY); 587 588 /* Caret still in visible window */ 589 line_scroll(hwndRichEdit, -1); 590 prevY = get_scroll_pos_y(hwndRichEdit); 591 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0); 592 curY = get_scroll_pos_y(hwndRichEdit); 593 ok(prevY == curY, "%d != %d\n", prevY, curY); 594 595 DestroyWindow(hwndRichEdit); 596 } 597 598 static void test_EM_POSFROMCHAR(void) 599 { 600 HWND hwndRichEdit = new_richedit(NULL); 601 int i, expected; 602 LRESULT result; 603 unsigned int height = 0; 604 int xpos = 0; 605 POINTL pt; 606 LOCALESIGNATURE sig; 607 BOOL rtl; 608 PARAFORMAT2 fmt; 609 static const char text[] = "aa\n" 610 "this is a long line of text that should be longer than the " 611 "control's width\n" 612 "cc\n" 613 "dd\n" 614 "ee\n" 615 "ff\n" 616 "gg\n" 617 "hh\n"; 618 619 rtl = (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE, 620 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) && 621 (sig.lsUsb[3] & 0x08000000) != 0); 622 623 /* Fill the control to lines to ensure that most of them are offscreen */ 624 for (i = 0; i < 50; i++) 625 { 626 /* Do not modify the string; it is exactly 16 characters long. */ 627 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 628 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n"); 629 } 630 631 /* 632 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void. 633 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y) 634 Richedit 3.0 accepts either of the above API conventions. 635 */ 636 637 /* Testing Richedit 2.0 API format */ 638 639 /* Testing start of lines. X-offset should be constant on all cases (native is 1). 640 Since all lines are identical and drawn with the same font, 641 they should have the same height... right? 642 */ 643 for (i = 0; i < 50; i++) 644 { 645 /* All the lines are 16 characters long */ 646 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0); 647 if (i == 0) 648 { 649 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 650 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 651 xpos = LOWORD(result); 652 } 653 else if (i == 1) 654 { 655 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result)); 656 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 657 height = HIWORD(result); 658 } 659 else 660 { 661 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height); 662 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 663 } 664 } 665 666 /* Testing position at end of text */ 667 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0); 668 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height); 669 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 670 671 /* Testing position way past end of text */ 672 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0); 673 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height); 674 expected = (rtl ? 8 : 1); 675 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected); 676 677 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */ 678 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */ 679 for (i = 0; i < 50; i++) 680 { 681 /* All the lines are 16 characters long */ 682 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0); 683 ok((signed short)(HIWORD(result)) == (i - 1) * height, 684 "EM_POSFROMCHAR reports y=%hd, expected %d\n", 685 (signed short)(HIWORD(result)), (i - 1) * height); 686 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 687 } 688 689 /* Testing position at end of text */ 690 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0); 691 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height); 692 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 693 694 /* Testing position way past end of text */ 695 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0); 696 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height); 697 expected = (rtl ? 8 : 1); 698 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected); 699 700 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */ 701 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 702 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */ 703 704 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0); 705 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 706 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); 707 xpos = LOWORD(result); 708 709 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0); 710 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0); 711 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); 712 ok((signed short)(LOWORD(result)) < xpos, 713 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n", 714 (signed short)(LOWORD(result)), xpos); 715 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0); 716 717 /* Test around end of text that doesn't end in a newline. */ 718 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"12345678901234"); 719 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 720 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1); 721 ok(pt.x > 1, "pt.x = %d\n", pt.x); 722 xpos = pt.x; 723 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 724 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)); 725 ok(pt.x > xpos, "pt.x = %d\n", pt.x); 726 xpos = (rtl ? pt.x + 7 : pt.x); 727 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 728 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1); 729 ok(pt.x == xpos, "pt.x = %d\n", pt.x); 730 731 /* Try a negative position. */ 732 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1); 733 ok(pt.x == 1, "pt.x = %d\n", pt.x); 734 735 /* test negative indentation */ 736 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 737 (LPARAM)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}"); 738 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 0); 739 ok(pt.x == 1, "pt.x = %d\n", pt.x); 740 741 fmt.cbSize = sizeof(fmt); 742 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 743 ok(fmt.dxStartIndent == -400, "got %d\n", fmt.dxStartIndent); 744 ok(fmt.dxOffset == 200, "got %d\n", fmt.dxOffset); 745 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment); 746 747 DestroyWindow(hwndRichEdit); 748 } 749 750 static void test_EM_SETCHARFORMAT(void) 751 { 752 HWND hwndRichEdit = new_richedit(NULL); 753 CHARFORMAT2A cf2; 754 CHARFORMAT2W cfW; 755 int rc = 0; 756 int tested_effects[] = { 757 CFE_BOLD, 758 CFE_ITALIC, 759 CFE_UNDERLINE, 760 CFE_STRIKEOUT, 761 CFE_PROTECTED, 762 CFE_LINK, 763 CFE_SUBSCRIPT, 764 CFE_SUPERSCRIPT, 765 0 766 }; 767 int i; 768 CHARRANGE cr; 769 LOCALESIGNATURE sig; 770 BOOL rtl; 771 DWORD expect_effects; 772 773 rtl = (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_FONTSIGNATURE, 774 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) && 775 (sig.lsUsb[3] & 0x08000000) != 0); 776 777 /* check charformat defaults */ 778 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 779 cf2.cbSize = sizeof(CHARFORMAT2A); 780 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 781 ok(cf2.dwMask == CFM_ALL2, "got %08x\n", cf2.dwMask); 782 expect_effects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; 783 if (cf2.wWeight > 550) expect_effects |= CFE_BOLD; 784 ok(cf2.dwEffects == expect_effects, "got %08x\n", cf2.dwEffects); 785 ok(cf2.yOffset == 0, "got %d\n", cf2.yOffset); 786 ok(cf2.sSpacing == 0, "got %d\n", cf2.sSpacing); 787 ok(cf2.lcid == GetSystemDefaultLCID(), "got %x\n", cf2.lcid); 788 ok(cf2.sStyle == 0, "got %d\n", cf2.sStyle); 789 ok(cf2.wKerning == 0, "got %d\n", cf2.wKerning); 790 ok(cf2.bAnimation == 0, "got %d\n", cf2.bAnimation); 791 ok(cf2.bRevAuthor == 0, "got %d\n", cf2.bRevAuthor); 792 793 /* Invalid flags, CHARFORMAT2 structure blanked out */ 794 memset(&cf2, 0, sizeof(cf2)); 795 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2); 796 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 797 798 /* A valid flag, CHARFORMAT2 structure blanked out */ 799 memset(&cf2, 0, sizeof(cf2)); 800 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 801 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 802 803 /* A valid flag, CHARFORMAT2 structure blanked out */ 804 memset(&cf2, 0, sizeof(cf2)); 805 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 806 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 807 808 /* A valid flag, CHARFORMAT2 structure blanked out */ 809 memset(&cf2, 0, sizeof(cf2)); 810 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2); 811 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 812 813 /* A valid flag, CHARFORMAT2 structure blanked out */ 814 memset(&cf2, 0, sizeof(cf2)); 815 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 816 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 817 818 /* Invalid flags, CHARFORMAT2 structure minimally filled */ 819 memset(&cf2, 0, sizeof(cf2)); 820 cf2.cbSize = sizeof(CHARFORMAT2A); 821 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2); 822 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 823 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 824 ok(rc == FALSE, "Should not be able to undo here.\n"); 825 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 826 827 /* A valid flag, CHARFORMAT2 structure minimally filled */ 828 memset(&cf2, 0, sizeof(cf2)); 829 cf2.cbSize = sizeof(CHARFORMAT2A); 830 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 831 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 832 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 833 ok(rc == FALSE, "Should not be able to undo here.\n"); 834 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 835 836 /* A valid flag, CHARFORMAT2 structure minimally filled */ 837 memset(&cf2, 0, sizeof(cf2)); 838 cf2.cbSize = sizeof(CHARFORMAT2A); 839 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 840 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 841 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 842 ok(rc == FALSE, "Should not be able to undo here.\n"); 843 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 844 845 /* A valid flag, CHARFORMAT2 structure minimally filled */ 846 memset(&cf2, 0, sizeof(cf2)); 847 cf2.cbSize = sizeof(CHARFORMAT2A); 848 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2); 849 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 850 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 851 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n"); 852 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 853 854 /* A valid flag, CHARFORMAT2 structure minimally filled */ 855 memset(&cf2, 0, sizeof(cf2)); 856 cf2.cbSize = sizeof(CHARFORMAT2A); 857 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 858 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 859 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 860 ok(rc == TRUE, "Should not be able to undo here.\n"); 861 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); 862 863 cf2.cbSize = sizeof(CHARFORMAT2A); 864 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 865 866 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */ 867 cf2.cbSize = sizeof(CHARFORMAT2A); 868 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 869 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 870 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 871 872 /* wParam==0 is default char format, does not set modify */ 873 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 874 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 875 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 876 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 877 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 878 if (! rtl) 879 { 880 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 881 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 882 } 883 else 884 skip("RTL language found\n"); 885 886 /* wParam==SCF_SELECTION sets modify if nonempty selection */ 887 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 888 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 889 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 890 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 891 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 892 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 893 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 894 895 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 896 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 897 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 898 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 899 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 900 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 901 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 902 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 903 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 904 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 905 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 906 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 907 908 /* wParam==SCF_ALL sets modify regardless of whether text is present */ 909 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 910 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 911 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 912 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 913 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 914 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 915 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 916 917 DestroyWindow(hwndRichEdit); 918 919 /* EM_GETCHARFORMAT tests */ 920 for (i = 0; tested_effects[i]; i++) 921 { 922 hwndRichEdit = new_richedit(NULL); 923 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 924 925 /* Need to set a TrueType font to get consistent CFM_BOLD results */ 926 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 927 cf2.cbSize = sizeof(CHARFORMAT2A); 928 cf2.dwMask = CFM_FACE|CFM_WEIGHT; 929 cf2.dwEffects = 0; 930 strcpy(cf2.szFaceName, "Courier New"); 931 cf2.wWeight = FW_DONTCARE; 932 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 933 934 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 935 cf2.cbSize = sizeof(CHARFORMAT2A); 936 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 4); 937 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 938 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 939 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 940 || 941 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 942 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 943 ok((cf2.dwEffects & tested_effects[i]) == 0, 944 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 945 946 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 947 cf2.cbSize = sizeof(CHARFORMAT2A); 948 cf2.dwMask = tested_effects[i]; 949 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT) 950 cf2.dwMask = CFM_SUPERSCRIPT; 951 cf2.dwEffects = tested_effects[i]; 952 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 953 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 954 955 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 956 cf2.cbSize = sizeof(CHARFORMAT2A); 957 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 958 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 959 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 960 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 961 || 962 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 963 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 964 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 965 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]); 966 967 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 968 cf2.cbSize = sizeof(CHARFORMAT2A); 969 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 970 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 971 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 972 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 973 || 974 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 975 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 976 ok((cf2.dwEffects & tested_effects[i]) == 0, 977 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 978 979 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 980 cf2.cbSize = sizeof(CHARFORMAT2A); 981 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3); 982 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 983 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 984 (cf2.dwMask & CFM_SUPERSCRIPT) == 0) 985 || 986 (cf2.dwMask & tested_effects[i]) == 0), 987 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]); 988 989 DestroyWindow(hwndRichEdit); 990 } 991 992 for (i = 0; tested_effects[i]; i++) 993 { 994 hwndRichEdit = new_richedit(NULL); 995 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 996 997 /* Need to set a TrueType font to get consistent CFM_BOLD results */ 998 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 999 cf2.cbSize = sizeof(CHARFORMAT2A); 1000 cf2.dwMask = CFM_FACE|CFM_WEIGHT; 1001 cf2.dwEffects = 0; 1002 strcpy(cf2.szFaceName, "Courier New"); 1003 cf2.wWeight = FW_DONTCARE; 1004 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 1005 1006 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1007 cf2.cbSize = sizeof(CHARFORMAT2A); 1008 cf2.dwMask = tested_effects[i]; 1009 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT) 1010 cf2.dwMask = CFM_SUPERSCRIPT; 1011 cf2.dwEffects = tested_effects[i]; 1012 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 1013 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1014 1015 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1016 cf2.cbSize = sizeof(CHARFORMAT2A); 1017 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 1018 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1019 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1020 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 1021 || 1022 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 1023 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 1024 ok((cf2.dwEffects & tested_effects[i]) == 0, 1025 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]); 1026 1027 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1028 cf2.cbSize = sizeof(CHARFORMAT2A); 1029 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4); 1030 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1031 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1032 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT) 1033 || 1034 (cf2.dwMask & tested_effects[i]) == tested_effects[i]), 1035 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]); 1036 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 1037 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]); 1038 1039 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1040 cf2.cbSize = sizeof(CHARFORMAT2A); 1041 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3); 1042 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1043 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) && 1044 (cf2.dwMask & CFM_SUPERSCRIPT) == 0) 1045 || 1046 (cf2.dwMask & tested_effects[i]) == 0), 1047 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]); 1048 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i], 1049 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]); 1050 1051 DestroyWindow(hwndRichEdit); 1052 } 1053 1054 /* Effects applied on an empty selection should take effect when selection is 1055 replaced with text */ 1056 hwndRichEdit = new_richedit(NULL); 1057 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1058 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1059 1060 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1061 cf2.cbSize = sizeof(CHARFORMAT2A); 1062 cf2.dwMask = CFM_BOLD; 1063 cf2.dwEffects = CFE_BOLD; 1064 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1065 1066 /* Selection is now nonempty */ 1067 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1068 1069 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1070 cf2.cbSize = sizeof(CHARFORMAT2A); 1071 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1072 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1073 1074 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1075 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1076 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1077 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1078 1079 1080 /* Set two effects on an empty selection */ 1081 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1082 /* first clear bold, italic */ 1083 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1084 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1085 cf2.cbSize = sizeof(CHARFORMAT2A); 1086 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1087 cf2.dwEffects = 0; 1088 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1089 1090 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1091 1092 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1093 cf2.cbSize = sizeof(CHARFORMAT2A); 1094 cf2.dwMask = CFM_BOLD; 1095 cf2.dwEffects = CFE_BOLD; 1096 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1097 cf2.dwMask = CFM_ITALIC; 1098 cf2.dwEffects = CFE_ITALIC; 1099 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1100 1101 /* Selection is now nonempty */ 1102 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1103 1104 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1105 cf2.cbSize = sizeof(CHARFORMAT2A); 1106 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1107 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1108 1109 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)), 1110 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC)); 1111 ok((cf2.dwEffects & (CFE_BOLD|CFE_ITALIC)) == (CFE_BOLD|CFE_ITALIC), 1112 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC)); 1113 1114 /* Setting the (empty) selection to exactly the same place as before should 1115 NOT clear the insertion style! */ 1116 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1117 /* first clear bold, italic */ 1118 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1119 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1120 cf2.cbSize = sizeof(CHARFORMAT2A); 1121 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1122 cf2.dwEffects = 0; 1123 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1124 1125 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1126 1127 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1128 cf2.cbSize = sizeof(CHARFORMAT2A); 1129 cf2.dwMask = CFM_BOLD; 1130 cf2.dwEffects = CFE_BOLD; 1131 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1132 1133 /* Empty selection in same place, insert style should NOT be forgotten here. */ 1134 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); 1135 1136 /* Selection is now nonempty */ 1137 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1138 1139 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1140 cf2.cbSize = sizeof(CHARFORMAT2A); 1141 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1142 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1143 1144 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1145 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1146 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1147 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1148 1149 /* Moving the selection will clear the insertion style */ 1150 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1151 /* first clear bold, italic */ 1152 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1153 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1154 cf2.cbSize = sizeof(CHARFORMAT2A); 1155 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1156 cf2.dwEffects = 0; 1157 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1158 1159 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1160 1161 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1162 cf2.cbSize = sizeof(CHARFORMAT2A); 1163 cf2.dwMask = CFM_BOLD; 1164 cf2.dwEffects = CFE_BOLD; 1165 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1166 1167 /* Move selection and then put it back, insert style should be forgotten here. */ 1168 SendMessageA(hwndRichEdit, EM_SETSEL, 3, 3); 1169 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */ 1170 1171 /* Selection is now nonempty */ 1172 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1173 1174 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1175 cf2.cbSize = sizeof(CHARFORMAT2A); 1176 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6); 1177 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1178 1179 ok(((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1180 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1181 ok((cf2.dwEffects & CFE_BOLD) == 0, 1182 "%d, cf2.dwEffects == 0x%08x not expecting effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1183 1184 /* Ditto with EM_EXSETSEL */ 1185 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1186 /* first clear bold, italic */ 1187 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1188 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1189 cf2.cbSize = sizeof(CHARFORMAT2A); 1190 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1191 cf2.dwEffects = 0; 1192 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1193 1194 cr.cpMin = 2; cr.cpMax = 2; 1195 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1196 1197 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1198 cf2.cbSize = sizeof(CHARFORMAT2A); 1199 cf2.dwMask = CFM_BOLD; 1200 cf2.dwEffects = CFE_BOLD; 1201 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1202 1203 /* Empty selection in same place, insert style should NOT be forgotten here. */ 1204 cr.cpMin = 2; cr.cpMax = 2; 1205 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1206 1207 /* Selection is now nonempty */ 1208 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi"); 1209 1210 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1211 cf2.cbSize = sizeof(CHARFORMAT2A); 1212 cr.cpMin = 2; cr.cpMax = 6; 1213 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */ 1214 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1215 1216 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD), 1217 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD); 1218 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD, 1219 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD); 1220 1221 /* show that wWeight is at the correct offset in CHARFORMAT2A */ 1222 memset(&cf2, 0, sizeof(cf2)); 1223 cf2.cbSize = sizeof(cf2); 1224 cf2.dwMask = CFM_WEIGHT; 1225 cf2.wWeight = 100; 1226 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1227 memset(&cf2, 0, sizeof(cf2)); 1228 cf2.cbSize = sizeof(cf2); 1229 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1230 ok(cf2.wWeight == 100, "got %d\n", cf2.wWeight); 1231 1232 memset(&cf2, 0, sizeof(cf2)); 1233 cf2.cbSize = sizeof(cf2); 1234 cf2.dwMask = CFM_SPACING; 1235 cf2.sSpacing = 10; 1236 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1237 memset(&cf2, 0, sizeof(cf2)); 1238 cf2.cbSize = sizeof(cf2); 1239 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1240 ok(cf2.sSpacing == 10, "got %d\n", cf2.sSpacing); 1241 1242 /* show that wWeight is at the correct offset in CHARFORMAT2W */ 1243 memset(&cfW, 0, sizeof(cfW)); 1244 cfW.cbSize = sizeof(cfW); 1245 cfW.dwMask = CFM_WEIGHT; 1246 cfW.wWeight = 100; 1247 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1248 memset(&cfW, 0, sizeof(cfW)); 1249 cfW.cbSize = sizeof(cfW); 1250 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1251 ok(cfW.wWeight == 100, "got %d\n", cfW.wWeight); 1252 1253 memset(&cfW, 0, sizeof(cfW)); 1254 cfW.cbSize = sizeof(cfW); 1255 cfW.dwMask = CFM_SPACING; 1256 cfW.sSpacing = 10; 1257 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1258 memset(&cfW, 0, sizeof(cfW)); 1259 cfW.cbSize = sizeof(cfW); 1260 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW); 1261 ok(cfW.sSpacing == 10, "got %d\n", cfW.sSpacing); 1262 1263 /* test CFE_UNDERLINE and bUnderlineType interaction */ 1264 /* clear bold, italic */ 1265 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 1266 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1267 cf2.cbSize = sizeof(CHARFORMAT2A); 1268 cf2.dwMask = CFM_BOLD | CFM_ITALIC; 1269 cf2.dwEffects = 0; 1270 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1271 1272 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */ 1273 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1274 cf2.cbSize = sizeof(CHARFORMAT2A); 1275 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1276 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1277 "got %08x\n", cf2.dwMask); 1278 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1279 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType); 1280 1281 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */ 1282 cf2.dwMask = CFM_UNDERLINETYPE; 1283 cf2.bUnderlineType = CFU_UNDERLINE; 1284 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1285 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1286 cf2.cbSize = sizeof(CHARFORMAT2A); 1287 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1288 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1289 "got %08x\n", cf2.dwMask); 1290 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1291 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType); 1292 1293 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */ 1294 cf2.dwMask = CFM_UNDERLINETYPE; 1295 cf2.bUnderlineType = CFU_UNDERLINENONE; 1296 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1297 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1298 cf2.cbSize = sizeof(CHARFORMAT2A); 1299 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1300 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1301 "got %08x\n", cf2.dwMask); 1302 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1303 ok(cf2.bUnderlineType == CFU_UNDERLINENONE, "got %x\n", cf2.bUnderlineType); 1304 1305 /* another underline type also sets CFE_UNDERLINE */ 1306 cf2.dwMask = CFM_UNDERLINETYPE; 1307 cf2.bUnderlineType = CFU_UNDERLINEDOUBLE; 1308 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1309 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1310 cf2.cbSize = sizeof(CHARFORMAT2A); 1311 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1312 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1313 "got %08x\n", cf2.dwMask); 1314 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1315 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1316 1317 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */ 1318 cf2.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; 1319 cf2.bUnderlineType = CFU_UNDERLINEDOUBLE; 1320 cf2.dwEffects = 0; 1321 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1322 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1323 cf2.cbSize = sizeof(CHARFORMAT2A); 1324 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1325 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1326 "got %08x\n", cf2.dwMask); 1327 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects); 1328 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1329 1330 /* And turing it back on again by just setting CFE_UNDERLINE */ 1331 cf2.dwMask = CFM_UNDERLINE; 1332 cf2.dwEffects = CFE_UNDERLINE; 1333 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1334 memset(&cf2, 0, sizeof(CHARFORMAT2A)); 1335 cf2.cbSize = sizeof(CHARFORMAT2A); 1336 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1337 ok((cf2.dwMask & (CFM_UNDERLINE | CFM_UNDERLINETYPE)) == (CFM_UNDERLINE | CFM_UNDERLINETYPE), 1338 "got %08x\n", cf2.dwMask); 1339 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); 1340 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); 1341 1342 DestroyWindow(hwndRichEdit); 1343 } 1344 1345 static void test_EM_SETTEXTMODE(void) 1346 { 1347 HWND hwndRichEdit = new_richedit(NULL); 1348 CHARFORMAT2A cf2, cf2test; 1349 CHARRANGE cr; 1350 int rc = 0; 1351 1352 /*Attempt to use mutually exclusive modes*/ 1353 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT|TM_RICHTEXT, 0); 1354 ok(rc == E_INVALIDARG, 1355 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc); 1356 1357 /*Test that EM_SETTEXTMODE fails if text exists within the control*/ 1358 /*Insert text into the control*/ 1359 1360 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1361 1362 /*Attempt to change the control to plain text mode*/ 1363 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 1364 ok(rc == E_UNEXPECTED, 1365 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc); 1366 1367 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted. 1368 If rich text is pasted, it should have the same formatting as the rest 1369 of the text in the control*/ 1370 1371 /*Italicize the text 1372 *NOTE: If the default text was already italicized, the test will simply 1373 reverse; in other words, it will copy a regular "wine" into a plain 1374 text window that uses an italicized format*/ 1375 cf2.cbSize = sizeof(CHARFORMAT2A); 1376 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2); 1377 1378 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 1379 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 1380 1381 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 1382 ok(rc == 0, "Text marked as modified, expected not modified!\n"); 1383 1384 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine; 1385 however, SCF_ALL has been implemented*/ 1386 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 1387 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1388 1389 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 1390 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); 1391 1392 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1393 1394 /*Select the string "wine"*/ 1395 cr.cpMin = 0; 1396 cr.cpMax = 4; 1397 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1398 1399 /*Copy the italicized "wine" to the clipboard*/ 1400 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 1401 1402 /*Reset the formatting to default*/ 1403 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects; 1404 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2); 1405 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1406 1407 /*Clear the text in the control*/ 1408 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1409 1410 /*Switch to Plain Text Mode*/ 1411 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 1412 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc); 1413 1414 /*Input "wine" again in normal format*/ 1415 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1416 1417 /*Paste the italicized "wine" into the control*/ 1418 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1419 1420 /*Select a character from the first "wine" string*/ 1421 cr.cpMin = 2; 1422 cr.cpMax = 3; 1423 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1424 1425 /*Retrieve its formatting*/ 1426 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 1427 1428 /*Select a character from the second "wine" string*/ 1429 cr.cpMin = 5; 1430 cr.cpMax = 6; 1431 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1432 1433 /*Retrieve its formatting*/ 1434 cf2test.cbSize = sizeof(CHARFORMAT2A); 1435 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test); 1436 1437 /*Compare the two formattings*/ 1438 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1439 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n", 1440 cf2.dwEffects, cf2test.dwEffects); 1441 /*Test TM_RICHTEXT by: switching back to Rich Text mode 1442 printing "wine" in the current format(normal) 1443 pasting "wine" from the clipboard(italicized) 1444 comparing the two formats(should differ)*/ 1445 1446 /*Attempt to switch with text in control*/ 1447 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0); 1448 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc); 1449 1450 /*Clear control*/ 1451 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1452 1453 /*Switch into Rich Text mode*/ 1454 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0); 1455 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc); 1456 1457 /*Print "wine" in normal formatting into the control*/ 1458 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1459 1460 /*Paste italicized "wine" into the control*/ 1461 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1462 1463 /*Select text from the first "wine" string*/ 1464 cr.cpMin = 1; 1465 cr.cpMax = 3; 1466 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1467 1468 /*Retrieve its formatting*/ 1469 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2); 1470 1471 /*Select text from the second "wine" string*/ 1472 cr.cpMin = 6; 1473 cr.cpMax = 7; 1474 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1475 1476 /*Retrieve its formatting*/ 1477 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test); 1478 1479 /*Test that the two formattings are not the same*/ 1480 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects), 1481 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1482 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1483 1484 DestroyWindow(hwndRichEdit); 1485 } 1486 1487 static void test_SETPARAFORMAT(void) 1488 { 1489 HWND hwndRichEdit = new_richedit(NULL); 1490 PARAFORMAT2 fmt; 1491 HRESULT ret; 1492 LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER; 1493 fmt.cbSize = sizeof(PARAFORMAT2); 1494 fmt.dwMask = PFM_ALIGNMENT; 1495 fmt.wAlignment = PFA_LEFT; 1496 1497 ret = SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt); 1498 ok(ret != 0, "expected non-zero got %d\n", ret); 1499 1500 fmt.cbSize = sizeof(PARAFORMAT2); 1501 fmt.dwMask = -1; 1502 ret = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 1503 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes 1504 * between richedit different native builds of riched20.dll 1505 * used on different Windows versions. */ 1506 ret &= ~PFM_TABLEROWDELIMITER; 1507 fmt.dwMask &= ~PFM_TABLEROWDELIMITER; 1508 1509 ok(ret == expectedMask, "expected %x got %x\n", expectedMask, ret); 1510 ok(fmt.dwMask == expectedMask, "expected %x got %x\n", expectedMask, fmt.dwMask); 1511 1512 /* Test some other paraformat field defaults */ 1513 ok( fmt.wNumbering == 0, "got %d\n", fmt.wNumbering ); 1514 ok( fmt.wNumberingStart == 0, "got %d\n", fmt.wNumberingStart ); 1515 ok( fmt.wNumberingStyle == 0, "got %04x\n", fmt.wNumberingStyle ); 1516 ok( fmt.wNumberingTab == 0, "got %d\n", fmt.wNumberingTab ); 1517 1518 DestroyWindow(hwndRichEdit); 1519 } 1520 1521 static void test_TM_PLAINTEXT(void) 1522 { 1523 /*Tests plain text properties*/ 1524 1525 HWND hwndRichEdit = new_richedit(NULL); 1526 CHARFORMAT2A cf2, cf2test; 1527 CHARRANGE cr; 1528 int rc = 0; 1529 1530 /*Switch to plain text mode*/ 1531 1532 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1533 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0); 1534 1535 /*Fill control with text*/ 1536 1537 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Is Wine an emulator? No it's not"); 1538 1539 /*Select some text and bold it*/ 1540 1541 cr.cpMin = 10; 1542 cr.cpMax = 20; 1543 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1544 cf2.cbSize = sizeof(CHARFORMAT2A); 1545 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 1546 1547 cf2.dwMask = CFM_BOLD | cf2.dwMask; 1548 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects; 1549 1550 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1551 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc); 1552 1553 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_WORD | 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_ALL, (LPARAM)&cf2); 1557 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1558 1559 /*Get the formatting of those characters*/ 1560 1561 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1562 1563 /*Get the formatting of some other characters*/ 1564 cf2test.cbSize = sizeof(CHARFORMAT2A); 1565 cr.cpMin = 21; 1566 cr.cpMax = 30; 1567 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1568 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test); 1569 1570 /*Test that they are the same as plain text allows only one formatting*/ 1571 1572 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1573 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1574 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1575 1576 /*Fill the control with a "wine" string, which when inserted will be bold*/ 1577 1578 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1579 1580 /*Copy the bolded "wine" string*/ 1581 1582 cr.cpMin = 0; 1583 cr.cpMax = 4; 1584 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1585 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 1586 1587 /*Swap back to rich text*/ 1588 1589 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 1590 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_RICHTEXT, 0); 1591 1592 /*Set the default formatting to bold italics*/ 1593 1594 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 1595 cf2.dwMask |= CFM_ITALIC; 1596 cf2.dwEffects ^= CFE_ITALIC; 1597 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 1598 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); 1599 1600 /*Set the text in the control to "wine", which will be bold and italicized*/ 1601 1602 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); 1603 1604 /*Paste the plain text "wine" string, which should take the insert 1605 formatting, which at the moment is bold italics*/ 1606 1607 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 1608 1609 /*Select the first "wine" string and retrieve its formatting*/ 1610 1611 cr.cpMin = 1; 1612 cr.cpMax = 3; 1613 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1614 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); 1615 1616 /*Select the second "wine" string and retrieve its formatting*/ 1617 1618 cr.cpMin = 5; 1619 cr.cpMax = 7; 1620 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 1621 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test); 1622 1623 /*Compare the two formattings. They should be the same.*/ 1624 1625 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects), 1626 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n", 1627 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects); 1628 DestroyWindow(hwndRichEdit); 1629 } 1630 1631 static void test_WM_GETTEXT(void) 1632 { 1633 HWND hwndRichEdit = new_richedit(NULL); 1634 static const char text[] = "Hello. My name is RichEdit!"; 1635 static const char text2[] = "Hello. My name is RichEdit!\r"; 1636 static const char text2_after[] = "Hello. My name is RichEdit!\r\n"; 1637 char buffer[1024] = {0}; 1638 int result; 1639 1640 /* Baseline test with normal-sized buffer */ 1641 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1642 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1643 ok(result == lstrlenA(buffer), 1644 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer)); 1645 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1646 result = strcmp(buffer,text); 1647 ok(result == 0, 1648 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1649 1650 /* Test for returned value of WM_GETTEXTLENGTH */ 1651 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 1652 ok(result == lstrlenA(text), 1653 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", 1654 result, lstrlenA(text)); 1655 1656 /* Test for behavior in overflow case */ 1657 memset(buffer, 0, 1024); 1658 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer); 1659 ok(result == 0 || 1660 result == lstrlenA(text) - 1, /* XP, win2k3 */ 1661 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1); 1662 result = strcmp(buffer,text); 1663 if (result) 1664 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */ 1665 ok(result == 0, 1666 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1667 1668 /* Baseline test with normal-sized buffer and carriage return */ 1669 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1670 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1671 ok(result == lstrlenA(buffer), 1672 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer)); 1673 result = strcmp(buffer,text2_after); 1674 ok(result == 0, 1675 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1676 1677 /* Test for returned value of WM_GETTEXTLENGTH */ 1678 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 1679 ok(result == lstrlenA(text2_after), 1680 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", 1681 result, lstrlenA(text2_after)); 1682 1683 /* Test for behavior of CRLF conversion in case of overflow */ 1684 memset(buffer, 0, 1024); 1685 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer); 1686 ok(result == 0 || 1687 result == lstrlenA(text2) - 1, /* XP, win2k3 */ 1688 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1); 1689 result = strcmp(buffer,text2); 1690 if (result) 1691 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */ 1692 ok(result == 0, 1693 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); 1694 1695 DestroyWindow(hwndRichEdit); 1696 } 1697 1698 static void test_EM_GETTEXTRANGE(void) 1699 { 1700 HWND hwndRichEdit = new_richedit(NULL); 1701 const char * text1 = "foo bar\r\nfoo bar"; 1702 const char * text2 = "foo bar\rfoo bar"; 1703 const char * expect = "bar\rfoo"; 1704 char buffer[1024] = {0}; 1705 LRESULT result; 1706 TEXTRANGEA textRange; 1707 1708 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 1709 1710 textRange.lpstrText = buffer; 1711 textRange.chrg.cpMin = 4; 1712 textRange.chrg.cpMax = 11; 1713 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1714 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); 1715 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1716 1717 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1718 1719 textRange.lpstrText = buffer; 1720 textRange.chrg.cpMin = 4; 1721 textRange.chrg.cpMax = 11; 1722 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1723 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); 1724 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1725 1726 /* cpMax of text length is used instead of -1 in this case */ 1727 textRange.lpstrText = buffer; 1728 textRange.chrg.cpMin = 0; 1729 textRange.chrg.cpMax = -1; 1730 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1731 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); 1732 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1733 1734 /* cpMin < 0 causes no text to be copied, and 0 to be returned */ 1735 textRange.lpstrText = buffer; 1736 textRange.chrg.cpMin = -1; 1737 textRange.chrg.cpMax = 1; 1738 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1739 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1740 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1741 1742 /* cpMax of -1 is not replaced with text length if cpMin != 0 */ 1743 textRange.lpstrText = buffer; 1744 textRange.chrg.cpMin = 1; 1745 textRange.chrg.cpMax = -1; 1746 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1747 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1748 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1749 1750 /* no end character is copied if cpMax - cpMin < 0 */ 1751 textRange.lpstrText = buffer; 1752 textRange.chrg.cpMin = 5; 1753 textRange.chrg.cpMax = 5; 1754 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1755 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); 1756 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1757 1758 /* cpMax of text length is used if cpMax > text length*/ 1759 textRange.lpstrText = buffer; 1760 textRange.chrg.cpMin = 0; 1761 textRange.chrg.cpMax = 1000; 1762 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1763 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); 1764 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1765 1766 /* Test with multibyte character */ 1767 if (!is_lang_japanese) 1768 skip("Skip multibyte character tests on non-Japanese platform\n"); 1769 else 1770 { 1771 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 1772 textRange.chrg.cpMin = 4; 1773 textRange.chrg.cpMax = 8; 1774 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); 1775 todo_wine ok(result == 5, "EM_GETTEXTRANGE returned %ld\n", result); 1776 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETTEXTRANGE filled %s\n", buffer); 1777 } 1778 1779 DestroyWindow(hwndRichEdit); 1780 } 1781 1782 static void test_EM_GETSELTEXT(void) 1783 { 1784 HWND hwndRichEdit = new_richedit(NULL); 1785 const char * text1 = "foo bar\r\nfoo bar"; 1786 const char * text2 = "foo bar\rfoo bar"; 1787 const char * expect = "bar\rfoo"; 1788 char buffer[1024] = {0}; 1789 LRESULT result; 1790 1791 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 1792 1793 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11); 1794 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1795 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result); 1796 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer); 1797 1798 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 1799 1800 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11); 1801 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1802 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result); 1803 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer); 1804 1805 /* Test with multibyte character */ 1806 if (!is_lang_japanese) 1807 skip("Skip multibyte character tests on non-Japanese platform\n"); 1808 else 1809 { 1810 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 1811 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8); 1812 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); 1813 todo_wine ok(result == 5, "EM_GETSELTEXT returned %ld\n", result); 1814 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETSELTEXT filled %s\n", buffer); 1815 } 1816 1817 DestroyWindow(hwndRichEdit); 1818 } 1819 1820 /* FIXME: need to test unimplemented options and robustly test wparam */ 1821 static void test_EM_SETOPTIONS(void) 1822 { 1823 HWND hwndRichEdit; 1824 static const char text[] = "Hello. My name is RichEdit!"; 1825 char buffer[1024] = {0}; 1826 DWORD dwStyle, options, oldOptions; 1827 DWORD optionStyles = ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL| 1828 ES_READONLY|ES_WANTRETURN|ES_SAVESEL| 1829 ES_SELECTIONBAR|ES_VERTICAL; 1830 1831 /* Test initial options. */ 1832 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, WS_POPUP, 1833 0, 0, 200, 60, NULL, NULL, 1834 hmoduleRichEdit, NULL); 1835 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", 1836 RICHEDIT_CLASS20A, (int) GetLastError()); 1837 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1838 ok(options == 0, "Incorrect initial options %x\n", options); 1839 DestroyWindow(hwndRichEdit); 1840 1841 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL, 1842 WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 1843 0, 0, 200, 60, NULL, NULL, 1844 hmoduleRichEdit, NULL); 1845 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", 1846 RICHEDIT_CLASS20A, (int) GetLastError()); 1847 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1848 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */ 1849 ok(options == (ECO_AUTOVSCROLL|ECO_AUTOHSCROLL), 1850 "Incorrect initial options %x\n", options); 1851 1852 /* NEGATIVE TESTING - NO OPTIONS SET */ 1853 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1854 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0); 1855 1856 /* testing no readonly by sending 'a' to the control*/ 1857 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001); 1858 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1859 ok(buffer[0]=='a', 1860 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer); 1861 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1862 1863 /* READONLY - sending 'a' to the control */ 1864 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 1865 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY); 1866 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001); 1867 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1868 ok(buffer[0]==text[0], 1869 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); 1870 1871 /* EM_SETOPTIONS changes the window style, but changing the 1872 * window style does not change the options. */ 1873 dwStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE); 1874 ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n"); 1875 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY); 1876 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1877 ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n"); 1878 /* Confirm that the text is still read only. */ 1879 SendMessageA(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001); 1880 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 1881 ok(buffer[0]==text[0], 1882 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); 1883 1884 oldOptions = options; 1885 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles); 1886 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0); 1887 ok(options == oldOptions, 1888 "Options set by SetWindowLong (%x -> %x)\n", oldOptions, options); 1889 1890 DestroyWindow(hwndRichEdit); 1891 } 1892 1893 static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end) 1894 { 1895 CHARFORMAT2A text_format; 1896 text_format.cbSize = sizeof(text_format); 1897 SendMessageA(hwnd, EM_SETSEL, sel_start, sel_end); 1898 SendMessageA(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&text_format); 1899 return (text_format.dwEffects & CFE_LINK) != 0; 1900 } 1901 1902 static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char * url) 1903 { 1904 BOOL link_present = FALSE; 1905 1906 link_present = check_CFE_LINK_selection(hwnd, 0, 1); 1907 if (is_url) 1908 { /* control text is url; should get CFE_LINK */ 1909 ok(link_present, "URL Case: CFE_LINK not set for [%s].\n", url); 1910 } 1911 else 1912 { 1913 ok(!link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url); 1914 } 1915 } 1916 1917 static HWND new_static_wnd(HWND parent) { 1918 return new_window("Static", 0, parent); 1919 } 1920 1921 static void test_EM_AUTOURLDETECT(void) 1922 { 1923 /* DO NOT change the properties of the first two elements. To shorten the 1924 tests, all tests after WM_SETTEXT test just the first two elements - 1925 one non-URL and one URL */ 1926 struct urls_s { 1927 const char *text; 1928 BOOL is_url; 1929 } urls[12] = { 1930 {"winehq.org", FALSE}, 1931 {"http://www.winehq.org", TRUE}, 1932 {"http//winehq.org", FALSE}, 1933 {"ww.winehq.org", FALSE}, 1934 {"www.winehq.org", TRUE}, 1935 {"ftp://192.168.1.1", TRUE}, 1936 {"ftp//192.168.1.1", FALSE}, 1937 {"mailto:your@email.com", TRUE}, 1938 {"prospero:prosperoserver", TRUE}, 1939 {"telnet:test", TRUE}, 1940 {"news:newserver", TRUE}, 1941 {"wais:waisserver", TRUE} 1942 }; 1943 1944 int i, j; 1945 int urlRet=-1; 1946 HWND hwndRichEdit, parent; 1947 1948 /* All of the following should cause the URL to be detected */ 1949 const char * templates_delim[] = { 1950 "This is some text with X on it", 1951 "This is some text with (X) on it", 1952 "This is some text with X\r on it", 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' on it", 1956 "This is some text with 'X' on it", 1957 "This is some text with :X: on it", 1958 1959 "This text ends with X", 1960 1961 "This is some text with X) on it", 1962 "This is some text with X--- on it", 1963 "This is some text with X\" on it", 1964 "This is some text with X' on it", 1965 "This is some text with X: on it", 1966 1967 "This is some text with (X on it", 1968 "This is some text with \rX on it", 1969 "This is some text with ---X on it", 1970 "This is some text with \"X on it", 1971 "This is some text with 'X on it", 1972 "This is some text with :X on it", 1973 }; 1974 /* None of these should cause the URL to be detected */ 1975 const char * templates_non_delim[] = { 1976 "This is some text with |X| on it", 1977 "This is some text with *X* on it", 1978 "This is some text with /X/ on it", 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 }; 1994 /* All of these cause the URL detection to be extended by one more byte, 1995 thus demonstrating that the tested character is considered as part 1996 of the URL. */ 1997 const char * templates_xten_delim[] = { 1998 "This is some text with X| on it", 1999 "This is some text with X* on it", 2000 "This is some text with X/ on it", 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 }; 2008 /* These delims act as neutral breaks. Whether the url is ended 2009 or not depends on the next non-neutral character. We'll test 2010 with Y unchanged, in which case the url should include the 2011 deliminator and the Y. We'll also test with the Y changed 2012 to a space, in which case the url stops before the 2013 deliminator. */ 2014 const char * templates_neutral_delim[] = { 2015 "This is some text with X-Y on it", 2016 "This is some text with X--Y on it", 2017 "This is some text with X!Y on it", 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 }; 2034 char buffer[1024]; 2035 2036 parent = new_static_wnd(NULL); 2037 hwndRichEdit = new_richedit(parent); 2038 /* Try and pass EM_AUTOURLDETECT some test wParam values */ 2039 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0); 2040 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet); 2041 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 1, 0); 2042 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet); 2043 /* Windows returns -2147024809 (0x80070057) on bad wParam values */ 2044 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 8, 0); 2045 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet); 2046 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h"); 2047 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet); 2048 /* for each url, check the text to see if CFE_LINK effect is present */ 2049 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { 2050 2051 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0); 2052 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text); 2053 check_CFE_LINK_rcvd(hwndRichEdit, FALSE, urls[i].text); 2054 2055 /* Link detection should happen immediately upon WM_SETTEXT */ 2056 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2057 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text); 2058 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text); 2059 } 2060 DestroyWindow(hwndRichEdit); 2061 2062 /* Test detection of URLs within normal text - WM_SETTEXT case. */ 2063 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { 2064 hwndRichEdit = new_richedit(parent); 2065 2066 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2067 char * at_pos; 2068 int at_offset; 2069 int end_offset; 2070 2071 at_pos = strchr(templates_delim[j], 'X'); 2072 at_offset = at_pos - templates_delim[j]; 2073 memcpy(buffer, templates_delim[j], at_offset); 2074 buffer[at_offset] = '\0'; 2075 strcat(buffer, urls[i].text); 2076 strcat(buffer, templates_delim[j] + at_offset + 1); 2077 end_offset = at_offset + strlen(urls[i].text); 2078 2079 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2080 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2081 2082 /* This assumes no templates start with the URL itself, and that they 2083 have at least two characters before the URL text */ 2084 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2085 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2086 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2087 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2088 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2089 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2090 2091 if (urls[i].is_url) 2092 { 2093 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2094 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2095 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2096 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2097 } 2098 else 2099 { 2100 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2101 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2102 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2103 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2104 } 2105 if (buffer[end_offset] != '\0') 2106 { 2107 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2108 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2109 if (buffer[end_offset +1] != '\0') 2110 { 2111 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2112 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2113 } 2114 } 2115 } 2116 2117 for (j = 0; j < sizeof(templates_non_delim) / sizeof(const char *); j++) { 2118 char * at_pos; 2119 int at_offset; 2120 int end_offset; 2121 2122 at_pos = strchr(templates_non_delim[j], 'X'); 2123 at_offset = at_pos - templates_non_delim[j]; 2124 memcpy(buffer, templates_non_delim[j], at_offset); 2125 buffer[at_offset] = '\0'; 2126 strcat(buffer, urls[i].text); 2127 strcat(buffer, templates_non_delim[j] + at_offset + 1); 2128 end_offset = at_offset + strlen(urls[i].text); 2129 2130 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2131 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2132 2133 /* This assumes no templates start with the URL itself, and that they 2134 have at least two characters before the URL text */ 2135 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2136 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2137 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2138 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2139 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2140 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2141 2142 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2143 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2144 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2145 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2146 if (buffer[end_offset] != '\0') 2147 { 2148 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2149 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2150 if (buffer[end_offset +1] != '\0') 2151 { 2152 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2153 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2154 } 2155 } 2156 } 2157 2158 for (j = 0; j < sizeof(templates_xten_delim) / sizeof(const char *); j++) { 2159 char * at_pos; 2160 int at_offset; 2161 int end_offset; 2162 2163 at_pos = strchr(templates_xten_delim[j], 'X'); 2164 at_offset = at_pos - templates_xten_delim[j]; 2165 memcpy(buffer, templates_xten_delim[j], at_offset); 2166 buffer[at_offset] = '\0'; 2167 strcat(buffer, urls[i].text); 2168 strcat(buffer, templates_xten_delim[j] + at_offset + 1); 2169 end_offset = at_offset + strlen(urls[i].text); 2170 2171 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2172 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2173 2174 /* This assumes no templates start with the URL itself, and that they 2175 have at least two characters before the URL text */ 2176 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2177 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2178 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2179 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2180 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2181 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2182 2183 if (urls[i].is_url) 2184 { 2185 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2186 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2187 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2188 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2189 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2190 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2191 } 2192 else 2193 { 2194 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2195 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2196 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2197 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2198 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2199 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2200 } 2201 if (buffer[end_offset +1] != '\0') 2202 { 2203 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2204 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer); 2205 if (buffer[end_offset +2] != '\0') 2206 { 2207 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3), 2208 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer); 2209 } 2210 } 2211 } 2212 2213 for (j = 0; j < sizeof(templates_neutral_delim) / sizeof(const char *); j++) { 2214 char * at_pos, * end_pos; 2215 int at_offset; 2216 int end_offset; 2217 2218 if (!urls[i].is_url) continue; 2219 2220 at_pos = strchr(templates_neutral_delim[j], 'X'); 2221 at_offset = at_pos - templates_neutral_delim[j]; 2222 memcpy(buffer, templates_neutral_delim[j], at_offset); 2223 buffer[at_offset] = '\0'; 2224 strcat(buffer, urls[i].text); 2225 strcat(buffer, templates_neutral_delim[j] + at_offset + 1); 2226 2227 end_pos = strchr(buffer, 'Y'); 2228 end_offset = end_pos - buffer; 2229 2230 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2231 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2232 2233 /* This assumes no templates start with the URL itself, and that they 2234 have at least two characters before the URL text */ 2235 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2236 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2237 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2238 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2239 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2240 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2241 2242 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2243 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2244 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2245 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2246 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2247 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2248 2249 *end_pos = ' '; 2250 2251 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2252 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer); 2253 2254 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2255 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2256 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2257 "CFE_LINK set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2258 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2259 "CFE_LINK set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer); 2260 } 2261 2262 DestroyWindow(hwndRichEdit); 2263 hwndRichEdit = NULL; 2264 } 2265 2266 /* Test detection of URLs within normal text - WM_CHAR case. */ 2267 /* Test only the first two URL examples for brevity */ 2268 for (i = 0; i < 2; i++) { 2269 hwndRichEdit = new_richedit(parent); 2270 2271 /* Also for brevity, test only the first three delimiters */ 2272 for (j = 0; j < 3; j++) { 2273 char * at_pos; 2274 int at_offset; 2275 int end_offset; 2276 int u, v; 2277 2278 at_pos = strchr(templates_delim[j], 'X'); 2279 at_offset = at_pos - templates_delim[j]; 2280 end_offset = at_offset + strlen(urls[i].text); 2281 2282 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2283 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2284 for (u = 0; templates_delim[j][u]; u++) { 2285 if (templates_delim[j][u] == '\r') { 2286 simulate_typing_characters(hwndRichEdit, "\r"); 2287 } else if (templates_delim[j][u] != 'X') { 2288 SendMessageA(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1); 2289 } else { 2290 for (v = 0; urls[i].text[v]; v++) { 2291 SendMessageA(hwndRichEdit, WM_CHAR, urls[i].text[v], 1); 2292 } 2293 } 2294 } 2295 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2296 2297 /* This assumes no templates start with the URL itself, and that they 2298 have at least two characters before the URL text */ 2299 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2300 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2301 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2302 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2303 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2304 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2305 2306 if (urls[i].is_url) 2307 { 2308 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2309 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2310 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2311 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2312 } 2313 else 2314 { 2315 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2316 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2317 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2318 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2319 } 2320 if (buffer[end_offset] != '\0') 2321 { 2322 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2323 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2324 if (buffer[end_offset +1] != '\0') 2325 { 2326 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2327 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2328 } 2329 } 2330 2331 /* The following will insert a paragraph break after the first character 2332 of the URL candidate, thus breaking the URL. It is expected that the 2333 CFE_LINK attribute should break across both pieces of the URL */ 2334 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1); 2335 simulate_typing_characters(hwndRichEdit, "\r"); 2336 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2337 2338 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2339 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2340 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2341 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2342 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2343 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2344 2345 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2346 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2347 /* end_offset moved because of paragraph break */ 2348 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2349 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer); 2350 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer); 2351 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0') 2352 { 2353 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2), 2354 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer); 2355 if (buffer[end_offset +2] != '\0') 2356 { 2357 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3), 2358 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer); 2359 } 2360 } 2361 2362 /* The following will remove the just-inserted paragraph break, thus 2363 restoring the URL */ 2364 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2); 2365 simulate_typing_characters(hwndRichEdit, "\b"); 2366 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2367 2368 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2369 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2370 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2371 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2372 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2373 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2374 2375 if (urls[i].is_url) 2376 { 2377 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2378 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2379 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2380 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2381 } 2382 else 2383 { 2384 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2385 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2386 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2387 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2388 } 2389 if (buffer[end_offset] != '\0') 2390 { 2391 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2392 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2393 if (buffer[end_offset +1] != '\0') 2394 { 2395 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2396 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2397 } 2398 } 2399 } 2400 DestroyWindow(hwndRichEdit); 2401 hwndRichEdit = NULL; 2402 } 2403 2404 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */ 2405 /* Test just the first two URL examples for brevity */ 2406 for (i = 0; i < 2; i++) { 2407 SETTEXTEX st; 2408 2409 hwndRichEdit = new_richedit(parent); 2410 2411 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to 2412 be detected: 2413 1) Set entire text, a la WM_SETTEXT 2414 2) Set a selection of the text to the URL 2415 3) Set a portion of the text at a time, which eventually results in 2416 an URL 2417 All of them should give equivalent results 2418 */ 2419 2420 /* Set entire text in one go, like WM_SETTEXT */ 2421 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2422 char * at_pos; 2423 int at_offset; 2424 int end_offset; 2425 2426 st.codepage = CP_ACP; 2427 st.flags = ST_DEFAULT; 2428 2429 at_pos = strchr(templates_delim[j], 'X'); 2430 at_offset = at_pos - templates_delim[j]; 2431 memcpy(buffer, templates_delim[j], at_offset); 2432 buffer[at_offset] = '\0'; 2433 strcat(buffer, urls[i].text); 2434 strcat(buffer, templates_delim[j] + at_offset + 1); 2435 end_offset = at_offset + strlen(urls[i].text); 2436 2437 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2438 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer); 2439 2440 /* This assumes no templates start with the URL itself, and that they 2441 have at least two characters before the URL text */ 2442 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2443 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2444 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2445 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2446 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2447 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2448 2449 if (urls[i].is_url) 2450 { 2451 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2452 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2453 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2454 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2455 } 2456 else 2457 { 2458 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2459 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2460 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2461 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2462 } 2463 if (buffer[end_offset] != '\0') 2464 { 2465 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2466 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2467 if (buffer[end_offset +1] != '\0') 2468 { 2469 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2470 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2471 } 2472 } 2473 } 2474 2475 /* Set selection with X to the URL */ 2476 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2477 char * at_pos; 2478 int at_offset; 2479 int end_offset; 2480 2481 at_pos = strchr(templates_delim[j], 'X'); 2482 at_offset = at_pos - templates_delim[j]; 2483 end_offset = at_offset + strlen(urls[i].text); 2484 2485 st.codepage = CP_ACP; 2486 st.flags = ST_DEFAULT; 2487 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2488 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]); 2489 st.flags = ST_SELECTION; 2490 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2491 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)urls[i].text); 2492 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2493 2494 /* This assumes no templates start with the URL itself, and that they 2495 have at least two characters before the URL text */ 2496 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2497 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2498 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2499 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2500 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2501 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2502 2503 if (urls[i].is_url) 2504 { 2505 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2506 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2507 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2508 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2509 } 2510 else 2511 { 2512 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2513 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2514 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2515 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2516 } 2517 if (buffer[end_offset] != '\0') 2518 { 2519 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2520 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2521 if (buffer[end_offset +1] != '\0') 2522 { 2523 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2524 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2525 } 2526 } 2527 } 2528 2529 /* Set selection with X to the first character of the URL, then the rest */ 2530 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2531 char * at_pos; 2532 int at_offset; 2533 int end_offset; 2534 2535 at_pos = strchr(templates_delim[j], 'X'); 2536 at_offset = at_pos - templates_delim[j]; 2537 end_offset = at_offset + strlen(urls[i].text); 2538 2539 strcpy(buffer, "YY"); 2540 buffer[0] = urls[i].text[0]; 2541 2542 st.codepage = CP_ACP; 2543 st.flags = ST_DEFAULT; 2544 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2545 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]); 2546 st.flags = ST_SELECTION; 2547 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2548 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer); 2549 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2); 2550 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1)); 2551 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2552 2553 /* This assumes no templates start with the URL itself, and that they 2554 have at least two characters before the URL text */ 2555 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2556 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2557 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2558 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2559 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2560 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2561 2562 if (urls[i].is_url) 2563 { 2564 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2565 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2566 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2567 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2568 } 2569 else 2570 { 2571 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2572 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2573 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2574 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2575 } 2576 if (buffer[end_offset] != '\0') 2577 { 2578 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2579 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2580 if (buffer[end_offset +1] != '\0') 2581 { 2582 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2583 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2584 } 2585 } 2586 } 2587 2588 DestroyWindow(hwndRichEdit); 2589 hwndRichEdit = NULL; 2590 } 2591 2592 /* Test detection of URLs within normal text - EM_REPLACESEL case. */ 2593 /* Test just the first two URL examples for brevity */ 2594 for (i = 0; i < 2; i++) { 2595 hwndRichEdit = new_richedit(parent); 2596 2597 /* Set selection with X to the URL */ 2598 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2599 char * at_pos; 2600 int at_offset; 2601 int end_offset; 2602 2603 at_pos = strchr(templates_delim[j], 'X'); 2604 at_offset = at_pos - templates_delim[j]; 2605 end_offset = at_offset + strlen(urls[i].text); 2606 2607 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2608 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]); 2609 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2610 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urls[i].text); 2611 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2612 2613 /* This assumes no templates start with the URL itself, and that they 2614 have at least two characters before the URL text */ 2615 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2616 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2617 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2618 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2619 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2620 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2621 2622 if (urls[i].is_url) 2623 { 2624 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2625 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2626 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2627 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2628 } 2629 else 2630 { 2631 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2632 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2633 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2634 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2635 } 2636 if (buffer[end_offset] != '\0') 2637 { 2638 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2639 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2640 if (buffer[end_offset +1] != '\0') 2641 { 2642 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2643 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2644 } 2645 } 2646 } 2647 2648 /* Set selection with X to the first character of the URL, then the rest */ 2649 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { 2650 char * at_pos; 2651 int at_offset; 2652 int end_offset; 2653 2654 at_pos = strchr(templates_delim[j], 'X'); 2655 at_offset = at_pos - templates_delim[j]; 2656 end_offset = at_offset + strlen(urls[i].text); 2657 2658 strcpy(buffer, "YY"); 2659 buffer[0] = urls[i].text[0]; 2660 2661 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0); 2662 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]); 2663 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1); 2664 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)buffer); 2665 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2); 2666 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1)); 2667 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 2668 2669 /* This assumes no templates start with the URL itself, and that they 2670 have at least two characters before the URL text */ 2671 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1), 2672 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer); 2673 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1), 2674 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer); 2675 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset), 2676 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer); 2677 2678 if (urls[i].is_url) 2679 { 2680 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2681 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer); 2682 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2683 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2684 } 2685 else 2686 { 2687 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1), 2688 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer); 2689 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset), 2690 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer); 2691 } 2692 if (buffer[end_offset] != '\0') 2693 { 2694 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1), 2695 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer); 2696 if (buffer[end_offset +1] != '\0') 2697 { 2698 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2), 2699 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer); 2700 } 2701 } 2702 } 2703 2704 DestroyWindow(hwndRichEdit); 2705 hwndRichEdit = NULL; 2706 } 2707 2708 DestroyWindow(parent); 2709 } 2710 2711 static void test_EM_SCROLL(void) 2712 { 2713 int i, j; 2714 int r; /* return value */ 2715 int expr; /* expected return value */ 2716 HWND hwndRichEdit = new_richedit(NULL); 2717 int y_before, y_after; /* units of lines of text */ 2718 2719 /* test a richedit box containing a single line of text */ 2720 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");/* one line of text */ 2721 expr = 0x00010000; 2722 for (i = 0; i < 4; i++) { 2723 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP }; 2724 2725 r = SendMessageA(hwndRichEdit, EM_SCROLL, cmd[i], 0); 2726 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2727 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). " 2728 "Got 0x%08x, expected 0x%08x\n", i, r, expr); 2729 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 " 2730 "(i == %d)\n", y_after, i); 2731 } 2732 2733 /* 2734 * test a richedit box that will scroll. There are two general 2735 * cases: the case without any long lines and the case with a long 2736 * line. 2737 */ 2738 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */ 2739 if (i == 0) 2740 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\nb\nc\nd\ne"); 2741 else 2742 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) 2743 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " 2744 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " 2745 "LONG LINE \nb\nc\nd\ne"); 2746 for (j = 0; j < 12; j++) /* reset scroll position to top */ 2747 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); 2748 2749 /* get first visible line */ 2750 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2751 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */ 2752 2753 /* get new current first visible line */ 2754 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2755 2756 ok(((r & 0xffffff00) == 0x00010000) && 2757 ((r & 0x000000ff) != 0x00000000), 2758 "EM_SCROLL page down didn't scroll by a small positive number of " 2759 "lines (r == 0x%08x)\n", r); 2760 ok(y_after > y_before, "EM_SCROLL page down not functioning " 2761 "(line %d scrolled to line %d\n", y_before, y_after); 2762 2763 y_before = y_after; 2764 2765 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */ 2766 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2767 ok(((r & 0xffffff00) == 0x0001ff00), 2768 "EM_SCROLL page up didn't scroll by a small negative number of lines " 2769 "(r == 0x%08x)\n", r); 2770 ok(y_after < y_before, "EM_SCROLL page up not functioning (line " 2771 "%d scrolled to line %d\n", y_before, y_after); 2772 2773 y_before = y_after; 2774 2775 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */ 2776 2777 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2778 2779 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line " 2780 "(r == 0x%08x)\n", r); 2781 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by " 2782 "1 line (%d scrolled to %d)\n", y_before, y_after); 2783 2784 y_before = y_after; 2785 2786 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */ 2787 2788 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2789 2790 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line " 2791 "(r == 0x%08x)\n", r); 2792 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 " 2793 "line (%d scrolled to %d)\n", y_before, y_after); 2794 2795 y_before = y_after; 2796 2797 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2798 SB_LINEUP, 0); /* lineup beyond top */ 2799 2800 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2801 2802 ok(r == 0x00010000, 2803 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r); 2804 ok(y_before == y_after, 2805 "EM_SCROLL line up beyond top worked (%d)\n", y_after); 2806 2807 y_before = y_after; 2808 2809 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2810 SB_PAGEUP, 0);/*page up beyond top */ 2811 2812 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2813 2814 ok(r == 0x00010000, 2815 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r); 2816 ok(y_before == y_after, 2817 "EM_SCROLL page up beyond top worked (%d)\n", y_after); 2818 2819 for (j = 0; j < 12; j++) /* page down all the way to the bottom */ 2820 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); 2821 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2822 r = SendMessageA(hwndRichEdit, EM_SCROLL, 2823 SB_PAGEDOWN, 0); /* page down beyond bot */ 2824 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2825 2826 ok(r == 0x00010000, 2827 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r); 2828 ok(y_before == y_after, 2829 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n", 2830 y_before, y_after); 2831 2832 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2833 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down beyond bot */ 2834 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0); 2835 2836 ok(r == 0x00010000, 2837 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r); 2838 ok(y_before == y_after, 2839 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n", 2840 y_before, y_after); 2841 } 2842 DestroyWindow(hwndRichEdit); 2843 } 2844 2845 static unsigned int recursionLevel = 0; 2846 static unsigned int WM_SIZE_recursionLevel = 0; 2847 static BOOL bailedOutOfRecursion = FALSE; 2848 static LRESULT (WINAPI *richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 2849 2850 static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 2851 { 2852 LRESULT r; 2853 2854 if (bailedOutOfRecursion) return 0; 2855 if (recursionLevel >= 32) { 2856 bailedOutOfRecursion = TRUE; 2857 return 0; 2858 } 2859 2860 recursionLevel++; 2861 switch (message) { 2862 case WM_SIZE: 2863 WM_SIZE_recursionLevel++; 2864 r = richeditProc(hwnd, message, wParam, lParam); 2865 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */ 2866 ShowScrollBar(hwnd, SB_VERT, TRUE); 2867 WM_SIZE_recursionLevel--; 2868 break; 2869 default: 2870 r = richeditProc(hwnd, message, wParam, lParam); 2871 break; 2872 } 2873 recursionLevel--; 2874 return r; 2875 } 2876 2877 static void test_scrollbar_visibility(void) 2878 { 2879 HWND hwndRichEdit; 2880 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"; 2881 SCROLLINFO si; 2882 WNDCLASSA cls; 2883 BOOL r; 2884 2885 /* These tests show that richedit should temporarily refrain from automatically 2886 hiding or showing its scrollbars (vertical at least) when an explicit request 2887 is made via ShowScrollBar() or similar, outside of standard richedit logic. 2888 Some applications depend on forced showing (when otherwise richedit would 2889 hide the vertical scrollbar) and are thrown on an endless recursive loop 2890 if richedit auto-hides the scrollbar again. Apparently they never heard of 2891 the ES_DISABLENOSCROLL style... */ 2892 2893 hwndRichEdit = new_richedit(NULL); 2894 2895 /* Test default scrollbar visibility behavior */ 2896 memset(&si, 0, sizeof(si)); 2897 si.cbSize = sizeof(si); 2898 si.fMask = SIF_PAGE | SIF_RANGE; 2899 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2900 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2901 "Vertical scrollbar is visible, should be invisible.\n"); 2902 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 2903 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 2904 si.nPage, si.nMin, si.nMax); 2905 2906 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2907 memset(&si, 0, sizeof(si)); 2908 si.cbSize = sizeof(si); 2909 si.fMask = SIF_PAGE | SIF_RANGE; 2910 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2911 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2912 "Vertical scrollbar is visible, should be invisible.\n"); 2913 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 2914 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 2915 si.nPage, si.nMin, si.nMax); 2916 2917 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 2918 memset(&si, 0, sizeof(si)); 2919 si.cbSize = sizeof(si); 2920 si.fMask = SIF_PAGE | SIF_RANGE; 2921 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2922 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 2923 "Vertical scrollbar is invisible, should be visible.\n"); 2924 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2925 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2926 si.nPage, si.nMin, si.nMax); 2927 2928 /* Oddly, setting text to NULL does *not* reset the scrollbar range, 2929 even though it hides the scrollbar */ 2930 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2931 memset(&si, 0, sizeof(si)); 2932 si.cbSize = sizeof(si); 2933 si.fMask = SIF_PAGE | SIF_RANGE; 2934 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2935 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2936 "Vertical scrollbar is visible, should be invisible.\n"); 2937 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2938 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2939 si.nPage, si.nMin, si.nMax); 2940 2941 /* Setting non-scrolling text again does *not* reset scrollbar range */ 2942 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 2943 memset(&si, 0, sizeof(si)); 2944 si.cbSize = sizeof(si); 2945 si.fMask = SIF_PAGE | SIF_RANGE; 2946 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2947 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2948 "Vertical scrollbar is visible, should be invisible.\n"); 2949 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2950 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2951 si.nPage, si.nMin, si.nMax); 2952 2953 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 2954 memset(&si, 0, sizeof(si)); 2955 si.cbSize = sizeof(si); 2956 si.fMask = SIF_PAGE | SIF_RANGE; 2957 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2958 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2959 "Vertical scrollbar is visible, should be invisible.\n"); 2960 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2961 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2962 si.nPage, si.nMin, si.nMax); 2963 2964 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 2965 memset(&si, 0, sizeof(si)); 2966 si.cbSize = sizeof(si); 2967 si.fMask = SIF_PAGE | SIF_RANGE; 2968 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2969 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2970 "Vertical scrollbar is visible, should be invisible.\n"); 2971 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2972 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2973 si.nPage, si.nMin, si.nMax); 2974 2975 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 2976 memset(&si, 0, sizeof(si)); 2977 si.cbSize = sizeof(si); 2978 si.fMask = SIF_PAGE | SIF_RANGE; 2979 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2980 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 2981 "Vertical scrollbar is visible, should be invisible.\n"); 2982 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 2983 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 2984 si.nPage, si.nMin, si.nMax); 2985 2986 DestroyWindow(hwndRichEdit); 2987 2988 /* Test again, with ES_DISABLENOSCROLL style */ 2989 hwndRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_DISABLENOSCROLL, NULL); 2990 2991 /* Test default scrollbar visibility behavior */ 2992 memset(&si, 0, sizeof(si)); 2993 si.cbSize = sizeof(si); 2994 si.fMask = SIF_PAGE | SIF_RANGE; 2995 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 2996 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 2997 "Vertical scrollbar is invisible, should be visible.\n"); 2998 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, 2999 "reported page/range is %d (%d..%d) expected 0 (0..1)\n", 3000 si.nPage, si.nMin, si.nMax); 3001 3002 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3003 memset(&si, 0, sizeof(si)); 3004 si.cbSize = sizeof(si); 3005 si.fMask = SIF_PAGE | SIF_RANGE; 3006 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3007 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3008 "Vertical scrollbar is invisible, should be visible.\n"); 3009 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, 3010 "reported page/range is %d (%d..%d) expected 0 (0..1)\n", 3011 si.nPage, si.nMin, si.nMax); 3012 3013 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3014 memset(&si, 0, sizeof(si)); 3015 si.cbSize = sizeof(si); 3016 si.fMask = SIF_PAGE | SIF_RANGE; 3017 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3018 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3019 "Vertical scrollbar is invisible, should be visible.\n"); 3020 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3021 "reported page/range is %d (%d..%d)\n", 3022 si.nPage, si.nMin, si.nMax); 3023 3024 /* Oddly, setting text to NULL does *not* reset the scrollbar range */ 3025 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3026 memset(&si, 0, sizeof(si)); 3027 si.cbSize = sizeof(si); 3028 si.fMask = SIF_PAGE | SIF_RANGE; 3029 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3030 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3031 "Vertical scrollbar is invisible, should be visible.\n"); 3032 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3033 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3034 si.nPage, si.nMin, si.nMax); 3035 3036 /* Setting non-scrolling text again does *not* reset scrollbar range */ 3037 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3038 memset(&si, 0, sizeof(si)); 3039 si.cbSize = sizeof(si); 3040 si.fMask = SIF_PAGE | SIF_RANGE; 3041 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3042 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3043 "Vertical scrollbar is invisible, should be visible.\n"); 3044 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3045 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3046 si.nPage, si.nMin, si.nMax); 3047 3048 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3049 memset(&si, 0, sizeof(si)); 3050 si.cbSize = sizeof(si); 3051 si.fMask = SIF_PAGE | SIF_RANGE; 3052 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3053 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3054 "Vertical scrollbar is invisible, should be visible.\n"); 3055 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3056 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3057 si.nPage, si.nMin, si.nMax); 3058 3059 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3060 memset(&si, 0, sizeof(si)); 3061 si.cbSize = sizeof(si); 3062 si.fMask = SIF_PAGE | SIF_RANGE; 3063 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3064 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3065 "Vertical scrollbar is invisible, should be visible.\n"); 3066 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3067 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3068 si.nPage, si.nMin, si.nMax); 3069 3070 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); 3071 memset(&si, 0, sizeof(si)); 3072 si.cbSize = sizeof(si); 3073 si.fMask = SIF_PAGE | SIF_RANGE; 3074 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3075 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3076 "Vertical scrollbar is invisible, should be visible.\n"); 3077 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, 3078 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3079 si.nPage, si.nMin, si.nMax); 3080 3081 DestroyWindow(hwndRichEdit); 3082 3083 /* Test behavior with explicit visibility request, using ShowScrollBar() */ 3084 hwndRichEdit = new_richedit(NULL); 3085 3086 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ 3087 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE); 3088 memset(&si, 0, sizeof(si)); 3089 si.cbSize = sizeof(si); 3090 si.fMask = SIF_PAGE | SIF_RANGE; 3091 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3092 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3093 "Vertical scrollbar is invisible, should be visible.\n"); 3094 todo_wine { 3095 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3096 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3097 si.nPage, si.nMin, si.nMax); 3098 } 3099 3100 /* Ditto, see above */ 3101 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3102 memset(&si, 0, sizeof(si)); 3103 si.cbSize = sizeof(si); 3104 si.fMask = SIF_PAGE | SIF_RANGE; 3105 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3106 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3107 "Vertical scrollbar is invisible, should be visible.\n"); 3108 todo_wine { 3109 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3110 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3111 si.nPage, si.nMin, si.nMax); 3112 } 3113 3114 /* Ditto, see above */ 3115 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3116 memset(&si, 0, sizeof(si)); 3117 si.cbSize = sizeof(si); 3118 si.fMask = SIF_PAGE | SIF_RANGE; 3119 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3120 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3121 "Vertical scrollbar is invisible, should be visible.\n"); 3122 todo_wine { 3123 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3124 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3125 si.nPage, si.nMin, si.nMax); 3126 } 3127 3128 /* Ditto, see above */ 3129 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); 3130 memset(&si, 0, sizeof(si)); 3131 si.cbSize = sizeof(si); 3132 si.fMask = SIF_PAGE | SIF_RANGE; 3133 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3134 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3135 "Vertical scrollbar is invisible, should be visible.\n"); 3136 todo_wine { 3137 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3138 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3139 si.nPage, si.nMin, si.nMax); 3140 } 3141 3142 /* Ditto, see above */ 3143 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3144 memset(&si, 0, sizeof(si)); 3145 si.cbSize = sizeof(si); 3146 si.fMask = SIF_PAGE | SIF_RANGE; 3147 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3148 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3149 "Vertical scrollbar is invisible, should be visible.\n"); 3150 todo_wine { 3151 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, 3152 "reported page/range is %d (%d..%d) expected 0 (0..100)\n", 3153 si.nPage, si.nMin, si.nMax); 3154 } 3155 3156 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3157 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3158 memset(&si, 0, sizeof(si)); 3159 si.cbSize = sizeof(si); 3160 si.fMask = SIF_PAGE | SIF_RANGE; 3161 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3162 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3163 "Vertical scrollbar is visible, should be invisible.\n"); 3164 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3165 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3166 si.nPage, si.nMin, si.nMax); 3167 3168 DestroyWindow(hwndRichEdit); 3169 3170 hwndRichEdit = new_richedit(NULL); 3171 3172 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3173 memset(&si, 0, sizeof(si)); 3174 si.cbSize = sizeof(si); 3175 si.fMask = SIF_PAGE | SIF_RANGE; 3176 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3177 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3178 "Vertical scrollbar is visible, should be invisible.\n"); 3179 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3180 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3181 si.nPage, si.nMin, si.nMax); 3182 3183 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3184 memset(&si, 0, sizeof(si)); 3185 si.cbSize = sizeof(si); 3186 si.fMask = SIF_PAGE | SIF_RANGE; 3187 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3188 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3189 "Vertical scrollbar is visible, should be invisible.\n"); 3190 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3191 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3192 si.nPage, si.nMin, si.nMax); 3193 3194 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3195 memset(&si, 0, sizeof(si)); 3196 si.cbSize = sizeof(si); 3197 si.fMask = SIF_PAGE | SIF_RANGE; 3198 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3199 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3200 "Vertical scrollbar is visible, should be invisible.\n"); 3201 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3202 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3203 si.nPage, si.nMin, si.nMax); 3204 3205 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3206 memset(&si, 0, sizeof(si)); 3207 si.cbSize = sizeof(si); 3208 si.fMask = SIF_PAGE | SIF_RANGE; 3209 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3210 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3211 "Vertical scrollbar is visible, should be invisible.\n"); 3212 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3213 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3214 si.nPage, si.nMin, si.nMax); 3215 3216 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3217 memset(&si, 0, sizeof(si)); 3218 si.cbSize = sizeof(si); 3219 si.fMask = SIF_PAGE | SIF_RANGE; 3220 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3221 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3222 "Vertical scrollbar is invisible, should be visible.\n"); 3223 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3224 "reported page/range is %d (%d..%d)\n", 3225 si.nPage, si.nMin, si.nMax); 3226 3227 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ 3228 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3229 memset(&si, 0, sizeof(si)); 3230 si.cbSize = sizeof(si); 3231 si.fMask = SIF_PAGE | SIF_RANGE; 3232 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3233 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3234 "Vertical scrollbar is visible, should be invisible.\n"); 3235 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3236 "reported page/range is %d (%d..%d)\n", 3237 si.nPage, si.nMin, si.nMax); 3238 3239 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3240 memset(&si, 0, sizeof(si)); 3241 si.cbSize = sizeof(si); 3242 si.fMask = SIF_PAGE | SIF_RANGE; 3243 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3244 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3245 "Vertical scrollbar is visible, should be invisible.\n"); 3246 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3247 "reported page/range is %d (%d..%d)\n", 3248 si.nPage, si.nMin, si.nMax); 3249 3250 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 3251 EM_SCROLL will make visible any forcefully invisible scrollbar */ 3252 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); 3253 memset(&si, 0, sizeof(si)); 3254 si.cbSize = sizeof(si); 3255 si.fMask = SIF_PAGE | SIF_RANGE; 3256 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3257 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3258 "Vertical scrollbar is invisible, should be visible.\n"); 3259 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3260 "reported page/range is %d (%d..%d)\n", 3261 si.nPage, si.nMin, si.nMax); 3262 3263 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); 3264 memset(&si, 0, sizeof(si)); 3265 si.cbSize = sizeof(si); 3266 si.fMask = SIF_PAGE | SIF_RANGE; 3267 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3268 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3269 "Vertical scrollbar is visible, should be invisible.\n"); 3270 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3271 "reported page/range is %d (%d..%d)\n", 3272 si.nPage, si.nMin, si.nMax); 3273 3274 /* Again, EM_SCROLL, with SB_LINEUP */ 3275 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); 3276 memset(&si, 0, sizeof(si)); 3277 si.cbSize = sizeof(si); 3278 si.fMask = SIF_PAGE | SIF_RANGE; 3279 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3280 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3281 "Vertical scrollbar is invisible, should be visible.\n"); 3282 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3283 "reported page/range is %d (%d..%d)\n", 3284 si.nPage, si.nMin, si.nMax); 3285 3286 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3287 memset(&si, 0, sizeof(si)); 3288 si.cbSize = sizeof(si); 3289 si.fMask = SIF_PAGE | SIF_RANGE; 3290 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3291 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3292 "Vertical scrollbar is visible, should be invisible.\n"); 3293 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3294 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3295 si.nPage, si.nMin, si.nMax); 3296 3297 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3298 memset(&si, 0, sizeof(si)); 3299 si.cbSize = sizeof(si); 3300 si.fMask = SIF_PAGE | SIF_RANGE; 3301 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3302 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3303 "Vertical scrollbar is invisible, should be visible.\n"); 3304 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3305 "reported page/range is %d (%d..%d)\n", 3306 si.nPage, si.nMin, si.nMax); 3307 3308 DestroyWindow(hwndRichEdit); 3309 3310 3311 /* Test behavior with explicit visibility request, using SetWindowLongA()() */ 3312 hwndRichEdit = new_richedit(NULL); 3313 3314 #define ENABLE_WS_VSCROLL(hwnd) \ 3315 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL) 3316 #define DISABLE_WS_VSCROLL(hwnd) \ 3317 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL) 3318 3319 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ 3320 ENABLE_WS_VSCROLL(hwndRichEdit); 3321 memset(&si, 0, sizeof(si)); 3322 si.cbSize = sizeof(si); 3323 si.fMask = SIF_PAGE | SIF_RANGE; 3324 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3325 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3326 "Vertical scrollbar is invisible, should be visible.\n"); 3327 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3328 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3329 si.nPage, si.nMin, si.nMax); 3330 3331 /* Ditto, see above */ 3332 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3333 memset(&si, 0, sizeof(si)); 3334 si.cbSize = sizeof(si); 3335 si.fMask = SIF_PAGE | SIF_RANGE; 3336 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3337 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3338 "Vertical scrollbar is invisible, should be visible.\n"); 3339 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3340 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3341 si.nPage, si.nMin, si.nMax); 3342 3343 /* Ditto, see above */ 3344 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3345 memset(&si, 0, sizeof(si)); 3346 si.cbSize = sizeof(si); 3347 si.fMask = SIF_PAGE | SIF_RANGE; 3348 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3349 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3350 "Vertical scrollbar is invisible, should be visible.\n"); 3351 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3352 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3353 si.nPage, si.nMin, si.nMax); 3354 3355 /* Ditto, see above */ 3356 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); 3357 memset(&si, 0, sizeof(si)); 3358 si.cbSize = sizeof(si); 3359 si.fMask = SIF_PAGE | SIF_RANGE; 3360 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3361 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3362 "Vertical scrollbar is invisible, should be visible.\n"); 3363 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3364 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3365 si.nPage, si.nMin, si.nMax); 3366 3367 /* Ditto, see above */ 3368 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3369 memset(&si, 0, sizeof(si)); 3370 si.cbSize = sizeof(si); 3371 si.fMask = SIF_PAGE | SIF_RANGE; 3372 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3373 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3374 "Vertical scrollbar is invisible, should be visible.\n"); 3375 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3376 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3377 si.nPage, si.nMin, si.nMax); 3378 3379 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3380 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3381 memset(&si, 0, sizeof(si)); 3382 si.cbSize = sizeof(si); 3383 si.fMask = SIF_PAGE | SIF_RANGE; 3384 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3385 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3386 "Vertical scrollbar is visible, should be invisible.\n"); 3387 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3388 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3389 si.nPage, si.nMin, si.nMax); 3390 3391 DestroyWindow(hwndRichEdit); 3392 3393 hwndRichEdit = new_richedit(NULL); 3394 3395 DISABLE_WS_VSCROLL(hwndRichEdit); 3396 memset(&si, 0, sizeof(si)); 3397 si.cbSize = sizeof(si); 3398 si.fMask = SIF_PAGE | SIF_RANGE; 3399 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3400 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3401 "Vertical scrollbar is visible, should be invisible.\n"); 3402 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3403 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3404 si.nPage, si.nMin, si.nMax); 3405 3406 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3407 memset(&si, 0, sizeof(si)); 3408 si.cbSize = sizeof(si); 3409 si.fMask = SIF_PAGE | SIF_RANGE; 3410 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3411 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3412 "Vertical scrollbar is visible, should be invisible.\n"); 3413 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3414 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3415 si.nPage, si.nMin, si.nMax); 3416 3417 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 3418 memset(&si, 0, sizeof(si)); 3419 si.cbSize = sizeof(si); 3420 si.fMask = SIF_PAGE | SIF_RANGE; 3421 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3422 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3423 "Vertical scrollbar is visible, should be invisible.\n"); 3424 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3425 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3426 si.nPage, si.nMin, si.nMax); 3427 3428 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3429 memset(&si, 0, sizeof(si)); 3430 si.cbSize = sizeof(si); 3431 si.fMask = SIF_PAGE | SIF_RANGE; 3432 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3433 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3434 "Vertical scrollbar is visible, should be invisible.\n"); 3435 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), 3436 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", 3437 si.nPage, si.nMin, si.nMax); 3438 3439 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3440 memset(&si, 0, sizeof(si)); 3441 si.cbSize = sizeof(si); 3442 si.fMask = SIF_PAGE | SIF_RANGE; 3443 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3444 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3445 "Vertical scrollbar is invisible, should be visible.\n"); 3446 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3447 "reported page/range is %d (%d..%d)\n", 3448 si.nPage, si.nMin, si.nMax); 3449 3450 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ 3451 DISABLE_WS_VSCROLL(hwndRichEdit); 3452 memset(&si, 0, sizeof(si)); 3453 si.cbSize = sizeof(si); 3454 si.fMask = SIF_PAGE | SIF_RANGE; 3455 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3456 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3457 "Vertical scrollbar is visible, should be invisible.\n"); 3458 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3459 "reported page/range is %d (%d..%d)\n", 3460 si.nPage, si.nMin, si.nMax); 3461 3462 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 3463 memset(&si, 0, sizeof(si)); 3464 si.cbSize = sizeof(si); 3465 si.fMask = SIF_PAGE | SIF_RANGE; 3466 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3467 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3468 "Vertical scrollbar is visible, should be invisible.\n"); 3469 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3470 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", 3471 si.nPage, si.nMin, si.nMax); 3472 3473 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 3474 memset(&si, 0, sizeof(si)); 3475 si.cbSize = sizeof(si); 3476 si.fMask = SIF_PAGE | SIF_RANGE; 3477 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3478 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3479 "Vertical scrollbar is invisible, should be visible.\n"); 3480 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3481 "reported page/range is %d (%d..%d)\n", 3482 si.nPage, si.nMin, si.nMax); 3483 3484 DISABLE_WS_VSCROLL(hwndRichEdit); 3485 memset(&si, 0, sizeof(si)); 3486 si.cbSize = sizeof(si); 3487 si.fMask = SIF_PAGE | SIF_RANGE; 3488 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3489 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3490 "Vertical scrollbar is visible, should be invisible.\n"); 3491 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3492 "reported page/range is %d (%d..%d)\n", 3493 si.nPage, si.nMin, si.nMax); 3494 3495 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 3496 EM_SCROLL will make visible any forcefully invisible scrollbar */ 3497 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); 3498 memset(&si, 0, sizeof(si)); 3499 si.cbSize = sizeof(si); 3500 si.fMask = SIF_PAGE | SIF_RANGE; 3501 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3502 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3503 "Vertical scrollbar is invisible, should be visible.\n"); 3504 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3505 "reported page/range is %d (%d..%d)\n", 3506 si.nPage, si.nMin, si.nMax); 3507 3508 DISABLE_WS_VSCROLL(hwndRichEdit); 3509 memset(&si, 0, sizeof(si)); 3510 si.cbSize = sizeof(si); 3511 si.fMask = SIF_PAGE | SIF_RANGE; 3512 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3513 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 3514 "Vertical scrollbar is visible, should be invisible.\n"); 3515 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3516 "reported page/range is %d (%d..%d)\n", 3517 si.nPage, si.nMin, si.nMax); 3518 3519 /* Again, EM_SCROLL, with SB_LINEUP */ 3520 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); 3521 memset(&si, 0, sizeof(si)); 3522 si.cbSize = sizeof(si); 3523 si.fMask = SIF_PAGE | SIF_RANGE; 3524 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 3525 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 3526 "Vertical scrollbar is invisible, should be visible.\n"); 3527 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, 3528 "reported page/range is %d (%d..%d)\n", 3529 si.nPage, si.nMin, si.nMax); 3530 3531 DestroyWindow(hwndRichEdit); 3532 3533 /* This window proc models what is going on with Corman Lisp 3.0. 3534 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to 3535 force the scrollbar into visibility. Recursion should NOT happen 3536 as a result of this action. 3537 */ 3538 r = GetClassInfoA(NULL, RICHEDIT_CLASS20A, &cls); 3539 if (r) { 3540 richeditProc = cls.lpfnWndProc; 3541 cls.lpfnWndProc = RicheditStupidOverrideProcA; 3542 cls.lpszClassName = "RicheditStupidOverride"; 3543 if(!RegisterClassA(&cls)) assert(0); 3544 3545 recursionLevel = 0; 3546 WM_SIZE_recursionLevel = 0; 3547 bailedOutOfRecursion = FALSE; 3548 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL); 3549 ok(!bailedOutOfRecursion, 3550 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); 3551 3552 recursionLevel = 0; 3553 WM_SIZE_recursionLevel = 0; 3554 bailedOutOfRecursion = FALSE; 3555 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE); 3556 ok(!bailedOutOfRecursion, 3557 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); 3558 3559 /* Unblock window in order to process WM_DESTROY */ 3560 recursionLevel = 0; 3561 bailedOutOfRecursion = FALSE; 3562 WM_SIZE_recursionLevel = 0; 3563 DestroyWindow(hwndRichEdit); 3564 } 3565 } 3566 3567 static void test_EM_SETUNDOLIMIT(void) 3568 { 3569 /* cases we test for: 3570 * default behaviour - limiting at 100 undo's 3571 * undo disabled - setting a limit of 0 3572 * undo limited - undo limit set to some to some number, like 2 3573 * bad input - sending a negative number should default to 100 undo's */ 3574 3575 HWND hwndRichEdit = new_richedit(NULL); 3576 CHARRANGE cr; 3577 int i; 3578 int result; 3579 3580 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x"); 3581 cr.cpMin = 0; 3582 cr.cpMax = -1; 3583 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 3584 3585 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 3586 /*Load "x" into the clipboard. Paste is an easy, undo'able operation. 3587 also, multiple pastes don't combine like WM_CHAR would */ 3588 3589 /* first case - check the default */ 3590 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 3591 for (i=0; i<101; i++) /* Put 101 undo's on the stack */ 3592 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3593 for (i=0; i<100; i++) /* Undo 100 of them */ 3594 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 3595 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3596 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n"); 3597 3598 /* second case - cannot undo */ 3599 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 3600 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0); 3601 SendMessageA(hwndRichEdit, 3602 WM_PASTE, 0, 0); /* Try to put something in the undo stack */ 3603 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3604 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n"); 3605 3606 /* third case - set it to an arbitrary number */ 3607 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 3608 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0); 3609 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3610 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3611 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 3612 /* If SETUNDOLIMIT is working, there should only be two undo's after this */ 3613 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0,0), 3614 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n"); 3615 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 3616 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0), 3617 "EM_SETUNDOLIMIT didn't allow a second 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 allowed a third undo with UNDOLIMIT set to 2\n"); 3621 3622 /* fourth case - setting negative numbers should default to 100 undos */ 3623 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 3624 result = SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0); 3625 ok (result == 100, 3626 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result); 3627 3628 DestroyWindow(hwndRichEdit); 3629 } 3630 3631 static void test_ES_PASSWORD(void) 3632 { 3633 /* This isn't hugely testable, so we're just going to run it through its paces */ 3634 3635 HWND hwndRichEdit = new_richedit(NULL); 3636 WCHAR result; 3637 3638 /* First, check the default of a regular control */ 3639 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3640 ok (result == 0, 3641 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result); 3642 3643 /* Now, set it to something normal */ 3644 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0); 3645 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3646 ok (result == 120, 3647 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); 3648 3649 /* Now, set it to something odd */ 3650 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0); 3651 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); 3652 ok (result == 1234, 3653 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); 3654 DestroyWindow(hwndRichEdit); 3655 } 3656 3657 LONG streamout_written = 0; 3658 3659 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, 3660 LPBYTE pbBuff, 3661 LONG cb, 3662 LONG *pcb) 3663 { 3664 char** str = (char**)dwCookie; 3665 *pcb = cb; 3666 if (*pcb > 0) { 3667 memcpy(*str, pbBuff, *pcb); 3668 *str += *pcb; 3669 } 3670 streamout_written = *pcb; 3671 return 0; 3672 } 3673 3674 static void test_WM_SETTEXT(void) 3675 { 3676 HWND hwndRichEdit = new_richedit(NULL); 3677 const char * TestItem1 = "TestSomeText"; 3678 const char * TestItem2 = "TestSomeText\r"; 3679 const char * TestItem2_after = "TestSomeText\r\n"; 3680 const char * TestItem3 = "TestSomeText\rSomeMoreText\r"; 3681 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n"; 3682 const char * TestItem4 = "TestSomeText\n\nTestSomeText"; 3683 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText"; 3684 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText"; 3685 const char * TestItem5_after = "TestSomeText TestSomeText"; 3686 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText"; 3687 const char * TestItem6_after = "TestSomeText \r\nTestSomeText"; 3688 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText"; 3689 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText"; 3690 3691 const char rtftextA[] = "{\\rtf sometext}"; 3692 const char urtftextA[] = "{\\urtf sometext}"; 3693 const WCHAR rtftextW[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0}; 3694 const WCHAR urtftextW[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0}; 3695 const WCHAR sometextW[] = {'s','o','m','e','t','e','x','t',0}; 3696 3697 char buf[1024] = {0}; 3698 WCHAR bufW[1024] = {0}; 3699 LRESULT result; 3700 3701 /* This test attempts to show that WM_SETTEXT on a riched20 control causes 3702 any solitary \r to be converted to \r\n on return. Properly paired 3703 \r\n are not affected. It also shows that the special sequence \r\r\n 3704 gets converted to a single space. 3705 */ 3706 3707 #define TEST_SETTEXT(a, b) \ 3708 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \ 3709 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ 3710 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \ 3711 ok (result == lstrlenA(buf), \ 3712 "WM_GETTEXT returned %ld instead of expected %u\n", \ 3713 result, lstrlenA(buf)); \ 3714 result = strcmp(b, buf); \ 3715 ok(result == 0, \ 3716 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf); 3717 3718 TEST_SETTEXT(TestItem1, TestItem1) 3719 TEST_SETTEXT(TestItem2, TestItem2_after) 3720 TEST_SETTEXT(TestItem3, TestItem3_after) 3721 TEST_SETTEXT(TestItem3_after, TestItem3_after) 3722 TEST_SETTEXT(TestItem4, TestItem4_after) 3723 TEST_SETTEXT(TestItem5, TestItem5_after) 3724 TEST_SETTEXT(TestItem6, TestItem6_after) 3725 TEST_SETTEXT(TestItem7, TestItem7_after) 3726 3727 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */ 3728 TEST_SETTEXT(rtftextA, "sometext") /* interpreted as ascii rtf */ 3729 TEST_SETTEXT(urtftextA, "sometext") /* interpreted as ascii rtf */ 3730 TEST_SETTEXT(rtftextW, "{") /* interpreted as ascii text */ 3731 TEST_SETTEXT(urtftextW, "{") /* interpreted as ascii text */ 3732 DestroyWindow(hwndRichEdit); 3733 #undef TEST_SETTEXT 3734 3735 #define TEST_SETTEXTW(a, b) \ 3736 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \ 3737 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ 3738 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \ 3739 ok (result == lstrlenW(bufW), \ 3740 "WM_GETTEXT returned %ld instead of expected %u\n", \ 3741 result, lstrlenW(bufW)); \ 3742 result = lstrcmpW(b, bufW); \ 3743 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result); 3744 3745 hwndRichEdit = CreateWindowW(RICHEDIT_CLASS20W, NULL, 3746 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 3747 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 3748 ok(hwndRichEdit != NULL, "class: RichEdit20W, error: %d\n", (int) GetLastError()); 3749 TEST_SETTEXTW(rtftextA, sometextW) /* interpreted as ascii rtf */ 3750 TEST_SETTEXTW(urtftextA, sometextW) /* interpreted as ascii rtf */ 3751 TEST_SETTEXTW(rtftextW, rtftextW) /* interpreted as ascii text */ 3752 TEST_SETTEXTW(urtftextW, urtftextW) /* interpreted as ascii text */ 3753 DestroyWindow(hwndRichEdit); 3754 #undef TEST_SETTEXTW 3755 3756 /* Single-line richedit */ 3757 hwndRichEdit = new_richedit_with_style(NULL, 0); 3758 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"line1\r\nline2"); 3759 ok(result == 1, "WM_SETTEXT returned %ld, expected 12\n", result); 3760 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 3761 ok(result == 5, "WM_GETTEXT returned %ld, expected 5\n", result); 3762 ok(!strcmp(buf, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buf); 3763 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}"); 3764 ok(result == 1, "WM_SETTEXT returned %ld, expected 1\n", result); 3765 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 3766 ok(result == 3, "WM_GETTEXT returned %ld, expected 3\n", result); 3767 ok(!strcmp(buf, "ABC"), "WM_GETTEXT returned incorrect string '%s'\n", buf); 3768 DestroyWindow(hwndRichEdit); 3769 } 3770 3771 /* Set *pcb to one to show that the remaining cb-1 bytes are not 3772 resent to the callkack. */ 3773 static DWORD CALLBACK test_esCallback_written_1(DWORD_PTR dwCookie, 3774 LPBYTE pbBuff, 3775 LONG cb, 3776 LONG *pcb) 3777 { 3778 char** str = (char**)dwCookie; 3779 ok(*pcb == cb || *pcb == 0, "cb %d, *pcb %d\n", cb, *pcb); 3780 *pcb = 0; 3781 if (cb > 0) { 3782 memcpy(*str, pbBuff, cb); 3783 *str += cb; 3784 *pcb = 1; 3785 } 3786 return 0; 3787 } 3788 3789 static int count_pars(const char *buf) 3790 { 3791 const char *p = buf; 3792 int count = 0; 3793 while ((p = strstr( p, "\\par" )) != NULL) 3794 { 3795 if (!isalpha( p[4] )) 3796 count++; 3797 p++; 3798 } 3799 return count; 3800 } 3801 3802 static void test_EM_STREAMOUT(void) 3803 { 3804 HWND hwndRichEdit = new_richedit(NULL); 3805 int r; 3806 EDITSTREAM es; 3807 char buf[1024] = {0}; 3808 char * p; 3809 LRESULT result; 3810 3811 const char * TestItem1 = "TestSomeText"; 3812 const char * TestItem2 = "TestSomeText\r"; 3813 const char * TestItem3 = "TestSomeText\r\n"; 3814 3815 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1); 3816 p = buf; 3817 es.dwCookie = (DWORD_PTR)&p; 3818 es.dwError = 0; 3819 es.pfnCallback = test_WM_SETTEXT_esCallback; 3820 memset(buf, 0, sizeof(buf)); 3821 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3822 r = strlen(buf); 3823 ok(r == 12, "streamed text length is %d, expecting 12\n", r); 3824 ok(strcmp(buf, TestItem1) == 0, 3825 "streamed text different, got %s\n", buf); 3826 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3827 3828 /* RTF mode writes the final end of para \r if it's part of the selection */ 3829 p = buf; 3830 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3831 ok (count_pars(buf) == 1, "got %s\n", buf); 3832 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3833 p = buf; 3834 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 12); 3835 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3836 ok (count_pars(buf) == 0, "got %s\n", buf); 3837 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3838 p = buf; 3839 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 3840 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3841 ok (count_pars(buf) == 1, "got %s\n", buf); 3842 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3843 3844 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2); 3845 p = buf; 3846 es.dwCookie = (DWORD_PTR)&p; 3847 es.dwError = 0; 3848 es.pfnCallback = test_WM_SETTEXT_esCallback; 3849 memset(buf, 0, sizeof(buf)); 3850 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3851 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3852 r = strlen(buf); 3853 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */ 3854 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3855 ok(strcmp(buf, TestItem3) == 0, 3856 "streamed text different from, got %s\n", buf); 3857 3858 /* And again RTF mode writes the final end of para \r if it's part of the selection */ 3859 p = buf; 3860 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3861 ok (count_pars(buf) == 2, "got %s\n", buf); 3862 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3863 p = buf; 3864 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 13); 3865 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3866 ok (count_pars(buf) == 1, "got %s\n", buf); 3867 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3868 p = buf; 3869 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 3870 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF|SFF_SELECTION, (LPARAM)&es); 3871 ok (count_pars(buf) == 2, "got %s\n", buf); 3872 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3873 3874 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3); 3875 p = buf; 3876 es.dwCookie = (DWORD_PTR)&p; 3877 es.dwError = 0; 3878 es.pfnCallback = test_WM_SETTEXT_esCallback; 3879 memset(buf, 0, sizeof(buf)); 3880 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3881 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written); 3882 r = strlen(buf); 3883 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3884 ok(strcmp(buf, TestItem3) == 0, 3885 "streamed text different, got %s\n", buf); 3886 3887 /* Use a callback that sets *pcb to one */ 3888 p = buf; 3889 es.dwCookie = (DWORD_PTR)&p; 3890 es.dwError = 0; 3891 es.pfnCallback = test_esCallback_written_1; 3892 memset(buf, 0, sizeof(buf)); 3893 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es); 3894 r = strlen(buf); 3895 ok(r == 14, "streamed text length is %d, expecting 14\n", r); 3896 ok(strcmp(buf, TestItem3) == 0, 3897 "streamed text different, got %s\n", buf); 3898 ok(result == 0, "got %ld expected 0\n", result); 3899 3900 3901 DestroyWindow(hwndRichEdit); 3902 } 3903 3904 static void test_EM_STREAMOUT_FONTTBL(void) 3905 { 3906 HWND hwndRichEdit = new_richedit(NULL); 3907 EDITSTREAM es; 3908 char buf[1024] = {0}; 3909 char * p; 3910 char * fontTbl; 3911 int brackCount; 3912 3913 const char * TestItem = "TestSomeText"; 3914 3915 /* fills in the richedit control with some text */ 3916 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem); 3917 3918 /* streams out the text in rtf format */ 3919 p = buf; 3920 es.dwCookie = (DWORD_PTR)&p; 3921 es.dwError = 0; 3922 es.pfnCallback = test_WM_SETTEXT_esCallback; 3923 memset(buf, 0, sizeof(buf)); 3924 SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3925 3926 /* scans for \fonttbl, error if not found */ 3927 fontTbl = strstr(buf, "\\fonttbl"); 3928 ok(fontTbl != NULL, "missing \\fonttbl section\n"); 3929 if(fontTbl) 3930 { 3931 /* scans for terminating closing bracket */ 3932 brackCount = 1; 3933 while(*fontTbl && brackCount) 3934 { 3935 if(*fontTbl == '{') 3936 brackCount++; 3937 else if(*fontTbl == '}') 3938 brackCount--; 3939 fontTbl++; 3940 } 3941 /* checks whether closing bracket is ok */ 3942 ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n"); 3943 if(!brackCount) 3944 { 3945 /* char before closing fonttbl block should be a closed bracket */ 3946 fontTbl -= 2; 3947 ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl); 3948 3949 /* char after fonttbl block should be a crlf */ 3950 fontTbl += 2; 3951 ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n"); 3952 } 3953 } 3954 DestroyWindow(hwndRichEdit); 3955 } 3956 3957 static void test_EM_STREAMOUT_empty_para(void) 3958 { 3959 HWND hwnd = new_richedit(NULL); 3960 char buf[1024], *p = buf; 3961 EDITSTREAM es; 3962 3963 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 3964 3965 memset(buf, 0, sizeof(buf)); 3966 es.dwCookie = (DWORD_PTR)&p; 3967 es.dwError = 0; 3968 es.pfnCallback = test_WM_SETTEXT_esCallback; 3969 3970 SendMessageA(hwnd, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 3971 ok((p = strstr(buf, "\\pard")) != NULL, "missing \\pard\n"); 3972 ok(((p = strstr(p, "\\fs")) && isdigit(p[3])), "missing \\fs\n"); 3973 3974 DestroyWindow(hwnd); 3975 } 3976 3977 static void test_EM_SETTEXTEX(void) 3978 { 3979 HWND hwndRichEdit, parent; 3980 SCROLLINFO si; 3981 int sel_start, sel_end; 3982 SETTEXTEX setText; 3983 GETTEXTEX getText; 3984 WCHAR TestItem1[] = {'T', 'e', 's', 't', 3985 'S', 'o', 'm', 'e', 3986 'T', 'e', 'x', 't', 0}; 3987 WCHAR TestItem1alt[] = {'T', 'T', 'e', 's', 3988 't', 'S', 'o', 'm', 3989 'e', 'T', 'e', 'x', 3990 't', 't', 'S', 'o', 3991 'm', 'e', 'T', 'e', 3992 'x', 't', 0}; 3993 WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t', 3994 '\r','t','S','o','m','e','T','e','x','t',0}; 3995 WCHAR TestItem2[] = {'T', 'e', 's', 't', 3996 'S', 'o', 'm', 'e', 3997 'T', 'e', 'x', 't', 3998 '\r', 0}; 3999 const char * TestItem2_after = "TestSomeText\r\n"; 4000 WCHAR TestItem3[] = {'T', 'e', 's', 't', 4001 'S', 'o', 'm', 'e', 4002 'T', 'e', 'x', 't', 4003 '\r','\n','\r','\n', 0}; 4004 WCHAR TestItem3alt[] = {'T', 'e', 's', 't', 4005 'S', 'o', 'm', 'e', 4006 'T', 'e', 'x', 't', 4007 '\n','\n', 0}; 4008 WCHAR TestItem3_after[] = {'T', 'e', 's', 't', 4009 'S', 'o', 'm', 'e', 4010 'T', 'e', 'x', 't', 4011 '\r','\r', 0}; 4012 WCHAR TestItem4[] = {'T', 'e', 's', 't', 4013 'S', 'o', 'm', 'e', 4014 'T', 'e', 'x', 't', 4015 '\r','\r','\n','\r', 4016 '\n', 0}; 4017 WCHAR TestItem4_after[] = {'T', 'e', 's', 't', 4018 'S', 'o', 'm', 'e', 4019 'T', 'e', 'x', 't', 4020 ' ','\r', 0}; 4021 #define MAX_BUF_LEN 1024 4022 WCHAR buf[MAX_BUF_LEN]; 4023 char bufACP[MAX_BUF_LEN]; 4024 char * p; 4025 int result; 4026 CHARRANGE cr; 4027 EDITSTREAM es; 4028 WNDCLASSA cls; 4029 4030 /* Test the scroll position with and without a parent window. 4031 * 4032 * For some reason the scroll position is 0 after EM_SETTEXTEX 4033 * with the ST_SELECTION flag only when the control has a parent 4034 * window, even though the selection is at the end. */ 4035 cls.style = 0; 4036 cls.lpfnWndProc = DefWindowProcA; 4037 cls.cbClsExtra = 0; 4038 cls.cbWndExtra = 0; 4039 cls.hInstance = GetModuleHandleA(0); 4040 cls.hIcon = 0; 4041 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 4042 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 4043 cls.lpszMenuName = NULL; 4044 cls.lpszClassName = "ParentTestClass"; 4045 if(!RegisterClassA(&cls)) assert(0); 4046 4047 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 4048 0, 0, 200, 60, NULL, NULL, NULL, NULL); 4049 ok (parent != 0, "Failed to create parent window\n"); 4050 4051 hwndRichEdit = CreateWindowExA(0, 4052 RICHEDIT_CLASS20A, NULL, 4053 ES_MULTILINE|WS_VSCROLL|WS_VISIBLE|WS_CHILD, 4054 0, 0, 200, 60, parent, NULL, 4055 hmoduleRichEdit, NULL); 4056 4057 setText.codepage = CP_ACP; 4058 setText.flags = ST_SELECTION; 4059 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4060 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4061 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result); 4062 si.cbSize = sizeof(si); 4063 si.fMask = SIF_ALL; 4064 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4065 todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); 4066 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4067 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); 4068 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); 4069 4070 DestroyWindow(parent); 4071 4072 /* Test without a parent window */ 4073 hwndRichEdit = new_richedit(NULL); 4074 setText.codepage = CP_ACP; 4075 setText.flags = ST_SELECTION; 4076 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4077 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4078 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result); 4079 si.cbSize = sizeof(si); 4080 si.fMask = SIF_ALL; 4081 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4082 ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos); 4083 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4084 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); 4085 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); 4086 4087 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT, 4088 * but this time it is because the selection is at the beginning. */ 4089 setText.codepage = CP_ACP; 4090 setText.flags = ST_DEFAULT; 4091 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 4092 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); 4093 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4094 si.cbSize = sizeof(si); 4095 si.fMask = SIF_ALL; 4096 GetScrollInfo(hwndRichEdit, SB_VERT, &si); 4097 ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); 4098 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 4099 ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start); 4100 ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end); 4101 4102 setText.codepage = 1200; /* no constant for unicode */ 4103 getText.codepage = 1200; /* no constant for unicode */ 4104 getText.cb = MAX_BUF_LEN; 4105 getText.flags = GT_DEFAULT; 4106 getText.lpDefaultChar = NULL; 4107 getText.lpUsedDefChar = NULL; 4108 4109 setText.flags = 0; 4110 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4111 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4112 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4113 ok(lstrcmpW(buf, TestItem1) == 0, 4114 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4115 4116 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not 4117 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf 4118 */ 4119 setText.codepage = 1200; /* no constant for unicode */ 4120 getText.codepage = 1200; /* no constant for unicode */ 4121 getText.cb = MAX_BUF_LEN; 4122 getText.flags = GT_DEFAULT; 4123 getText.lpDefaultChar = NULL; 4124 getText.lpUsedDefChar = NULL; 4125 setText.flags = 0; 4126 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem2); 4127 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4128 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4129 ok(lstrcmpW(buf, TestItem2) == 0, 4130 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4131 4132 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */ 4133 SendMessageA(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf); 4134 ok(strcmp((const char *)buf, TestItem2_after) == 0, 4135 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n"); 4136 4137 /* Baseline test for just-enough buffer space for string */ 4138 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); 4139 getText.codepage = 1200; /* no constant for unicode */ 4140 getText.flags = GT_DEFAULT; 4141 getText.lpDefaultChar = NULL; 4142 getText.lpUsedDefChar = NULL; 4143 memset(buf, 0, sizeof(buf)); 4144 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4145 ok(lstrcmpW(buf, TestItem2) == 0, 4146 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4147 4148 /* When there is enough space for one character, but not both, of the CRLF 4149 pair at the end of the string, the CR is not copied at all. That is, 4150 the caller must not see CRLF pairs truncated to CR at the end of the 4151 string. 4152 */ 4153 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); 4154 getText.codepage = 1200; /* no constant for unicode */ 4155 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */ 4156 getText.lpDefaultChar = NULL; 4157 getText.lpUsedDefChar = NULL; 4158 memset(buf, 0, sizeof(buf)); 4159 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4160 ok(lstrcmpW(buf, TestItem1) == 0, 4161 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4162 4163 4164 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */ 4165 setText.codepage = 1200; /* no constant for unicode */ 4166 getText.codepage = 1200; /* no constant for unicode */ 4167 getText.cb = MAX_BUF_LEN; 4168 getText.flags = GT_DEFAULT; 4169 getText.lpDefaultChar = NULL; 4170 getText.lpUsedDefChar = NULL; 4171 setText.flags = 0; 4172 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3); 4173 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4174 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4175 ok(lstrcmpW(buf, TestItem3_after) == 0, 4176 "EM_SETTEXTEX did not convert properly\n"); 4177 4178 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */ 4179 setText.codepage = 1200; /* no constant for unicode */ 4180 getText.codepage = 1200; /* no constant for unicode */ 4181 getText.cb = MAX_BUF_LEN; 4182 getText.flags = GT_DEFAULT; 4183 getText.lpDefaultChar = NULL; 4184 getText.lpUsedDefChar = NULL; 4185 setText.flags = 0; 4186 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3alt); 4187 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4188 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4189 ok(lstrcmpW(buf, TestItem3_after) == 0, 4190 "EM_SETTEXTEX did not convert properly\n"); 4191 4192 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */ 4193 setText.codepage = 1200; /* no constant for unicode */ 4194 getText.codepage = 1200; /* no constant for unicode */ 4195 getText.cb = MAX_BUF_LEN; 4196 getText.flags = GT_DEFAULT; 4197 getText.lpDefaultChar = NULL; 4198 getText.lpUsedDefChar = NULL; 4199 setText.flags = 0; 4200 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem4); 4201 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4202 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4203 ok(lstrcmpW(buf, TestItem4_after) == 0, 4204 "EM_SETTEXTEX did not convert properly\n"); 4205 4206 /* !ST_SELECTION && Unicode && !\rtf */ 4207 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); 4208 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4209 4210 ok (result == 1, 4211 "EM_SETTEXTEX returned %d, instead of 1\n",result); 4212 ok(!buf[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n"); 4213 4214 /* put some text back: !ST_SELECTION && Unicode && !\rtf */ 4215 setText.flags = 0; 4216 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4217 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4218 /* select some text */ 4219 cr.cpMax = 1; 4220 cr.cpMin = 3; 4221 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4222 /* replace current selection: ST_SELECTION && Unicode && !\rtf */ 4223 setText.flags = ST_SELECTION; 4224 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); 4225 ok(result == 0, 4226 "EM_SETTEXTEX with NULL lParam to replace selection" 4227 " with no text should return 0. Got %i\n", 4228 result); 4229 4230 /* put some text back: !ST_SELECTION && Unicode && !\rtf */ 4231 setText.flags = 0; 4232 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4233 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4234 /* select some text */ 4235 cr.cpMax = 1; 4236 cr.cpMin = 3; 4237 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4238 /* replace current selection: ST_SELECTION && Unicode && !\rtf */ 4239 setText.flags = ST_SELECTION; 4240 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4241 /* get text */ 4242 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4243 ok(result == lstrlenW(TestItem1), 4244 "EM_SETTEXTEX with NULL lParam to replace selection" 4245 " with no text should return 0. Got %i\n", 4246 result); 4247 ok(lstrlenW(buf) == 22, 4248 "EM_SETTEXTEX to replace selection with more text failed: %i.\n", 4249 lstrlenW(buf) ); 4250 4251 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */ 4252 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */ 4253 p = (char *)buf; 4254 es.dwCookie = (DWORD_PTR)&p; 4255 es.dwError = 0; 4256 es.pfnCallback = test_WM_SETTEXT_esCallback; 4257 memset(buf, 0, sizeof(buf)); 4258 SendMessageA(hwndRichEdit, EM_STREAMOUT, 4259 (WPARAM)(SF_RTF), (LPARAM)&es); 4260 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf); 4261 4262 /* !ST_SELECTION && !Unicode && \rtf */ 4263 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ 4264 getText.codepage = 1200; /* no constant for unicode */ 4265 getText.cb = MAX_BUF_LEN; 4266 getText.flags = GT_DEFAULT; 4267 getText.lpDefaultChar = NULL; 4268 getText.lpUsedDefChar = NULL; 4269 4270 setText.flags = 0; 4271 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf); 4272 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result); 4273 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4274 ok(lstrcmpW(buf, TestItem1) == 0, 4275 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); 4276 4277 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it 4278 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */ 4279 setText.codepage = 1200; /* Lie about code page (actual ASCII) */ 4280 getText.codepage = CP_ACP; 4281 getText.cb = MAX_BUF_LEN; 4282 getText.flags = GT_DEFAULT; 4283 getText.lpDefaultChar = NULL; 4284 getText.lpUsedDefChar = NULL; 4285 4286 setText.flags = ST_SELECTION; 4287 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4288 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf not unicode}"); 4289 todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result); 4290 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4291 ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP); 4292 4293 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */ 4294 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */ 4295 p = (char *)buf; 4296 es.dwCookie = (DWORD_PTR)&p; 4297 es.dwError = 0; 4298 es.pfnCallback = test_WM_SETTEXT_esCallback; 4299 memset(buf, 0, sizeof(buf)); 4300 SendMessageA(hwndRichEdit, EM_STREAMOUT, 4301 (WPARAM)(SF_RTF), (LPARAM)&es); 4302 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf); 4303 4304 /* select some text */ 4305 cr.cpMax = 1; 4306 cr.cpMin = 3; 4307 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4308 4309 /* ST_SELECTION && !Unicode && \rtf */ 4310 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ 4311 getText.codepage = 1200; /* no constant for unicode */ 4312 getText.cb = MAX_BUF_LEN; 4313 getText.flags = GT_DEFAULT; 4314 getText.lpDefaultChar = NULL; 4315 getText.lpUsedDefChar = NULL; 4316 4317 setText.flags = ST_SELECTION; 4318 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf); 4319 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4320 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf); 4321 4322 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */ 4323 setText.codepage = 1200; /* no constant for unicode */ 4324 getText.codepage = CP_ACP; 4325 getText.cb = MAX_BUF_LEN; 4326 4327 setText.flags = 0; 4328 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); /* TestItem1 */ 4329 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4330 4331 /* select some text */ 4332 cr.cpMax = 1; 4333 cr.cpMin = 3; 4334 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4335 4336 /* ST_SELECTION && !Unicode && !\rtf */ 4337 setText.codepage = CP_ACP; 4338 getText.codepage = 1200; /* no constant for unicode */ 4339 getText.cb = MAX_BUF_LEN; 4340 getText.flags = GT_DEFAULT; 4341 getText.lpDefaultChar = NULL; 4342 getText.lpUsedDefChar = NULL; 4343 4344 setText.flags = ST_SELECTION; 4345 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)bufACP); 4346 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 4347 ok(lstrcmpW(buf, TestItem1alt) == 0, 4348 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when" 4349 " using ST_SELECTION and non-Unicode\n"); 4350 4351 /* Test setting text using rich text format */ 4352 setText.flags = 0; 4353 setText.codepage = CP_ACP; 4354 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}"); 4355 getText.codepage = CP_ACP; 4356 getText.cb = MAX_BUF_LEN; 4357 getText.flags = GT_DEFAULT; 4358 getText.lpDefaultChar = NULL; 4359 getText.lpUsedDefChar = NULL; 4360 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4361 ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP); 4362 4363 setText.flags = 0; 4364 setText.codepage = CP_ACP; 4365 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}"); 4366 getText.codepage = CP_ACP; 4367 getText.cb = MAX_BUF_LEN; 4368 getText.flags = GT_DEFAULT; 4369 getText.lpDefaultChar = NULL; 4370 getText.lpUsedDefChar = NULL; 4371 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP); 4372 ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP); 4373 4374 /* test for utf8 text with BOM */ 4375 setText.flags = 0; 4376 setText.codepage = CP_ACP; 4377 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM"); 4378 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4379 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result); 4380 result = strcmp(bufACP, "TestUTF8WithBOM"); 4381 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP); 4382 4383 setText.flags = 0; 4384 setText.codepage = CP_UTF8; 4385 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM"); 4386 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4387 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result); 4388 result = strcmp(bufACP, "TestUTF8WithBOM"); 4389 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP); 4390 4391 /* Test multibyte character */ 4392 if (!is_lang_japanese) 4393 skip("Skip multibyte character tests on non-Japanese platform\n"); 4394 else 4395 { 4396 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4397 setText.flags = ST_SELECTION; 4398 setText.codepage = CP_ACP; 4399 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0"); 4400 todo_wine ok(result == 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result); 4401 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4402 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4403 ok(!strcmp(bufACP, "abc\x8e\xf0"), 4404 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4405 4406 setText.flags = ST_DEFAULT; 4407 setText.codepage = CP_ACP; 4408 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0"); 4409 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result); 4410 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4411 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4412 ok(!strcmp(bufACP, "abc\x8e\xf0"), 4413 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4414 4415 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4416 setText.flags = ST_SELECTION; 4417 setText.codepage = CP_ACP; 4418 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf abc\x8e\xf0}"); 4419 todo_wine ok(result == 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result); 4420 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4421 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4422 todo_wine ok(!strcmp(bufACP, "abc\x8e\xf0"), 4423 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP); 4424 } 4425 4426 DestroyWindow(hwndRichEdit); 4427 4428 /* Single-line richedit */ 4429 hwndRichEdit = new_richedit_with_style(NULL, 0); 4430 setText.flags = ST_DEFAULT; 4431 setText.codepage = CP_ACP; 4432 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"line1\r\nline2"); 4433 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result); 4434 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP); 4435 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result); 4436 ok(!strcmp(bufACP, "line1"), "EM_SETTEXTEX: Test single-line text: Result: %s\n", bufACP); 4437 DestroyWindow(hwndRichEdit); 4438 } 4439 4440 static void test_EM_LIMITTEXT(void) 4441 { 4442 int ret; 4443 4444 HWND hwndRichEdit = new_richedit(NULL); 4445 4446 /* The main purpose of this test is to demonstrate that the nonsense in MSDN 4447 * about setting the length to -1 for multiline edit controls doesn't happen. 4448 */ 4449 4450 /* Don't check default gettextlimit case. That's done in other tests */ 4451 4452 /* Set textlimit to 100 */ 4453 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 100, 0); 4454 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4455 ok (ret == 100, 4456 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret); 4457 4458 /* Set textlimit to 0 */ 4459 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 0, 0); 4460 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4461 ok (ret == 65536, 4462 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret); 4463 4464 /* Set textlimit to -1 */ 4465 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -1, 0); 4466 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4467 ok (ret == -1, 4468 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret); 4469 4470 /* Set textlimit to -2 */ 4471 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -2, 0); 4472 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4473 ok (ret == -2, 4474 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret); 4475 4476 DestroyWindow (hwndRichEdit); 4477 } 4478 4479 4480 static void test_EM_EXLIMITTEXT(void) 4481 { 4482 int i, selBegin, selEnd, len1, len2; 4483 int result; 4484 char text[1024 + 1]; 4485 char buffer[1024 + 1]; 4486 int textlimit = 0; /* multiple of 100 */ 4487 HWND hwndRichEdit = new_richedit(NULL); 4488 4489 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4490 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */ 4491 4492 textlimit = 256000; 4493 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4494 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4495 /* set higher */ 4496 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i); 4497 4498 textlimit = 1000; 4499 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4500 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4501 /* set lower */ 4502 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i); 4503 4504 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 0); 4505 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4506 /* default for WParam = 0 */ 4507 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i); 4508 4509 textlimit = sizeof(text)-1; 4510 memset(text, 'W', textlimit); 4511 text[sizeof(text)-1] = 0; 4512 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4513 /* maxed out text */ 4514 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4515 4516 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */ 4517 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4518 len1 = selEnd - selBegin; 4519 4520 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1); 4521 SendMessageA(hwndRichEdit, WM_CHAR, VK_BACK, 1); 4522 SendMessageA(hwndRichEdit, WM_KEYUP, VK_BACK, 1); 4523 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4524 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4525 len2 = selEnd - selBegin; 4526 4527 ok(len1 != len2, 4528 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4529 len1,len2,i); 4530 4531 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1); 4532 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4533 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); 4534 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4535 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4536 len1 = selEnd - selBegin; 4537 4538 ok(len1 != len2, 4539 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4540 len1,len2,i); 4541 4542 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1); 4543 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4544 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */ 4545 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4546 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); 4547 len2 = selEnd - selBegin; 4548 4549 ok(len1 == len2, 4550 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n", 4551 len1,len2,i); 4552 4553 /* set text up to the limit, select all the text, then add a char */ 4554 textlimit = 5; 4555 memset(text, 'W', textlimit); 4556 text[textlimit] = 0; 4557 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4558 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4559 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 4560 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1); 4561 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4562 result = strcmp(buffer, "A"); 4563 ok(0 == result, "got string = \"%s\"\n", buffer); 4564 4565 /* WM_SETTEXT not limited */ 4566 textlimit = 10; 4567 memset(text, 'W', textlimit); 4568 text[textlimit] = 0; 4569 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5); 4570 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); 4571 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4572 i = strlen(buffer); 4573 ok(10 == i, "expected 10 chars\n"); 4574 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4575 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4576 4577 /* try inserting more text at end */ 4578 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4579 ok(0 == i, "WM_CHAR wasn't processed\n"); 4580 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4581 i = strlen(buffer); 4582 ok(10 == i, "expected 10 chars, got %i\n", i); 4583 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4584 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4585 4586 /* try inserting text at beginning */ 4587 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 4588 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4589 ok(0 == i, "WM_CHAR wasn't processed\n"); 4590 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4591 i = strlen(buffer); 4592 ok(10 == i, "expected 10 chars, got %i\n", i); 4593 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4594 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i); 4595 4596 /* WM_CHAR is limited */ 4597 textlimit = 1; 4598 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit); 4599 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */ 4600 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4601 ok(0 == i, "WM_CHAR wasn't processed\n"); 4602 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4603 ok(0 == i, "WM_CHAR wasn't processed\n"); 4604 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 4605 i = strlen(buffer); 4606 ok(1 == i, "expected 1 chars, got %i instead\n", i); 4607 4608 DestroyWindow(hwndRichEdit); 4609 } 4610 4611 static void test_EM_GETLIMITTEXT(void) 4612 { 4613 int i; 4614 HWND hwndRichEdit = new_richedit(NULL); 4615 4616 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4617 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */ 4618 4619 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000); 4620 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0); 4621 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i); 4622 4623 DestroyWindow(hwndRichEdit); 4624 } 4625 4626 static void test_WM_SETFONT(void) 4627 { 4628 /* There is no invalid input or error conditions for this function. 4629 * NULL wParam and lParam just fall back to their default values 4630 * It should be noted that even if you use a gibberish name for your fonts 4631 * here, it will still work because the name is stored. They will display as 4632 * System, but will report their name to be whatever they were created as */ 4633 4634 HWND hwndRichEdit = new_richedit(NULL); 4635 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4636 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4637 FF_DONTCARE, "Marlett"); 4638 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4639 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4640 FF_DONTCARE, "MS Sans Serif"); 4641 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4642 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4643 FF_DONTCARE, "Courier"); 4644 LOGFONTA sentLogFont; 4645 CHARFORMAT2A returnedCF2A; 4646 4647 returnedCF2A.cbSize = sizeof(returnedCF2A); 4648 4649 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x"); 4650 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0)); 4651 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4652 4653 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont); 4654 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4655 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n", 4656 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4657 4658 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0)); 4659 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4660 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont); 4661 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4662 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n", 4663 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4664 4665 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0)); 4666 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4667 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont); 4668 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), 4669 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n", 4670 sentLogFont.lfFaceName,returnedCF2A.szFaceName); 4671 4672 /* This last test is special since we send in NULL. We clear the variables 4673 * and just compare to "System" instead of the sent in font name. */ 4674 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A)); 4675 ZeroMemory(&sentLogFont,sizeof(sentLogFont)); 4676 returnedCF2A.cbSize = sizeof(returnedCF2A); 4677 4678 SendMessageA(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0)); 4679 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A); 4680 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont); 4681 ok (!strcmp("System",returnedCF2A.szFaceName), 4682 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName); 4683 4684 DestroyWindow(hwndRichEdit); 4685 } 4686 4687 4688 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, 4689 LPBYTE pbBuff, 4690 LONG cb, 4691 LONG *pcb) 4692 { 4693 const char** str = (const char**)dwCookie; 4694 int size = strlen(*str); 4695 if(size > 3) /* let's make it piecemeal for fun */ 4696 size = 3; 4697 *pcb = cb; 4698 if (*pcb > size) { 4699 *pcb = size; 4700 } 4701 if (*pcb > 0) { 4702 memcpy(pbBuff, *str, *pcb); 4703 *str += *pcb; 4704 } 4705 return 0; 4706 } 4707 4708 static void test_EM_GETMODIFY(void) 4709 { 4710 HWND hwndRichEdit = new_richedit(NULL); 4711 LRESULT result; 4712 SETTEXTEX setText; 4713 WCHAR TestItem1[] = {'T', 'e', 's', 't', 4714 'S', 'o', 'm', 'e', 4715 'T', 'e', 'x', 't', 0}; 4716 WCHAR TestItem2[] = {'T', 'e', 's', 't', 4717 'S', 'o', 'm', 'e', 4718 'O', 't', 'h', 'e', 'r', 4719 'T', 'e', 'x', 't', 0}; 4720 const char* streamText = "hello world"; 4721 CHARFORMAT2A cf2; 4722 PARAFORMAT2 pf2; 4723 EDITSTREAM es; 4724 4725 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 4726 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 4727 FF_DONTCARE, "Courier"); 4728 4729 setText.codepage = 1200; /* no constant for unicode */ 4730 setText.flags = ST_KEEPUNDO; 4731 4732 4733 /* modify flag shouldn't be set when richedit is first created */ 4734 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4735 ok (result == 0, 4736 "EM_GETMODIFY returned non-zero, instead of zero on create\n"); 4737 4738 /* setting modify flag should actually set it */ 4739 SendMessageA(hwndRichEdit, EM_SETMODIFY, TRUE, 0); 4740 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4741 ok (result != 0, 4742 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n"); 4743 4744 /* clearing modify flag should actually clear it */ 4745 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4746 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4747 ok (result == 0, 4748 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n"); 4749 4750 /* setting font doesn't change modify flag */ 4751 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4752 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0)); 4753 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4754 ok (result == 0, 4755 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n"); 4756 4757 /* setting text should set modify flag */ 4758 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4759 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4760 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4761 ok (result != 0, 4762 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n"); 4763 4764 /* undo previous text doesn't reset modify flag */ 4765 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0); 4766 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4767 ok (result != 0, 4768 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n"); 4769 4770 /* set text with no flag to keep undo stack should not set modify flag */ 4771 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4772 setText.flags = 0; 4773 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4774 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4775 ok (result == 0, 4776 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n"); 4777 4778 /* WM_SETTEXT doesn't modify */ 4779 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4780 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2); 4781 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4782 ok (result == 0, 4783 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n"); 4784 4785 /* clear the text */ 4786 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4787 SendMessageA(hwndRichEdit, WM_CLEAR, 0, 0); 4788 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4789 ok (result == 0, 4790 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n"); 4791 4792 /* replace text */ 4793 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4794 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); 4795 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4796 SendMessageA(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2); 4797 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4798 ok (result != 0, 4799 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n"); 4800 4801 /* copy/paste text 1 */ 4802 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4803 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4804 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 4805 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 4806 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4807 ok (result != 0, 4808 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n"); 4809 4810 /* copy/paste text 2 */ 4811 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4812 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2); 4813 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 4814 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 3); 4815 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 4816 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4817 ok (result != 0, 4818 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n"); 4819 4820 /* press char */ 4821 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4822 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 1); 4823 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4824 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4825 ok (result != 0, 4826 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n"); 4827 4828 /* press del */ 4829 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0); 4830 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4831 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0); 4832 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4833 ok (result != 0, 4834 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n"); 4835 4836 /* set char format */ 4837 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4838 cf2.cbSize = sizeof(CHARFORMAT2A); 4839 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 4840 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 4841 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 4842 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 4843 result = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); 4844 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result); 4845 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4846 ok (result != 0, 4847 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n"); 4848 4849 /* set para format */ 4850 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4851 pf2.cbSize = sizeof(PARAFORMAT2); 4852 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2); 4853 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask; 4854 pf2.wAlignment = PFA_RIGHT; 4855 SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); 4856 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4857 ok (result == 0, 4858 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n"); 4859 4860 /* EM_STREAM */ 4861 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0); 4862 es.dwCookie = (DWORD_PTR)&streamText; 4863 es.dwError = 0; 4864 es.pfnCallback = test_EM_GETMODIFY_esCallback; 4865 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 4866 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0); 4867 ok (result != 0, 4868 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n"); 4869 4870 DestroyWindow(hwndRichEdit); 4871 } 4872 4873 struct exsetsel_s { 4874 LONG min; 4875 LONG max; 4876 LRESULT expected_retval; 4877 int expected_getsel_start; 4878 int expected_getsel_end; 4879 BOOL todo; 4880 }; 4881 4882 static const struct exsetsel_s exsetsel_tests[] = { 4883 /* sanity tests */ 4884 {5, 10, 10, 5, 10 }, 4885 {15, 17, 17, 15, 17 }, 4886 /* test cpMax > strlen() */ 4887 {0, 100, 18, 0, 18 }, 4888 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */ 4889 {-1, 1, 17, 17, 17 }, 4890 /* test cpMin == cpMax */ 4891 {5, 5, 5, 5, 5 }, 4892 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */ 4893 {-1, 0, 5, 5, 5 }, 4894 {-1, 17, 5, 5, 5 }, 4895 {-1, 18, 5, 5, 5 }, 4896 /* test cpMin < 0 && cpMax < 0 */ 4897 {-1, -1, 17, 17, 17 }, 4898 {-4, -5, 17, 17, 17 }, 4899 /* test cpMin >=0 && cpMax < 0 (bug 6814) */ 4900 {0, -1, 18, 0, 18 }, 4901 {17, -5, 18, 17, 18 }, 4902 {18, -3, 17, 17, 17 }, 4903 /* test if cpMin > cpMax */ 4904 {15, 19, 18, 15, 18 }, 4905 {19, 15, 18, 15, 18 }, 4906 /* cpMin == strlen() && cpMax > cpMin */ 4907 {17, 18, 18, 17, 18 }, 4908 {17, 50, 18, 17, 18 }, 4909 }; 4910 4911 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 4912 CHARRANGE cr; 4913 LRESULT result; 4914 int start, end; 4915 4916 cr.cpMin = setsel->min; 4917 cr.cpMax = setsel->max; 4918 result = SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); 4919 4920 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); 4921 4922 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 4923 4924 todo_wine_if (setsel->todo) 4925 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", 4926 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end); 4927 } 4928 4929 static void test_EM_EXSETSEL(void) 4930 { 4931 HWND hwndRichEdit = new_richedit(NULL); 4932 int i; 4933 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); 4934 4935 /* sending some text to the window */ 4936 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 4937 /* 01234567890123456*/ 4938 /* 10 */ 4939 4940 for (i = 0; i < num_tests; i++) { 4941 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i); 4942 } 4943 4944 if (!is_lang_japanese) 4945 skip("Skip multibyte character tests on non-Japanese platform\n"); 4946 else 4947 { 4948 CHARRANGE cr; 4949 char bufA[MAX_BUF_LEN] = {0}; 4950 LRESULT result; 4951 4952 /* Test with multibyte character */ 4953 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 4954 /* 012345 6 78901 */ 4955 cr.cpMin = 4, cr.cpMax = 8; 4956 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); 4957 ok(result == 8, "EM_EXSETSEL return %ld expected 8\n", result); 4958 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA); 4959 ok(!strcmp(bufA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n"); 4960 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 4961 ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin); 4962 ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax); 4963 } 4964 4965 DestroyWindow(hwndRichEdit); 4966 } 4967 4968 static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { 4969 LRESULT result; 4970 int start, end; 4971 4972 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max); 4973 4974 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); 4975 4976 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 4977 4978 todo_wine_if (setsel->todo) 4979 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", 4980 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end); 4981 } 4982 4983 static void test_EM_SETSEL(void) 4984 { 4985 char buffA[32] = {0}; 4986 HWND hwndRichEdit = new_richedit(NULL); 4987 int i; 4988 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); 4989 4990 /* sending some text to the window */ 4991 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 4992 /* 01234567890123456*/ 4993 /* 10 */ 4994 4995 for (i = 0; i < num_tests; i++) { 4996 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i); 4997 } 4998 4999 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18); 5000 buffA[0] = 123; 5001 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA); 5002 ok(buffA[0] == 0, "selection text %s\n", buffA); 5003 5004 if (!is_lang_japanese) 5005 skip("Skip multibyte character tests on non-Japanese platform\n"); 5006 else 5007 { 5008 int sel_start, sel_end; 5009 LRESULT result; 5010 5011 /* Test with multibyte character */ 5012 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); 5013 /* 012345 6 78901 */ 5014 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8); 5015 ok(result == 8, "EM_SETSEL return %ld expected 8\n", result); 5016 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA); 5017 ok(!strcmp(buffA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n"); 5018 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 5019 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start); 5020 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end); 5021 } 5022 5023 DestroyWindow(hwndRichEdit); 5024 } 5025 5026 static void test_EM_REPLACESEL(int redraw) 5027 { 5028 HWND hwndRichEdit = new_richedit(NULL); 5029 char buffer[1024] = {0}; 5030 int r; 5031 GETTEXTEX getText; 5032 CHARRANGE cr; 5033 CHAR rtfstream[] = "{\\rtf1 TestSomeText}"; 5034 CHAR urtfstream[] = "{\\urtf1 TestSomeText}"; 5035 5036 /* sending some text to the window */ 5037 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); 5038 /* 01234567890123456*/ 5039 /* 10 */ 5040 5041 /* FIXME add more tests */ 5042 SendMessageA(hwndRichEdit, EM_SETSEL, 7, 17); 5043 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, 0); 5044 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r); 5045 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5046 r = strcmp(buffer, "testing"); 5047 ok(0 == r, "expected %d, got %d\n", 0, r); 5048 5049 DestroyWindow(hwndRichEdit); 5050 5051 hwndRichEdit = new_richedit(NULL); 5052 5053 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw); 5054 SendMessageA(hwndRichEdit, WM_SETREDRAW, redraw, 0); 5055 5056 /* Test behavior with carriage returns and newlines */ 5057 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5058 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1"); 5059 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r); 5060 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5061 r = strcmp(buffer, "RichEdit1"); 5062 ok(0 == r, "expected %d, got %d\n", 0, r); 5063 getText.cb = 1024; 5064 getText.codepage = CP_ACP; 5065 getText.flags = GT_DEFAULT; 5066 getText.lpDefaultChar = NULL; 5067 getText.lpUsedDefChar = NULL; 5068 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5069 ok(strcmp(buffer, "RichEdit1") == 0, 5070 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n"); 5071 5072 /* Test number of lines reported after EM_REPLACESEL */ 5073 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5074 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); 5075 5076 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5077 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r"); 5078 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r); 5079 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5080 r = strcmp(buffer, "RichEdit1\r\n"); 5081 ok(0 == r, "expected %d, got %d\n", 0, r); 5082 getText.cb = 1024; 5083 getText.codepage = CP_ACP; 5084 getText.flags = GT_DEFAULT; 5085 getText.lpDefaultChar = NULL; 5086 getText.lpUsedDefChar = NULL; 5087 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5088 ok(strcmp(buffer, "RichEdit1\r") == 0, 5089 "EM_GETTEXTEX returned incorrect string\n"); 5090 5091 /* Test number of lines reported after EM_REPLACESEL */ 5092 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5093 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5094 5095 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5096 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r\n"); 5097 ok(r == 11, "EM_REPLACESEL returned %d, expected 11\n", r); 5098 5099 /* Test number of lines reported after EM_REPLACESEL */ 5100 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5101 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5102 5103 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5104 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5105 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin); 5106 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax); 5107 5108 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5109 r = strcmp(buffer, "RichEdit1\r\n"); 5110 ok(0 == r, "expected %d, got %d\n", 0, r); 5111 getText.cb = 1024; 5112 getText.codepage = CP_ACP; 5113 getText.flags = GT_DEFAULT; 5114 getText.lpDefaultChar = NULL; 5115 getText.lpUsedDefChar = NULL; 5116 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5117 ok(strcmp(buffer, "RichEdit1\r") == 0, 5118 "EM_GETTEXTEX returned incorrect string\n"); 5119 5120 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5121 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5122 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin); 5123 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax); 5124 5125 /* The following tests show that richedit should handle the special \r\r\n 5126 sequence by turning it into a single space on insertion. However, 5127 EM_REPLACESEL on WinXP returns the number of characters in the original 5128 string. 5129 */ 5130 5131 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5132 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r"); 5133 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r); 5134 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5135 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5136 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5137 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5138 5139 /* Test the actual string */ 5140 getText.cb = 1024; 5141 getText.codepage = CP_ACP; 5142 getText.flags = GT_DEFAULT; 5143 getText.lpDefaultChar = NULL; 5144 getText.lpUsedDefChar = NULL; 5145 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5146 ok(strcmp(buffer, "\r\r") == 0, 5147 "EM_GETTEXTEX returned incorrect string\n"); 5148 5149 /* Test number of lines reported after EM_REPLACESEL */ 5150 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5151 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5152 5153 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5154 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n"); 5155 ok(r == 3, "EM_REPLACESEL returned %d, expected 3\n", r); 5156 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5157 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5158 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin); 5159 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax); 5160 5161 /* Test the actual string */ 5162 getText.cb = 1024; 5163 getText.codepage = CP_ACP; 5164 getText.flags = GT_DEFAULT; 5165 getText.lpDefaultChar = NULL; 5166 getText.lpUsedDefChar = NULL; 5167 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5168 ok(strcmp(buffer, " ") == 0, 5169 "EM_GETTEXTEX returned incorrect string\n"); 5170 5171 /* Test number of lines reported after EM_REPLACESEL */ 5172 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5173 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); 5174 5175 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5176 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\r\r\r\n\r\r\r"); 5177 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r); 5178 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5179 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5180 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin); 5181 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax); 5182 5183 /* Test the actual string */ 5184 getText.cb = 1024; 5185 getText.codepage = CP_ACP; 5186 getText.flags = GT_DEFAULT; 5187 getText.lpDefaultChar = NULL; 5188 getText.lpUsedDefChar = NULL; 5189 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5190 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0, 5191 "EM_GETTEXTEX returned incorrect string\n"); 5192 5193 /* Test number of lines reported after EM_REPLACESEL */ 5194 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5195 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); 5196 5197 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5198 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\n"); 5199 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5200 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5201 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5202 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5203 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5204 5205 /* Test the actual string */ 5206 getText.cb = 1024; 5207 getText.codepage = CP_ACP; 5208 getText.flags = GT_DEFAULT; 5209 getText.lpDefaultChar = NULL; 5210 getText.lpUsedDefChar = NULL; 5211 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5212 ok(strcmp(buffer, " \r") == 0, 5213 "EM_GETTEXTEX returned incorrect string\n"); 5214 5215 /* Test number of lines reported after EM_REPLACESEL */ 5216 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5217 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); 5218 5219 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5220 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\r"); 5221 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5222 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5223 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5224 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin); 5225 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax); 5226 5227 /* Test the actual string */ 5228 getText.cb = 1024; 5229 getText.codepage = CP_ACP; 5230 getText.flags = GT_DEFAULT; 5231 getText.lpDefaultChar = NULL; 5232 getText.lpUsedDefChar = NULL; 5233 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5234 ok(strcmp(buffer, " \r\r") == 0, 5235 "EM_GETTEXTEX returned incorrect string\n"); 5236 5237 /* Test number of lines reported after EM_REPLACESEL */ 5238 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5239 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5240 5241 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5242 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\rX\r\n\r\r"); 5243 ok(r == 6, "EM_REPLACESEL returned %d, expected 6\n", r); 5244 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5245 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5246 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin); 5247 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax); 5248 5249 /* Test the actual string */ 5250 getText.cb = 1024; 5251 getText.codepage = CP_ACP; 5252 getText.flags = GT_DEFAULT; 5253 getText.lpDefaultChar = NULL; 5254 getText.lpUsedDefChar = NULL; 5255 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5256 ok(strcmp(buffer, "\rX\r\r\r") == 0, 5257 "EM_GETTEXTEX returned incorrect string\n"); 5258 5259 /* Test number of lines reported after EM_REPLACESEL */ 5260 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5261 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r); 5262 5263 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5264 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n"); 5265 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r); 5266 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5267 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5268 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin); 5269 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax); 5270 5271 /* Test the actual string */ 5272 getText.cb = 1024; 5273 getText.codepage = CP_ACP; 5274 getText.flags = GT_DEFAULT; 5275 getText.lpDefaultChar = NULL; 5276 getText.lpUsedDefChar = NULL; 5277 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5278 ok(strcmp(buffer, "\r\r") == 0, 5279 "EM_GETTEXTEX returned incorrect string\n"); 5280 5281 /* Test number of lines reported after EM_REPLACESEL */ 5282 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5283 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); 5284 5285 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5286 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n\n\n\r\r\r\r\n"); 5287 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r); 5288 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5289 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5290 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin); 5291 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax); 5292 5293 /* Test the actual string */ 5294 getText.cb = 1024; 5295 getText.codepage = CP_ACP; 5296 getText.flags = GT_DEFAULT; 5297 getText.lpDefaultChar = NULL; 5298 getText.lpUsedDefChar = NULL; 5299 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer); 5300 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0, 5301 "EM_GETTEXTEX returned incorrect string\n"); 5302 5303 /* Test number of lines reported after EM_REPLACESEL */ 5304 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0); 5305 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); 5306 5307 /* Test with multibyte character */ 5308 if (!is_lang_japanese) 5309 skip("Skip multibyte character tests on non-Japanese platform\n"); 5310 else 5311 { 5312 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5313 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"abc\x8e\xf0"); 5314 todo_wine ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r); 5315 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5316 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r); 5317 ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin); 5318 ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax); 5319 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5320 ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n"); 5321 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5322 5323 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5324 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"{\\rtf abc\x8e\xf0}"); 5325 todo_wine ok(r == 4, "EM_REPLACESEL returned %d, expected 4\n", r); 5326 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5327 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r); 5328 todo_wine ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin); 5329 todo_wine ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax); 5330 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5331 todo_wine ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n"); 5332 todo_wine ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5333 } 5334 5335 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5336 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5337 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5338 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5339 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5340 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin); 5341 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax); 5342 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5343 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n"); 5344 5345 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5346 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urtfstream); 5347 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5348 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5349 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5350 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin); 5351 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax); 5352 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5353 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n"); 5354 5355 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Wine"); 5356 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2); 5357 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5358 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5359 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5360 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5361 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin); 5362 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax); 5363 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5364 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n"); 5365 5366 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 Wine}"); 5367 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2); 5368 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream); 5369 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5370 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); 5371 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); 5372 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin); 5373 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax); 5374 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5375 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n"); 5376 5377 if (!redraw) 5378 /* This is needed to avoid interfering with keybd_event calls 5379 * on other tests that simulate keyboard events. */ 5380 SendMessageA(hwndRichEdit, WM_SETREDRAW, TRUE, 0); 5381 5382 DestroyWindow(hwndRichEdit); 5383 5384 /* Single-line richedit */ 5385 hwndRichEdit = new_richedit_with_style(NULL, 0); 5386 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"line1\r\nline2"); 5387 ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r); 5388 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5389 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r); 5390 ok(!strcmp(buffer, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buffer); 5391 DestroyWindow(hwndRichEdit); 5392 } 5393 5394 /* Native riched20 inspects the keyboard state (e.g. GetKeyState) 5395 * to test the state of the modifiers (Ctrl/Alt/Shift). 5396 * 5397 * Therefore Ctrl-<key> keystrokes need to be simulated with 5398 * keybd_event or by using SetKeyboardState to set the modifiers 5399 * and SendMessage to simulate the keystrokes. 5400 */ 5401 static LRESULT send_ctrl_key(HWND hwnd, UINT key) 5402 { 5403 LRESULT result; 5404 hold_key(VK_CONTROL); 5405 result = SendMessageA(hwnd, WM_KEYDOWN, key, 1); 5406 release_key(VK_CONTROL); 5407 return result; 5408 } 5409 5410 static void test_WM_PASTE(void) 5411 { 5412 int result; 5413 char buffer[1024] = {0}; 5414 const char* text1 = "testing paste\r"; 5415 const char* text1_step1 = "testing paste\r\ntesting paste\r\n"; 5416 const char* text1_after = "testing paste\r\n"; 5417 const char* text2 = "testing paste\r\rtesting paste"; 5418 const char* text2_after = "testing paste\r\n\r\ntesting paste"; 5419 const char* text3 = "testing paste\r\npaste\r\ntesting paste"; 5420 HWND hwndRichEdit = new_richedit(NULL); 5421 5422 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 5423 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 14); 5424 5425 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */ 5426 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14); 5427 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */ 5428 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5429 /* Pasted text should be visible at this step */ 5430 result = strcmp(text1_step1, buffer); 5431 ok(result == 0, 5432 "test paste: strcmp = %i, text='%s'\n", result, buffer); 5433 5434 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */ 5435 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5436 /* Text should be the same as before (except for \r -> \r\n conversion) */ 5437 result = strcmp(text1_after, buffer); 5438 ok(result == 0, 5439 "test paste: strcmp = %i, text='%s'\n", result, buffer); 5440 5441 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 5442 SendMessageA(hwndRichEdit, EM_SETSEL, 8, 13); 5443 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */ 5444 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14); 5445 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */ 5446 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5447 /* Pasted text should be visible at this step */ 5448 result = strcmp(text3, buffer); 5449 ok(result == 0, 5450 "test paste: strcmp = %i\n", result); 5451 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */ 5452 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5453 /* Text should be the same as before (except for \r -> \r\n conversion) */ 5454 result = strcmp(text2_after, buffer); 5455 ok(result == 0, 5456 "test paste: strcmp = %i\n", result); 5457 send_ctrl_key(hwndRichEdit, 'Y'); /* Redo */ 5458 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5459 /* Text should revert to post-paste state */ 5460 result = strcmp(buffer,text3); 5461 ok(result == 0, 5462 "test paste: strcmp = %i\n", result); 5463 5464 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5465 /* Send WM_CHAR to simulate Ctrl-V */ 5466 SendMessageA(hwndRichEdit, WM_CHAR, 22, 5467 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1); 5468 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5469 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */ 5470 result = strcmp(buffer,""); 5471 ok(result == 0, 5472 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5473 5474 /* Send keystrokes with WM_KEYDOWN after setting the modifiers 5475 * with SetKeyboard state. */ 5476 5477 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5478 /* Simulates paste (Ctrl-V) */ 5479 hold_key(VK_CONTROL); 5480 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'V', 5481 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1); 5482 release_key(VK_CONTROL); 5483 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5484 result = strcmp(buffer,"paste"); 5485 ok(result == 0, 5486 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5487 5488 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 5489 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 7); 5490 /* Simulates copy (Ctrl-C) */ 5491 hold_key(VK_CONTROL); 5492 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'C', 5493 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC) << 16) | 1); 5494 release_key(VK_CONTROL); 5495 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5496 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5497 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5498 result = strcmp(buffer,"testing"); 5499 ok(result == 0, 5500 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5501 5502 /* Cut with WM_KEYDOWN to simulate Ctrl-X */ 5503 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"cut"); 5504 /* Simulates select all (Ctrl-A) */ 5505 hold_key(VK_CONTROL); 5506 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 5507 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC) << 16) | 1); 5508 /* Simulates select cut (Ctrl-X) */ 5509 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'X', 5510 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC) << 16) | 1); 5511 release_key(VK_CONTROL); 5512 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5513 result = strcmp(buffer,""); 5514 ok(result == 0, 5515 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5516 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0); 5517 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5518 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5519 result = strcmp(buffer,"cut\r\n"); 5520 ok(result == 0, 5521 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5522 /* Simulates undo (Ctrl-Z) */ 5523 hold_key(VK_CONTROL); 5524 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Z', 5525 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC) << 16) | 1); 5526 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5527 result = strcmp(buffer,""); 5528 ok(result == 0, 5529 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5530 /* Simulates redo (Ctrl-Y) */ 5531 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Y', 5532 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC) << 16) | 1); 5533 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5534 result = strcmp(buffer,"cut\r\n"); 5535 ok(result == 0, 5536 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5537 release_key(VK_CONTROL); 5538 5539 /* Copy multiline text to clipboard for future use */ 5540 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); 5541 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 5542 SendMessageA(hwndRichEdit, WM_COPY, 0, 0); 5543 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0); 5544 5545 /* Paste into read-only control */ 5546 result = SendMessageA(hwndRichEdit, EM_SETREADONLY, TRUE, 0); 5547 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5548 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5549 result = strcmp(buffer, text3); 5550 ok(result == 0, 5551 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5552 5553 /* Cut from read-only control */ 5554 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); 5555 SendMessageA(hwndRichEdit, WM_CUT, 0, 0); 5556 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5557 result = strcmp(buffer, text3); 5558 ok(result == 0, 5559 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5560 5561 /* FIXME: Wine doesn't flush Ole clipboard when window is destroyed so do it manually */ 5562 OleFlushClipboard(); 5563 DestroyWindow(hwndRichEdit); 5564 5565 /* Paste multi-line text into single-line control */ 5566 hwndRichEdit = new_richedit_with_style(NULL, 0); 5567 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0); 5568 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5569 result = strcmp(buffer, "testing paste"); 5570 ok(result == 0, 5571 "test paste: strcmp = %i, actual = '%s'\n", result, buffer); 5572 DestroyWindow(hwndRichEdit); 5573 } 5574 5575 static void test_EM_FORMATRANGE(void) 5576 { 5577 int r, i, tpp_x, tpp_y; 5578 HDC hdc; 5579 HWND hwndRichEdit = new_richedit(NULL); 5580 FORMATRANGE fr; 5581 BOOL skip_non_english; 5582 static const struct { 5583 const char *string; /* The string */ 5584 int first; /* First 'pagebreak', 0 for don't care */ 5585 int second; /* Second 'pagebreak', 0 for don't care */ 5586 } fmtstrings[] = { 5587 {"WINE wine", 0, 0}, 5588 {"WINE wineWine", 0, 0}, 5589 {"WINE\r\nwine\r\nwine", 5, 10}, 5590 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14}, 5591 {"WINE\r\n\r\nwine\r\nwine", 5, 6} 5592 }; 5593 5594 skip_non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH); 5595 if (skip_non_english) 5596 skip("Skipping some tests on non-English platform\n"); 5597 5598 hdc = GetDC(hwndRichEdit); 5599 ok(hdc != NULL, "Could not get HDC\n"); 5600 5601 /* Calculate the twips per pixel */ 5602 tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX); 5603 tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY); 5604 5605 /* Test the simple case where all the text fits in the page rect. */ 5606 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); 5607 fr.hdc = fr.hdcTarget = hdc; 5608 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0; 5609 fr.rc.right = fr.rcPage.right = 500 * tpp_x; 5610 fr.rc.bottom = fr.rcPage.bottom = 500 * tpp_y; 5611 fr.chrg.cpMin = 0; 5612 fr.chrg.cpMax = -1; 5613 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr); 5614 todo_wine ok(r == 2, "r=%d expected r=2\n", r); 5615 5616 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"ab"); 5617 fr.rc.bottom = fr.rcPage.bottom; 5618 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr); 5619 todo_wine ok(r == 3, "r=%d expected r=3\n", r); 5620 5621 SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0); 5622 5623 for (i = 0; i < sizeof(fmtstrings)/sizeof(fmtstrings[0]); i++) 5624 { 5625 GETTEXTLENGTHEX gtl; 5626 SIZE stringsize; 5627 int len; 5628 5629 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)fmtstrings[i].string); 5630 5631 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 5632 gtl.codepage = CP_ACP; 5633 len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 5634 5635 /* Get some size information for the string */ 5636 GetTextExtentPoint32A(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize); 5637 5638 /* Define the box to be half the width needed and a bit larger than the height. 5639 * Changes to the width means we have at least 2 pages. Changes to the height 5640 * is done so we can check the changing of fr.rc.bottom. 5641 */ 5642 fr.hdc = fr.hdcTarget = hdc; 5643 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0; 5644 fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x; 5645 fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y; 5646 5647 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); 5648 todo_wine { 5649 ok(r == len, "Expected %d, got %d\n", len, r); 5650 } 5651 5652 /* We know that the page can't hold the full string. See how many characters 5653 * are on the first one 5654 */ 5655 fr.chrg.cpMin = 0; 5656 fr.chrg.cpMax = -1; 5657 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 5658 todo_wine { 5659 if (! skip_non_english) 5660 ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom); 5661 } 5662 if (fmtstrings[i].first) 5663 todo_wine { 5664 ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r); 5665 } 5666 else 5667 ok(r < len, "Expected < %d, got %d\n", len, r); 5668 5669 /* Do another page */ 5670 fr.chrg.cpMin = r; 5671 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 5672 if (fmtstrings[i].second) 5673 todo_wine { 5674 ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r); 5675 } 5676 else if (! skip_non_english) 5677 ok (r < len, "Expected < %d, got %d\n", len, r); 5678 5679 /* There is at least on more page, but we don't care */ 5680 5681 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); 5682 todo_wine { 5683 ok(r == len, "Expected %d, got %d\n", len, r); 5684 } 5685 } 5686 5687 ReleaseDC(NULL, hdc); 5688 DestroyWindow(hwndRichEdit); 5689 } 5690 5691 static int nCallbackCount = 0; 5692 5693 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, 5694 LONG cb, LONG* pcb) 5695 { 5696 const char text[] = {'t','e','s','t'}; 5697 5698 if (sizeof(text) <= cb) 5699 { 5700 if ((int)dwCookie != nCallbackCount) 5701 { 5702 *pcb = 0; 5703 return 0; 5704 } 5705 5706 memcpy (pbBuff, text, sizeof(text)); 5707 *pcb = sizeof(text); 5708 5709 nCallbackCount++; 5710 5711 return 0; 5712 } 5713 else 5714 return 1; /* indicates callback failed */ 5715 } 5716 5717 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, 5718 LPBYTE pbBuff, 5719 LONG cb, 5720 LONG *pcb) 5721 { 5722 const char** str = (const char**)dwCookie; 5723 int size = strlen(*str); 5724 *pcb = cb; 5725 if (*pcb > size) { 5726 *pcb = size; 5727 } 5728 if (*pcb > 0) { 5729 memcpy(pbBuff, *str, *pcb); 5730 *str += *pcb; 5731 } 5732 return 0; 5733 } 5734 5735 static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie, 5736 LPBYTE pbBuff, 5737 LONG cb, 5738 LONG *pcb) 5739 { 5740 DWORD *phase = (DWORD *)dwCookie; 5741 5742 if(*phase == 0){ 5743 static const char first[] = "\xef\xbb\xbf\xc3\x96\xc3"; 5744 *pcb = sizeof(first) - 1; 5745 memcpy(pbBuff, first, *pcb); 5746 }else if(*phase == 1){ 5747 static const char second[] = "\x8f\xc3\x8b"; 5748 *pcb = sizeof(second) - 1; 5749 memcpy(pbBuff, second, *pcb); 5750 }else 5751 *pcb = 0; 5752 5753 ++*phase; 5754 5755 return 0; 5756 } 5757 5758 struct StringWithLength { 5759 int length; 5760 char *buffer; 5761 }; 5762 5763 /* This callback is used to handled the null characters in a string. */ 5764 static DWORD CALLBACK test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie, 5765 LPBYTE pbBuff, 5766 LONG cb, 5767 LONG *pcb) 5768 { 5769 struct StringWithLength* str = (struct StringWithLength*)dwCookie; 5770 int size = str->length; 5771 *pcb = cb; 5772 if (*pcb > size) { 5773 *pcb = size; 5774 } 5775 if (*pcb > 0) { 5776 memcpy(pbBuff, str->buffer, *pcb); 5777 str->buffer += *pcb; 5778 str->length -= *pcb; 5779 } 5780 return 0; 5781 } 5782 5783 static void test_EM_STREAMIN(void) 5784 { 5785 HWND hwndRichEdit = new_richedit(NULL); 5786 DWORD phase; 5787 LRESULT result; 5788 EDITSTREAM es; 5789 char buffer[1024] = {0}, tmp[16]; 5790 CHARRANGE range; 5791 PARAFORMAT2 fmt; 5792 5793 const char * streamText0 = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}"; 5794 const char * streamText0a = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}"; 5795 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; 5796 const char * ptr; 5797 5798 const char * streamText1 = 5799 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" 5800 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" 5801 "}\r\n"; 5802 5803 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */ 5804 const char * streamText2 = 5805 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" 5806 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" 5807 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " 5808 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " 5809 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " 5810 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " 5811 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; 5812 5813 const char * streamText3 = "RichEdit1"; 5814 5815 const char * streamTextUTF8BOM = "\xef\xbb\xbfTestUTF8WithBOM"; 5816 5817 const char * streamText4 = 5818 "This text just needs to be long enough to cause run to be split onto " 5819 "two separate lines and make sure the null terminating character is " 5820 "handled properly.\0"; 5821 5822 const WCHAR UTF8Split_exp[4] = {0xd6, 0xcf, 0xcb, 0}; 5823 5824 int length4 = strlen(streamText4) + 1; 5825 struct StringWithLength cookieForStream4 = { 5826 length4, 5827 (char *)streamText4, 5828 }; 5829 5830 const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' }; 5831 int length5 = sizeof(streamText5) / sizeof(WCHAR); 5832 struct StringWithLength cookieForStream5 = { 5833 sizeof(streamText5), 5834 (char *)streamText5, 5835 }; 5836 5837 /* Minimal test without \par at the end */ 5838 es.dwCookie = (DWORD_PTR)&streamText0; 5839 es.dwError = 0; 5840 es.pfnCallback = test_EM_STREAMIN_esCallback; 5841 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5842 ok(result == 12, "got %ld, expected %d\n", result, 12); 5843 5844 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5845 ok (result == 12, 5846 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result); 5847 result = strcmp (buffer,"TestSomeText"); 5848 ok (result == 0, 5849 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer); 5850 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); 5851 /* Show that para fmts are ignored */ 5852 range.cpMin = 2; 5853 range.cpMax = 2; 5854 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5855 memset(&fmt, 0xcc, sizeof(fmt)); 5856 fmt.cbSize = sizeof(fmt); 5857 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 5858 ok(fmt.dxStartIndent == 0, "got %d\n", fmt.dxStartIndent); 5859 ok(fmt.dxOffset == 0, "got %d\n", fmt.dxOffset); 5860 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment); 5861 ok((fmt.wEffects & PFE_RTLPARA) == 0, "got %x\n", fmt.wEffects); 5862 5863 /* Native richedit 2.0 ignores last \par */ 5864 ptr = streamText0a; 5865 es.dwCookie = (DWORD_PTR)&ptr; 5866 es.dwError = 0; 5867 es.pfnCallback = test_EM_STREAMIN_esCallback; 5868 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5869 ok(result == 12, "got %ld, expected %d\n", result, 12); 5870 5871 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5872 ok (result == 12, 5873 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); 5874 result = strcmp (buffer,"TestSomeText"); 5875 ok (result == 0, 5876 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); 5877 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0); 5878 /* This time para fmts are processed */ 5879 range.cpMin = 2; 5880 range.cpMax = 2; 5881 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5882 memset(&fmt, 0xcc, sizeof(fmt)); 5883 fmt.cbSize = sizeof(fmt); 5884 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt); 5885 ok(fmt.dxStartIndent == 300, "got %d\n", fmt.dxStartIndent); 5886 ok(fmt.dxOffset == -100, "got %d\n", fmt.dxOffset); 5887 ok(fmt.wAlignment == PFA_RIGHT, "got %d\n", fmt.wAlignment); 5888 ok((fmt.wEffects & PFE_RTLPARA) == PFE_RTLPARA, "got %x\n", fmt.wEffects); 5889 5890 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */ 5891 es.dwCookie = (DWORD_PTR)&streamText0b; 5892 es.dwError = 0; 5893 es.pfnCallback = test_EM_STREAMIN_esCallback; 5894 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5895 ok(result == 13, "got %ld, expected %d\n", result, 13); 5896 5897 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5898 ok (result == 14, 5899 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result); 5900 result = strcmp (buffer,"TestSomeText\r\n"); 5901 ok (result == 0, 5902 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer); 5903 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0); 5904 5905 /* Show that when using SFF_SELECTION the last \par is not ignored. */ 5906 ptr = streamText0a; 5907 es.dwCookie = (DWORD_PTR)&ptr; 5908 es.dwError = 0; 5909 es.pfnCallback = test_EM_STREAMIN_esCallback; 5910 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5911 ok(result == 12, "got %ld, expected %d\n", result, 12); 5912 5913 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5914 ok (result == 12, 5915 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); 5916 result = strcmp (buffer,"TestSomeText"); 5917 ok (result == 0, 5918 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); 5919 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0); 5920 5921 range.cpMin = 0; 5922 range.cpMax = -1; 5923 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range); 5924 ok (result == 13, "got %ld\n", result); 5925 5926 ptr = streamText0a; 5927 es.dwCookie = (DWORD_PTR)&ptr; 5928 es.dwError = 0; 5929 es.pfnCallback = test_EM_STREAMIN_esCallback; 5930 5931 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SFF_SELECTION | SF_RTF, (LPARAM)&es); 5932 ok(result == 13, "got %ld, expected 13\n", result); 5933 5934 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5935 ok (result == 14, 5936 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result); 5937 result = strcmp (buffer,"TestSomeText\r\n"); 5938 ok (result == 0, 5939 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer); 5940 ok(es.dwError == 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es.dwError, 0); 5941 5942 es.dwCookie = (DWORD_PTR)&streamText1; 5943 es.dwError = 0; 5944 es.pfnCallback = test_EM_STREAMIN_esCallback; 5945 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5946 ok(result == 12, "got %ld, expected %d\n", result, 12); 5947 5948 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5949 ok (result == 12, 5950 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result); 5951 result = strcmp (buffer,"TestSomeText"); 5952 ok (result == 0, 5953 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); 5954 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0); 5955 5956 es.dwCookie = (DWORD_PTR)&streamText2; 5957 es.dwError = 0; 5958 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5959 ok(result == 0, "got %ld, expected %d\n", result, 0); 5960 5961 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5962 ok (result == 0, 5963 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result); 5964 ok(!buffer[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 5965 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16); 5966 5967 es.dwCookie = (DWORD_PTR)&streamText3; 5968 es.dwError = 0; 5969 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 5970 ok(result == 0, "got %ld, expected %d\n", result, 0); 5971 5972 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5973 ok (result == 0, 5974 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result); 5975 ok(!buffer[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer); 5976 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16); 5977 5978 es.dwCookie = (DWORD_PTR)&streamTextUTF8BOM; 5979 es.dwError = 0; 5980 es.pfnCallback = test_EM_STREAMIN_esCallback; 5981 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 5982 ok(result == 18, "got %ld, expected %d\n", result, 18); 5983 5984 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 5985 ok(result == 15, 5986 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result); 5987 result = strcmp (buffer,"TestUTF8WithBOM"); 5988 ok(result == 0, 5989 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer); 5990 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es.dwError, 0); 5991 5992 phase = 0; 5993 es.dwCookie = (DWORD_PTR)&phase; 5994 es.dwError = 0; 5995 es.pfnCallback = test_EM_STREAMIN_esCallback_UTF8Split; 5996 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 5997 ok(result == 8, "got %ld\n", result); 5998 5999 WideCharToMultiByte(CP_ACP, 0, UTF8Split_exp, -1, tmp, sizeof(tmp), NULL, NULL); 6000 6001 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6002 ok(result == 3, 6003 "EM_STREAMIN: Test UTF8Split returned %ld\n", result); 6004 result = memcmp (buffer, tmp, 3); 6005 ok(result == 0, 6006 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer); 6007 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es.dwError, 0); 6008 6009 es.dwCookie = (DWORD_PTR)&cookieForStream4; 6010 es.dwError = 0; 6011 es.pfnCallback = test_EM_STREAMIN_esCallback2; 6012 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6013 ok(result == length4, "got %ld, expected %d\n", result, length4); 6014 6015 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6016 ok (result == length4, 6017 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result, length4); 6018 ok(es.dwError == 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es.dwError, 0); 6019 6020 es.dwCookie = (DWORD_PTR)&cookieForStream5; 6021 es.dwError = 0; 6022 es.pfnCallback = test_EM_STREAMIN_esCallback2; 6023 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM)&es); 6024 ok(result == sizeof(streamText5), "got %ld, expected %u\n", result, (UINT)sizeof(streamText5)); 6025 6026 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6027 ok (result == length5, 6028 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result, length5); 6029 ok(es.dwError == 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es.dwError, 0); 6030 6031 DestroyWindow(hwndRichEdit); 6032 6033 /* Single-line richedit */ 6034 hwndRichEdit = new_richedit_with_style(NULL, 0); 6035 ptr = "line1\r\nline2"; 6036 es.dwCookie = (DWORD_PTR)&ptr; 6037 es.dwError = 0; 6038 es.pfnCallback = test_EM_STREAMIN_esCallback; 6039 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6040 ok(result == 12, "got %ld, expected %d\n", result, 12); 6041 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6042 ok (!strcmp(buffer, "line1"), 6043 "EM_STREAMIN: Unexpected text '%s'\n", buffer); 6044 } 6045 6046 static void test_EM_StreamIn_Undo(void) 6047 { 6048 /* The purpose of this test is to determine when a EM_StreamIn should be 6049 * undoable. This is important because WM_PASTE currently uses StreamIn and 6050 * pasting should always be undoable but streaming isn't always. 6051 * 6052 * cases to test: 6053 * StreamIn plain text without SFF_SELECTION. 6054 * StreamIn plain text with SFF_SELECTION set but a zero-length selection 6055 * StreamIn plain text with SFF_SELECTION and a valid, normal selection 6056 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to) 6057 * Feel free to add tests for other text modes or StreamIn things. 6058 */ 6059 6060 6061 HWND hwndRichEdit = new_richedit(NULL); 6062 LRESULT result; 6063 EDITSTREAM es; 6064 char buffer[1024] = {0}; 6065 const char randomtext[] = "Some text"; 6066 6067 es.pfnCallback = EditStreamCallback; 6068 6069 /* StreamIn, no SFF_SELECTION */ 6070 es.dwCookie = nCallbackCount; 6071 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6072 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6073 SendMessageA(hwndRichEdit, EM_SETSEL,0,0); 6074 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es); 6075 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6076 result = strcmp (buffer,"test"); 6077 ok (result == 0, 6078 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); 6079 6080 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6081 ok (result == FALSE, 6082 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n"); 6083 6084 /* StreamIn, SFF_SELECTION, but nothing selected */ 6085 es.dwCookie = nCallbackCount; 6086 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6087 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6088 SendMessageA(hwndRichEdit, EM_SETSEL,0,0); 6089 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es); 6090 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6091 result = strcmp (buffer,"testSome text"); 6092 ok (result == 0, 6093 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 6094 6095 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6096 ok (result == TRUE, 6097 "EM_STREAMIN with SFF_SELECTION but no selection set " 6098 "should create an undo\n"); 6099 6100 /* StreamIn, SFF_SELECTION, with a selection */ 6101 es.dwCookie = nCallbackCount; 6102 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 6103 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext); 6104 SendMessageA(hwndRichEdit, EM_SETSEL,4,5); 6105 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es); 6106 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); 6107 result = strcmp (buffer,"Sometesttext"); 6108 ok (result == 0, 6109 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); 6110 6111 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0); 6112 ok (result == TRUE, 6113 "EM_STREAMIN with SFF_SELECTION and selection set " 6114 "should create an undo\n"); 6115 6116 DestroyWindow(hwndRichEdit); 6117 } 6118 6119 static BOOL is_em_settextex_supported(HWND hwnd) 6120 { 6121 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; 6122 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0; 6123 } 6124 6125 static void test_unicode_conversions(void) 6126 { 6127 static const WCHAR tW[] = {'t',0}; 6128 static const WCHAR teW[] = {'t','e',0}; 6129 static const WCHAR textW[] = {'t','e','s','t',0}; 6130 static const char textA[] = "test"; 6131 char bufA[64]; 6132 WCHAR bufW[64]; 6133 HWND hwnd; 6134 int em_settextex_supported, ret; 6135 6136 #define set_textA(hwnd, wm_set_text, txt) \ 6137 do { \ 6138 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \ 6139 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ 6140 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ 6141 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \ 6142 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \ 6143 } while(0) 6144 #define expect_textA(hwnd, wm_get_text, txt) \ 6145 do { \ 6146 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ 6147 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6148 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6149 memset(bufA, 0xAA, sizeof(bufA)); \ 6150 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ 6151 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \ 6152 ret = lstrcmpA(bufA, txt); \ 6153 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \ 6154 } while(0) 6155 6156 #define set_textW(hwnd, wm_set_text, txt) \ 6157 do { \ 6158 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \ 6159 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ 6160 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ 6161 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \ 6162 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \ 6163 } while(0) 6164 #define expect_textW(hwnd, wm_get_text, txt) \ 6165 do { \ 6166 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \ 6167 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6168 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6169 memset(bufW, 0xAA, sizeof(bufW)); \ 6170 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \ 6171 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \ 6172 ret = lstrcmpW(bufW, txt); \ 6173 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \ 6174 } while(0) 6175 #define expect_empty(hwnd, wm_get_text) \ 6176 do { \ 6177 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ 6178 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ 6179 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ 6180 memset(bufA, 0xAA, sizeof(bufA)); \ 6181 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ 6182 ok(!ret, "empty richedit should return 0, got %d\n", ret); \ 6183 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \ 6184 } while(0) 6185 6186 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6187 0, 0, 200, 60, 0, 0, 0, 0); 6188 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6189 6190 ret = IsWindowUnicode(hwnd); 6191 ok(ret, "RichEdit20W should be unicode under NT\n"); 6192 6193 /* EM_SETTEXTEX is supported starting from version 3.0 */ 6194 em_settextex_supported = is_em_settextex_supported(hwnd); 6195 trace("EM_SETTEXTEX is %ssupported on this platform\n", 6196 em_settextex_supported ? "" : "NOT "); 6197 6198 expect_empty(hwnd, WM_GETTEXT); 6199 expect_empty(hwnd, EM_GETTEXTEX); 6200 6201 ret = SendMessageA(hwnd, WM_CHAR, textW[0], 0); 6202 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); 6203 expect_textA(hwnd, WM_GETTEXT, "t"); 6204 expect_textA(hwnd, EM_GETTEXTEX, "t"); 6205 expect_textW(hwnd, EM_GETTEXTEX, tW); 6206 6207 ret = SendMessageA(hwnd, WM_CHAR, textA[1], 0); 6208 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); 6209 expect_textA(hwnd, WM_GETTEXT, "te"); 6210 expect_textA(hwnd, EM_GETTEXTEX, "te"); 6211 expect_textW(hwnd, EM_GETTEXTEX, teW); 6212 6213 set_textA(hwnd, WM_SETTEXT, NULL); 6214 expect_empty(hwnd, WM_GETTEXT); 6215 expect_empty(hwnd, EM_GETTEXTEX); 6216 6217 set_textA(hwnd, WM_SETTEXT, textA); 6218 expect_textA(hwnd, WM_GETTEXT, textA); 6219 expect_textA(hwnd, EM_GETTEXTEX, textA); 6220 expect_textW(hwnd, EM_GETTEXTEX, textW); 6221 6222 if (em_settextex_supported) 6223 { 6224 set_textA(hwnd, EM_SETTEXTEX, textA); 6225 expect_textA(hwnd, WM_GETTEXT, textA); 6226 expect_textA(hwnd, EM_GETTEXTEX, textA); 6227 expect_textW(hwnd, EM_GETTEXTEX, textW); 6228 } 6229 6230 set_textW(hwnd, WM_SETTEXT, textW); 6231 expect_textW(hwnd, WM_GETTEXT, textW); 6232 expect_textA(hwnd, WM_GETTEXT, textA); 6233 expect_textW(hwnd, EM_GETTEXTEX, textW); 6234 expect_textA(hwnd, EM_GETTEXTEX, textA); 6235 6236 if (em_settextex_supported) 6237 { 6238 set_textW(hwnd, EM_SETTEXTEX, textW); 6239 expect_textW(hwnd, WM_GETTEXT, textW); 6240 expect_textA(hwnd, WM_GETTEXT, textA); 6241 expect_textW(hwnd, EM_GETTEXTEX, textW); 6242 expect_textA(hwnd, EM_GETTEXTEX, textA); 6243 } 6244 DestroyWindow(hwnd); 6245 6246 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP, 6247 0, 0, 200, 60, 0, 0, 0, 0); 6248 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6249 6250 ret = IsWindowUnicode(hwnd); 6251 ok(!ret, "RichEdit20A should NOT be unicode\n"); 6252 6253 set_textA(hwnd, WM_SETTEXT, textA); 6254 expect_textA(hwnd, WM_GETTEXT, textA); 6255 expect_textA(hwnd, EM_GETTEXTEX, textA); 6256 expect_textW(hwnd, EM_GETTEXTEX, textW); 6257 6258 if (em_settextex_supported) 6259 { 6260 set_textA(hwnd, EM_SETTEXTEX, textA); 6261 expect_textA(hwnd, WM_GETTEXT, textA); 6262 expect_textA(hwnd, EM_GETTEXTEX, textA); 6263 expect_textW(hwnd, EM_GETTEXTEX, textW); 6264 } 6265 6266 set_textW(hwnd, WM_SETTEXT, textW); 6267 expect_textW(hwnd, WM_GETTEXT, textW); 6268 expect_textA(hwnd, WM_GETTEXT, textA); 6269 expect_textW(hwnd, EM_GETTEXTEX, textW); 6270 expect_textA(hwnd, EM_GETTEXTEX, textA); 6271 6272 if (em_settextex_supported) 6273 { 6274 set_textW(hwnd, EM_SETTEXTEX, textW); 6275 expect_textW(hwnd, WM_GETTEXT, textW); 6276 expect_textA(hwnd, WM_GETTEXT, textA); 6277 expect_textW(hwnd, EM_GETTEXTEX, textW); 6278 expect_textA(hwnd, EM_GETTEXTEX, textA); 6279 } 6280 DestroyWindow(hwnd); 6281 } 6282 6283 static void test_WM_CHAR(void) 6284 { 6285 HWND hwnd; 6286 int ret; 6287 const char * char_list = "abc\rabc\r"; 6288 const char * expected_content_single = "abcabc"; 6289 const char * expected_content_multi = "abc\r\nabc\r\n"; 6290 char buffer[64] = {0}; 6291 const char * p; 6292 6293 /* single-line control must IGNORE carriage returns */ 6294 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6295 0, 0, 200, 60, 0, 0, 0, 0); 6296 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6297 6298 p = char_list; 6299 while (*p != '\0') { 6300 SendMessageA(hwnd, WM_KEYDOWN, *p, 1); 6301 ret = SendMessageA(hwnd, WM_CHAR, *p, 1); 6302 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret); 6303 SendMessageA(hwnd, WM_KEYUP, *p, 1); 6304 p++; 6305 } 6306 6307 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6308 ret = strcmp(buffer, expected_content_single); 6309 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6310 6311 DestroyWindow(hwnd); 6312 6313 /* multi-line control inserts CR normally */ 6314 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE, 6315 0, 0, 200, 60, 0, 0, 0, 0); 6316 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6317 6318 p = char_list; 6319 while (*p != '\0') { 6320 SendMessageA(hwnd, WM_KEYDOWN, *p, 1); 6321 ret = SendMessageA(hwnd, WM_CHAR, *p, 1); 6322 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret); 6323 SendMessageA(hwnd, WM_KEYUP, *p, 1); 6324 p++; 6325 } 6326 6327 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6328 ret = strcmp(buffer, expected_content_multi); 6329 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6330 6331 DestroyWindow(hwnd); 6332 } 6333 6334 static void test_EM_GETTEXTLENGTHEX(void) 6335 { 6336 HWND hwnd; 6337 GETTEXTLENGTHEX gtl; 6338 int ret; 6339 const char * base_string = "base string"; 6340 const char * test_string = "a\nb\n\n\r\n"; 6341 const char * test_string_after = "a"; 6342 const char * test_string_2 = "a\rtest\rstring"; 6343 char buffer[64] = {0}; 6344 6345 /* single line */ 6346 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 6347 0, 0, 200, 60, 0, 0, 0, 0); 6348 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6349 6350 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6351 gtl.codepage = CP_ACP; 6352 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6353 ok(ret == 0, "ret %d\n",ret); 6354 6355 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6356 gtl.codepage = CP_ACP; 6357 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6358 ok(ret == 0, "ret %d\n",ret); 6359 6360 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string); 6361 6362 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6363 gtl.codepage = CP_ACP; 6364 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6365 ok(ret == strlen(base_string), "ret %d\n",ret); 6366 6367 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6368 gtl.codepage = CP_ACP; 6369 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6370 ok(ret == strlen(base_string), "ret %d\n",ret); 6371 6372 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string); 6373 6374 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6375 gtl.codepage = CP_ACP; 6376 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6377 ok(ret == 1, "ret %d\n",ret); 6378 6379 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6380 gtl.codepage = CP_ACP; 6381 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6382 ok(ret == 1, "ret %d\n",ret); 6383 6384 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6385 ret = strcmp(buffer, test_string_after); 6386 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n"); 6387 6388 DestroyWindow(hwnd); 6389 6390 /* multi line */ 6391 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE, 6392 0, 0, 200, 60, 0, 0, 0, 0); 6393 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6394 6395 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6396 gtl.codepage = CP_ACP; 6397 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6398 ok(ret == 0, "ret %d\n",ret); 6399 6400 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6401 gtl.codepage = CP_ACP; 6402 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6403 ok(ret == 0, "ret %d\n",ret); 6404 6405 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string); 6406 6407 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6408 gtl.codepage = CP_ACP; 6409 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6410 ok(ret == strlen(base_string), "ret %d\n",ret); 6411 6412 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6413 gtl.codepage = CP_ACP; 6414 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6415 ok(ret == strlen(base_string), "ret %d\n",ret); 6416 6417 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2); 6418 6419 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6420 gtl.codepage = CP_ACP; 6421 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6422 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret); 6423 6424 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6425 gtl.codepage = CP_ACP; 6426 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6427 ok(ret == strlen(test_string_2), "ret %d\n",ret); 6428 6429 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string); 6430 6431 gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; 6432 gtl.codepage = CP_ACP; 6433 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6434 ok(ret == 10, "ret %d\n",ret); 6435 6436 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6437 gtl.codepage = CP_ACP; 6438 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6439 ok(ret == 6, "ret %d\n",ret); 6440 6441 /* Unicode/NUMCHARS/NUMBYTES */ 6442 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2); 6443 6444 gtl.flags = GTL_DEFAULT; 6445 gtl.codepage = 1200; 6446 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6447 ok(ret == lstrlenA(test_string_2), 6448 "GTL_DEFAULT gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6449 6450 gtl.flags = GTL_NUMCHARS; 6451 gtl.codepage = 1200; 6452 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6453 ok(ret == lstrlenA(test_string_2), 6454 "GTL_NUMCHARS gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6455 6456 gtl.flags = GTL_NUMBYTES; 6457 gtl.codepage = 1200; 6458 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6459 ok(ret == lstrlenA(test_string_2)*2, 6460 "GTL_NUMBYTES gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2); 6461 6462 gtl.flags = GTL_PRECISE; 6463 gtl.codepage = 1200; 6464 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6465 ok(ret == lstrlenA(test_string_2)*2, 6466 "GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2); 6467 6468 gtl.flags = GTL_NUMCHARS | GTL_PRECISE; 6469 gtl.codepage = 1200; 6470 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6471 ok(ret == lstrlenA(test_string_2), 6472 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)); 6473 6474 gtl.flags = GTL_NUMCHARS | GTL_NUMBYTES; 6475 gtl.codepage = 1200; 6476 ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); 6477 ok(ret == E_INVALIDARG, 6478 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret, E_INVALIDARG); 6479 6480 DestroyWindow(hwnd); 6481 } 6482 6483 6484 /* globals that parent and child access when checking event masks & notifications */ 6485 static HWND eventMaskEditHwnd = 0; 6486 static int queriedEventMask; 6487 static int watchForEventMask = 0; 6488 6489 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */ 6490 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6491 { 6492 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16))) 6493 { 6494 queriedEventMask = SendMessageA(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0); 6495 } 6496 return DefWindowProcA(hwnd, message, wParam, lParam); 6497 } 6498 6499 /* test event masks in combination with WM_COMMAND */ 6500 static void test_eventMask(void) 6501 { 6502 HWND parent; 6503 int ret, style; 6504 WNDCLASSA cls; 6505 const char text[] = "foo bar\n"; 6506 int eventMask; 6507 6508 /* register class to capture WM_COMMAND */ 6509 cls.style = 0; 6510 cls.lpfnWndProc = ParentMsgCheckProcA; 6511 cls.cbClsExtra = 0; 6512 cls.cbWndExtra = 0; 6513 cls.hInstance = GetModuleHandleA(0); 6514 cls.hIcon = 0; 6515 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6516 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6517 cls.lpszMenuName = NULL; 6518 cls.lpszClassName = "EventMaskParentClass"; 6519 if(!RegisterClassA(&cls)) assert(0); 6520 6521 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6522 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6523 ok (parent != 0, "Failed to create parent window\n"); 6524 6525 eventMaskEditHwnd = new_richedit(parent); 6526 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n"); 6527 6528 eventMask = ENM_CHANGE | ENM_UPDATE; 6529 ret = SendMessageA(eventMaskEditHwnd, EM_SETEVENTMASK, 0, eventMask); 6530 ok(ret == ENM_NONE, "wrong event mask\n"); 6531 ret = SendMessageA(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0); 6532 ok(ret == eventMask, "failed to set event mask\n"); 6533 6534 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */ 6535 queriedEventMask = 0; /* initialize to something other than we expect */ 6536 watchForEventMask = EN_CHANGE; 6537 ret = SendMessageA(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM)text); 6538 ok(ret == TRUE, "failed to set text\n"); 6539 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE 6540 notification in response to WM_SETTEXT */ 6541 ok(queriedEventMask == (eventMask & ~ENM_CHANGE), 6542 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6543 6544 /* check to see if EN_CHANGE is sent when redraw is turned off */ 6545 SendMessageA(eventMaskEditHwnd, WM_CLEAR, 0, 0); 6546 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6547 SendMessageA(eventMaskEditHwnd, WM_SETREDRAW, FALSE, 0); 6548 /* redraw is disabled by making the window invisible. */ 6549 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); 6550 queriedEventMask = 0; /* initialize to something other than we expect */ 6551 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6552 ok(queriedEventMask == (eventMask & ~ENM_CHANGE), 6553 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6554 SendMessageA(eventMaskEditHwnd, WM_SETREDRAW, TRUE, 0); 6555 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6556 6557 /* check to see if EN_UPDATE is sent when the editor isn't visible */ 6558 SendMessageA(eventMaskEditHwnd, WM_CLEAR, 0, 0); 6559 style = GetWindowLongA(eventMaskEditHwnd, GWL_STYLE); 6560 SetWindowLongA(eventMaskEditHwnd, GWL_STYLE, style & ~WS_VISIBLE); 6561 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); 6562 watchForEventMask = EN_UPDATE; 6563 queriedEventMask = 0; /* initialize to something other than we expect */ 6564 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6565 ok(queriedEventMask == 0, 6566 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6567 SetWindowLongA(eventMaskEditHwnd, GWL_STYLE, style); 6568 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); 6569 queriedEventMask = 0; /* initialize to something other than we expect */ 6570 SendMessageA(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM)text); 6571 ok(queriedEventMask == eventMask, 6572 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); 6573 6574 6575 DestroyWindow(parent); 6576 } 6577 6578 static int received_WM_NOTIFY = 0; 6579 static int modify_at_WM_NOTIFY = 0; 6580 static BOOL filter_on_WM_NOTIFY = FALSE; 6581 static HWND hwndRichedit_WM_NOTIFY; 6582 6583 static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6584 { 6585 if(message == WM_NOTIFY) 6586 { 6587 received_WM_NOTIFY = 1; 6588 modify_at_WM_NOTIFY = SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETMODIFY, 0, 0); 6589 if (filter_on_WM_NOTIFY) return TRUE; 6590 } 6591 return DefWindowProcA(hwnd, message, wParam, lParam); 6592 } 6593 6594 static void test_WM_NOTIFY(void) 6595 { 6596 HWND parent; 6597 WNDCLASSA cls; 6598 CHARFORMAT2A cf2; 6599 int sel_start, sel_end; 6600 6601 /* register class to capture WM_NOTIFY */ 6602 cls.style = 0; 6603 cls.lpfnWndProc = WM_NOTIFY_ParentMsgCheckProcA; 6604 cls.cbClsExtra = 0; 6605 cls.cbWndExtra = 0; 6606 cls.hInstance = GetModuleHandleA(0); 6607 cls.hIcon = 0; 6608 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6609 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6610 cls.lpszMenuName = NULL; 6611 cls.lpszClassName = "WM_NOTIFY_ParentClass"; 6612 if(!RegisterClassA(&cls)) assert(0); 6613 6614 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6615 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6616 ok (parent != 0, "Failed to create parent window\n"); 6617 6618 hwndRichedit_WM_NOTIFY = new_richedit(parent); 6619 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n"); 6620 6621 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_SELCHANGE); 6622 6623 /* Notifications for selection change should only be sent when selection 6624 actually changes. EM_SETCHARFORMAT is one message that calls 6625 ME_CommitUndo, which should check whether message should be sent */ 6626 received_WM_NOTIFY = 0; 6627 cf2.cbSize = sizeof(CHARFORMAT2A); 6628 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2); 6629 cf2.dwMask = CFM_ITALIC | cf2.dwMask; 6630 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; 6631 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 6632 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); 6633 6634 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is 6635 already at 0. */ 6636 received_WM_NOTIFY = 0; 6637 modify_at_WM_NOTIFY = 0; 6638 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); 6639 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); 6640 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); 6641 6642 received_WM_NOTIFY = 0; 6643 modify_at_WM_NOTIFY = 0; 6644 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 4, 4); 6645 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6646 6647 received_WM_NOTIFY = 0; 6648 modify_at_WM_NOTIFY = 0; 6649 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); 6650 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6651 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); 6652 6653 /* Test for WM_NOTIFY messages with redraw disabled. */ 6654 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 0, 0); 6655 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, FALSE, 0); 6656 received_WM_NOTIFY = 0; 6657 SendMessageA(hwndRichedit_WM_NOTIFY, EM_REPLACESEL, FALSE, (LPARAM)"inserted"); 6658 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); 6659 SendMessageA(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, TRUE, 0); 6660 6661 /* Test filtering key events. */ 6662 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETSEL, 0, 0); 6663 SendMessageA(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_KEYEVENTS); 6664 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6665 received_WM_NOTIFY = 0; 6666 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6667 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6668 ok(sel_start == 1 && sel_end == 1, 6669 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6670 filter_on_WM_NOTIFY = TRUE; 6671 received_WM_NOTIFY = 0; 6672 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6673 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6674 ok(sel_start == 1 && sel_end == 1, 6675 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6676 6677 /* test with owner set to NULL */ 6678 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY, GWLP_HWNDPARENT, 0); 6679 SendMessageA(hwndRichedit_WM_NOTIFY, WM_KEYDOWN, VK_RIGHT, 0); 6680 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 6681 ok(sel_start == 1 && sel_end == 1, 6682 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end); 6683 6684 DestroyWindow(hwndRichedit_WM_NOTIFY); 6685 DestroyWindow(parent); 6686 } 6687 6688 static ENLINK enlink; 6689 #define CURSOR_CLIENT_X 5 6690 #define CURSOR_CLIENT_Y 5 6691 #define WP_PARENT 1 6692 #define WP_CHILD 2 6693 6694 static LRESULT WINAPI EN_LINK_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 6695 { 6696 if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == EN_LINK) 6697 { 6698 enlink = *(ENLINK*)lParam; 6699 } 6700 return DefWindowProcA(hwnd, message, wParam, lParam); 6701 } 6702 6703 static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent, 6704 UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies) 6705 { 6706 ENLINK junk_enlink; 6707 6708 switch (msg) 6709 { 6710 case WM_LBUTTONDBLCLK: 6711 case WM_LBUTTONDOWN: 6712 case WM_LBUTTONUP: 6713 case WM_MOUSEHOVER: 6714 case WM_MOUSEMOVE: 6715 case WM_MOUSEWHEEL: 6716 case WM_RBUTTONDBLCLK: 6717 case WM_RBUTTONDOWN: 6718 case WM_RBUTTONUP: 6719 lParam = MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y); 6720 break; 6721 case WM_SETCURSOR: 6722 if (wParam == WP_PARENT) 6723 wParam = (WPARAM)parent; 6724 else if (wParam == WP_CHILD) 6725 wParam = (WPARAM)hwnd; 6726 break; 6727 } 6728 6729 memset(&junk_enlink, 0x23, sizeof(junk_enlink)); 6730 enlink = junk_enlink; 6731 6732 SendMessageA(hwnd, msg, wParam, lParam); 6733 6734 if (notifies) 6735 { 6736 ok(enlink.nmhdr.hwndFrom == hwnd, 6737 "%s test %i: Expected hwnd %p got %p\n", desc, i, hwnd, enlink.nmhdr.hwndFrom); 6738 ok(enlink.nmhdr.idFrom == 0, 6739 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc, i, enlink.nmhdr.idFrom); 6740 ok(enlink.msg == msg, 6741 "%s test %i: Expected msg 0x%x got 0x%x\n", desc, i, msg, enlink.msg); 6742 if (msg == WM_SETCURSOR) 6743 { 6744 ok(enlink.wParam == 0, 6745 "%s test %i: Expected wParam 0 got 0x%lx\n", desc, i, enlink.wParam); 6746 } 6747 else 6748 { 6749 ok(enlink.wParam == wParam, 6750 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc, i, wParam, enlink.wParam); 6751 } 6752 ok(enlink.lParam == MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y), 6753 "%s test %i: Expected lParam 0x%lx got 0x%lx\n", 6754 desc, i, MAKELPARAM(CURSOR_CLIENT_X, CURSOR_CLIENT_Y), enlink.lParam); 6755 ok(enlink.chrg.cpMin == 0 && enlink.chrg.cpMax == 31, 6756 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc, i, enlink.chrg.cpMin, enlink.chrg.cpMax); 6757 } 6758 else 6759 { 6760 ok(memcmp(&enlink, &junk_enlink, sizeof(enlink)) == 0, 6761 "%s test %i: Expected enlink to remain unmodified\n", desc, i); 6762 } 6763 } 6764 6765 static void test_EN_LINK(void) 6766 { 6767 HWND hwnd, parent; 6768 WNDCLASSA cls; 6769 CHARFORMAT2A cf2; 6770 POINT orig_cursor_pos; 6771 POINT cursor_screen_pos = {CURSOR_CLIENT_X, CURSOR_CLIENT_Y}; 6772 int i; 6773 6774 static const struct 6775 { 6776 UINT msg; 6777 WPARAM wParam; 6778 LPARAM lParam; 6779 BOOL notifies; 6780 } 6781 link_notify_tests[] = 6782 { 6783 /* hold down the left button and try some messages */ 6784 { WM_LBUTTONDOWN, 0, 0, TRUE }, /* 0 */ 6785 { EM_LINESCROLL, 0, 1, FALSE }, 6786 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6787 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6788 { WM_MOUSEHOVER, 0, 0, FALSE }, 6789 { WM_MOUSEMOVE, 0, 0, FALSE }, 6790 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6791 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6792 { WM_RBUTTONDOWN, 0, 0, TRUE }, 6793 { WM_RBUTTONUP, 0, 0, TRUE }, 6794 { WM_SETCURSOR, 0, 0, FALSE }, 6795 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6796 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6797 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6798 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }, 6799 { WM_LBUTTONUP, 0, 0, TRUE }, 6800 /* hold down the right button and try some messages */ 6801 { WM_RBUTTONDOWN, 0, 0, TRUE }, /* 16 */ 6802 { EM_LINESCROLL, 0, 1, FALSE }, 6803 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6804 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6805 { WM_LBUTTONDOWN, 0, 0, TRUE }, 6806 { WM_LBUTTONUP, 0, 0, TRUE }, 6807 { WM_MOUSEHOVER, 0, 0, FALSE }, 6808 { WM_MOUSEMOVE, 0, 0, TRUE }, 6809 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6810 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6811 { WM_SETCURSOR, 0, 0, FALSE }, 6812 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6813 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6814 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6815 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }, 6816 { WM_RBUTTONUP, 0, 0, TRUE }, 6817 /* try the messages with both buttons released */ 6818 { EM_LINESCROLL, 0, 1, FALSE }, /* 32 */ 6819 { EM_SCROLL, SB_BOTTOM, 0, FALSE }, 6820 { WM_LBUTTONDBLCLK, 0, 0, TRUE }, 6821 { WM_LBUTTONDOWN, 0, 0, TRUE }, 6822 { WM_LBUTTONUP, 0, 0, TRUE }, 6823 { WM_MOUSEHOVER, 0, 0, FALSE }, 6824 { WM_MOUSEMOVE, 0, 0, TRUE }, 6825 { WM_MOUSEWHEEL, 0, 0, FALSE }, 6826 { WM_RBUTTONDBLCLK, 0, 0, TRUE }, 6827 { WM_RBUTTONDOWN, 0, 0, TRUE }, 6828 { WM_RBUTTONUP, 0, 0, TRUE }, 6829 { WM_SETCURSOR, 0, 0, FALSE }, 6830 { WM_SETCURSOR, WP_CHILD, 0, TRUE }, 6831 { WM_SETCURSOR, WP_CHILD, 1, TRUE }, 6832 { WM_SETCURSOR, WP_PARENT, 0, FALSE }, 6833 { WM_VSCROLL, SB_BOTTOM, 0, FALSE } 6834 }; 6835 6836 /* register class to capture WM_NOTIFY */ 6837 cls.style = 0; 6838 cls.lpfnWndProc = EN_LINK_ParentMsgCheckProcA; 6839 cls.cbClsExtra = 0; 6840 cls.cbWndExtra = 0; 6841 cls.hInstance = GetModuleHandleA(0); 6842 cls.hIcon = 0; 6843 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 6844 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 6845 cls.lpszMenuName = NULL; 6846 cls.lpszClassName = "EN_LINK_ParentClass"; 6847 if(!RegisterClassA(&cls)) assert(0); 6848 6849 parent = CreateWindowA(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, 6850 0, 0, 200, 60, NULL, NULL, NULL, NULL); 6851 ok(parent != 0, "Failed to create parent window\n"); 6852 6853 hwnd = new_richedit(parent); 6854 ok(hwnd != 0, "Failed to create edit window\n"); 6855 6856 SendMessageA(hwnd, EM_SETEVENTMASK, 0, ENM_LINK); 6857 6858 cf2.cbSize = sizeof(CHARFORMAT2A); 6859 cf2.dwMask = CFM_LINK; 6860 cf2.dwEffects = CFE_LINK; 6861 SendMessageA(hwnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); 6862 /* mixing letters and numbers causes runs to be split */ 6863 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"link text with at least 2 runs"); 6864 6865 GetCursorPos(&orig_cursor_pos); 6866 SetCursorPos(0, 0); 6867 6868 for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) 6869 { 6870 link_notify_test("cursor position simulated", i, hwnd, parent, 6871 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, 6872 link_notify_tests[i].msg == WM_SETCURSOR ? FALSE : link_notify_tests[i].notifies); 6873 } 6874 6875 ClientToScreen(hwnd, &cursor_screen_pos); 6876 SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y); 6877 6878 for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) 6879 { 6880 link_notify_test("cursor position set", i, hwnd, parent, 6881 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, 6882 link_notify_tests[i].notifies); 6883 } 6884 6885 SetCursorPos(orig_cursor_pos.x, orig_cursor_pos.y); 6886 DestroyWindow(hwnd); 6887 DestroyWindow(parent); 6888 } 6889 6890 static void test_undo_coalescing(void) 6891 { 6892 HWND hwnd; 6893 int result; 6894 char buffer[64] = {0}; 6895 6896 /* multi-line control inserts CR normally */ 6897 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE, 6898 0, 0, 200, 60, 0, 0, 0, 0); 6899 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); 6900 6901 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6902 ok (result == FALSE, "Can undo after window creation.\n"); 6903 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6904 ok (result == FALSE, "Undo operation successful with nothing to undo.\n"); 6905 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6906 ok (result == FALSE, "Can redo after window creation.\n"); 6907 result = SendMessageA(hwnd, EM_REDO, 0, 0); 6908 ok (result == FALSE, "Redo operation successful with nothing undone.\n"); 6909 6910 /* Test the effect of arrows keys during typing on undo transactions*/ 6911 simulate_typing_characters(hwnd, "one two three"); 6912 SendMessageA(hwnd, WM_KEYDOWN, VK_RIGHT, 1); 6913 SendMessageA(hwnd, WM_KEYUP, VK_RIGHT, 1); 6914 simulate_typing_characters(hwnd, " four five six"); 6915 6916 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6917 ok (result == FALSE, "Can redo before anything is undone.\n"); 6918 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6919 ok (result == TRUE, "Cannot undo typed characters.\n"); 6920 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6921 ok (result == TRUE, "EM_UNDO Failed to undo typed characters.\n"); 6922 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6923 ok (result == TRUE, "Cannot redo after undo.\n"); 6924 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6925 result = strcmp(buffer, "one two three"); 6926 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 6927 6928 result = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 6929 ok (result == TRUE, "Cannot undo typed characters.\n"); 6930 result = SendMessageA(hwnd, WM_UNDO, 0, 0); 6931 ok (result == TRUE, "Failed to undo typed characters.\n"); 6932 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6933 result = strcmp(buffer, ""); 6934 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 6935 6936 /* Test the effect of focus changes during typing on undo transactions*/ 6937 simulate_typing_characters(hwnd, "one two three"); 6938 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6939 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n"); 6940 SendMessageA(hwnd, WM_KILLFOCUS, 0, 0); 6941 SendMessageA(hwnd, WM_SETFOCUS, 0, 0); 6942 simulate_typing_characters(hwnd, " four five six"); 6943 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6944 ok (result == TRUE, "Failed to undo typed characters.\n"); 6945 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6946 result = strcmp(buffer, "one two three"); 6947 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 6948 6949 /* Test the effect of the back key during typing on undo transactions */ 6950 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6951 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 6952 ok (result == TRUE, "Failed to clear the text.\n"); 6953 simulate_typing_characters(hwnd, "one two threa"); 6954 result = SendMessageA(hwnd, EM_CANREDO, 0, 0); 6955 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n"); 6956 SendMessageA(hwnd, WM_KEYDOWN, VK_BACK, 1); 6957 SendMessageA(hwnd, WM_KEYUP, VK_BACK, 1); 6958 simulate_typing_characters(hwnd, "e four five six"); 6959 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6960 ok (result == TRUE, "Failed to undo typed characters.\n"); 6961 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6962 result = strcmp(buffer, ""); 6963 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 6964 6965 /* Test the effect of the delete key during typing on undo transactions */ 6966 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6967 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"abcd"); 6968 ok(result == TRUE, "Failed to set the text.\n"); 6969 SendMessageA(hwnd, EM_SETSEL, 1, 1); 6970 SendMessageA(hwnd, WM_KEYDOWN, VK_DELETE, 1); 6971 SendMessageA(hwnd, WM_KEYUP, VK_DELETE, 1); 6972 SendMessageA(hwnd, WM_KEYDOWN, VK_DELETE, 1); 6973 SendMessageA(hwnd, WM_KEYUP, VK_DELETE, 1); 6974 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6975 ok (result == TRUE, "Failed to undo typed characters.\n"); 6976 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6977 result = strcmp(buffer, "acd"); 6978 ok (result == 0, "expected '%s' but got '%s'\n", "acd", buffer); 6979 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6980 ok (result == TRUE, "Failed to undo typed characters.\n"); 6981 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6982 result = strcmp(buffer, "abcd"); 6983 ok (result == 0, "expected '%s' but got '%s'\n", "abcd", buffer); 6984 6985 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/ 6986 SendMessageA(hwnd, EM_EMPTYUNDOBUFFER, 0, 0); 6987 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)""); 6988 ok (result == TRUE, "Failed to clear the text.\n"); 6989 simulate_typing_characters(hwnd, "one two three"); 6990 result = SendMessageA(hwnd, EM_STOPGROUPTYPING, 0, 0); 6991 ok (result == 0, "expected %d but got %d\n", 0, result); 6992 simulate_typing_characters(hwnd, " four five six"); 6993 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6994 ok (result == TRUE, "Failed to undo typed characters.\n"); 6995 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 6996 result = strcmp(buffer, "one two three"); 6997 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer); 6998 result = SendMessageA(hwnd, EM_UNDO, 0, 0); 6999 ok (result == TRUE, "Failed to undo typed characters.\n"); 7000 SendMessageA(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 7001 result = strcmp(buffer, ""); 7002 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer); 7003 7004 DestroyWindow(hwnd); 7005 } 7006 7007 static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code) 7008 { 7009 int length; 7010 7011 /* MSDN lied, length is actually the number of bytes. */ 7012 length = bytes / sizeof(WCHAR); 7013 switch(code) 7014 { 7015 case WB_ISDELIMITER: 7016 return text[pos] == 'X'; 7017 case WB_LEFT: 7018 case WB_MOVEWORDLEFT: 7019 if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7020 return pos-1; 7021 return min(customWordBreakProc(text, pos, bytes, WB_LEFTBREAK)-1, 0); 7022 case WB_LEFTBREAK: 7023 pos--; 7024 while (pos > 0 && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7025 pos--; 7026 return pos; 7027 case WB_RIGHT: 7028 case WB_MOVEWORDRIGHT: 7029 if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7030 return pos+1; 7031 return min(customWordBreakProc(text, pos, bytes, WB_RIGHTBREAK)+1, length); 7032 case WB_RIGHTBREAK: 7033 pos++; 7034 while (pos < length && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) 7035 pos++; 7036 return pos; 7037 default: 7038 ok(FALSE, "Unexpected code %d\n", code); 7039 break; 7040 } 7041 return 0; 7042 } 7043 7044 static void test_word_movement(void) 7045 { 7046 HWND hwnd; 7047 int result; 7048 int sel_start, sel_end; 7049 const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0}; 7050 7051 /* multi-line control inserts CR normally */ 7052 hwnd = new_richedit(NULL); 7053 7054 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one two three"); 7055 ok (result == TRUE, "Failed to clear the text.\n"); 7056 SendMessageA(hwnd, EM_SETSEL, 0, 0); 7057 /* |one two three */ 7058 7059 send_ctrl_key(hwnd, VK_RIGHT); 7060 /* one |two three */ 7061 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7062 ok(sel_start == sel_end, "Selection should be empty\n"); 7063 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); 7064 7065 send_ctrl_key(hwnd, VK_RIGHT); 7066 /* one two |three */ 7067 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7068 ok(sel_start == sel_end, "Selection should be empty\n"); 7069 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7070 7071 send_ctrl_key(hwnd, VK_LEFT); 7072 /* one |two three */ 7073 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7074 ok(sel_start == sel_end, "Selection should be empty\n"); 7075 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); 7076 7077 send_ctrl_key(hwnd, VK_LEFT); 7078 /* |one two three */ 7079 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7080 ok(sel_start == sel_end, "Selection should be empty\n"); 7081 ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0); 7082 7083 SendMessageA(hwnd, EM_SETSEL, 8, 8); 7084 /* one two | three */ 7085 send_ctrl_key(hwnd, VK_RIGHT); 7086 /* one two |three */ 7087 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7088 ok(sel_start == sel_end, "Selection should be empty\n"); 7089 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7090 7091 SendMessageA(hwnd, EM_SETSEL, 11, 11); 7092 /* one two th|ree */ 7093 send_ctrl_key(hwnd, VK_LEFT); 7094 /* one two |three */ 7095 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7096 ok(sel_start == sel_end, "Selection should be empty\n"); 7097 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); 7098 7099 /* Test with a custom word break procedure that uses X as the delimiter. */ 7100 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree"); 7101 ok (result == TRUE, "Failed to clear the text.\n"); 7102 SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); 7103 /* |one twoXthree */ 7104 send_ctrl_key(hwnd, VK_RIGHT); 7105 /* one twoX|three */ 7106 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7107 ok(sel_start == sel_end, "Selection should be empty\n"); 7108 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); 7109 7110 DestroyWindow(hwnd); 7111 7112 /* Make sure the behaviour is the same with a unicode richedit window, 7113 * and using unicode functions. */ 7114 7115 hwnd = CreateWindowW(RICHEDIT_CLASS20W, NULL, 7116 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7117 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7118 7119 /* Test with a custom word break procedure that uses X as the delimiter. */ 7120 result = SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW); 7121 ok (result == TRUE, "Failed to clear the text.\n"); 7122 SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); 7123 /* |one twoXthree */ 7124 send_ctrl_key(hwnd, VK_RIGHT); 7125 /* one twoX|three */ 7126 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); 7127 ok(sel_start == sel_end, "Selection should be empty\n"); 7128 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); 7129 7130 DestroyWindow(hwnd); 7131 } 7132 7133 static void test_EM_CHARFROMPOS(void) 7134 { 7135 HWND hwnd; 7136 int result; 7137 RECT rcClient; 7138 POINTL point; 7139 point.x = 0; 7140 point.y = 40; 7141 7142 /* multi-line control inserts CR normally */ 7143 hwnd = new_richedit(NULL); 7144 result = SendMessageA(hwnd, WM_SETTEXT, 0, 7145 (LPARAM)"one two three four five six seven\reight"); 7146 ok(result == 1, "Expected 1, got %d\n", result); 7147 GetClientRect(hwnd, &rcClient); 7148 7149 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7150 ok(result == 34, "expected character index of 34 but got %d\n", result); 7151 7152 /* Test with points outside the bounds of the richedit control. */ 7153 point.x = -1; 7154 point.y = 40; 7155 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7156 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); 7157 7158 point.x = 1000; 7159 point.y = 0; 7160 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7161 todo_wine ok(result == 33, "expected character index of 33 but got %d\n", result); 7162 7163 point.x = 1000; 7164 point.y = 36; 7165 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7166 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); 7167 7168 point.x = 1000; 7169 point.y = -1; 7170 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7171 todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result); 7172 7173 point.x = 1000; 7174 point.y = rcClient.bottom + 1; 7175 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7176 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); 7177 7178 point.x = 1000; 7179 point.y = rcClient.bottom; 7180 result = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7181 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); 7182 7183 DestroyWindow(hwnd); 7184 } 7185 7186 static void test_word_wrap(void) 7187 { 7188 HWND hwnd; 7189 POINTL point = {0, 60}; /* This point must be below the first line */ 7190 const char *text = "Must be long enough to test line wrapping"; 7191 DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE; 7192 int res, pos, lines; 7193 7194 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping 7195 * when specified on window creation and set later. */ 7196 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle, 7197 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7198 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7199 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7200 ok(res, "WM_SETTEXT failed.\n"); 7201 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7202 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7203 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7204 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); 7205 7206 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL); 7207 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7208 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7209 DestroyWindow(hwnd); 7210 7211 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle|WS_HSCROLL, 7212 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7213 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7214 7215 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7216 ok(res, "WM_SETTEXT failed.\n"); 7217 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7218 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7219 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7220 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); 7221 7222 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7223 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7224 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7225 DestroyWindow(hwnd); 7226 7227 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle|ES_AUTOHSCROLL, 7228 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7229 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7230 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7231 ok(res, "WM_SETTEXT failed.\n"); 7232 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7233 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7234 7235 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7236 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7237 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7238 DestroyWindow(hwnd); 7239 7240 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, 7241 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL, 7242 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); 7243 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7244 res = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text); 7245 ok(res, "WM_SETTEXT failed.\n"); 7246 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7247 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7248 7249 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); 7250 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7251 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7252 7253 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */ 7254 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 1); 7255 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); 7256 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7257 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); 7258 7259 res = SendMessageA(hwnd, EM_SETTARGETDEVICE, 0, 0); 7260 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); 7261 pos = SendMessageA(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); 7262 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); 7263 DestroyWindow(hwnd); 7264 7265 /* Test to see if wrapping happens with redraw disabled. */ 7266 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle, 7267 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL); 7268 ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); 7269 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0); 7270 res = SendMessageA(hwnd, EM_REPLACESEL, FALSE, (LPARAM)text); 7271 ok(res, "EM_REPLACESEL failed.\n"); 7272 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7273 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); 7274 MoveWindow(hwnd, 0, 0, 200, 80, FALSE); 7275 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7276 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); 7277 7278 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0); 7279 DestroyWindow(hwnd); 7280 } 7281 7282 static void test_autoscroll(void) 7283 { 7284 HWND hwnd = new_richedit(NULL); 7285 int lines, ret, redraw; 7286 POINT pt; 7287 7288 for (redraw = 0; redraw <= 1; redraw++) { 7289 trace("testing with WM_SETREDRAW=%d\n", redraw); 7290 SendMessageA(hwnd, WM_SETREDRAW, redraw, 0); 7291 SendMessageA(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8"); 7292 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7293 ok(lines == 8, "%d lines instead of 8\n", lines); 7294 ret = SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); 7295 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); 7296 ok(pt.y != 0, "Didn't scroll down after replacing text.\n"); 7297 ret = GetWindowLongA(hwnd, GWL_STYLE); 7298 ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret); 7299 7300 SendMessageA(hwnd, WM_SETTEXT, 0, 0); 7301 lines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0); 7302 ok(lines == 1, "%d lines instead of 1\n", lines); 7303 ret = SendMessageA(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); 7304 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); 7305 ok(pt.y == 0, "y scroll position is %d after clearing text.\n", pt.y); 7306 ret = GetWindowLongA(hwnd, GWL_STYLE); 7307 ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret); 7308 } 7309 7310 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0); 7311 DestroyWindow(hwnd); 7312 7313 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set 7314 * auto vertical/horizontal scrolling options. */ 7315 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7316 WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL, 7317 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7318 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7319 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7320 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n"); 7321 ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n"); 7322 ret = GetWindowLongA(hwnd, GWL_STYLE); 7323 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); 7324 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); 7325 DestroyWindow(hwnd); 7326 7327 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7328 WS_POPUP|ES_MULTILINE, 7329 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7330 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7331 ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7332 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n"); 7333 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n"); 7334 ret = GetWindowLongA(hwnd, GWL_STYLE); 7335 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); 7336 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); 7337 DestroyWindow(hwnd); 7338 } 7339 7340 7341 static void test_format_rect(void) 7342 { 7343 HWND hwnd; 7344 RECT rc, expected, clientRect; 7345 int n; 7346 DWORD options; 7347 7348 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7349 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7350 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7351 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7352 7353 GetClientRect(hwnd, &clientRect); 7354 7355 expected = clientRect; 7356 InflateRect(&expected, -1, 0); 7357 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7358 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7359 wine_dbgstr_rect(&expected)); 7360 7361 for (n = -3; n <= 3; n++) 7362 { 7363 rc = clientRect; 7364 InflateRect(&rc, -n, -n); 7365 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7366 7367 expected = rc; 7368 expected.top = max(0, rc.top); 7369 expected.left = max(0, rc.left); 7370 expected.bottom = min(clientRect.bottom, rc.bottom); 7371 expected.right = min(clientRect.right, rc.right); 7372 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7373 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc), 7374 wine_dbgstr_rect(&expected)); 7375 } 7376 7377 rc = clientRect; 7378 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7379 expected = clientRect; 7380 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7381 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7382 wine_dbgstr_rect(&expected)); 7383 7384 /* Adding the selectionbar adds the selectionbar width to the left side. */ 7385 SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_OR, ECO_SELECTIONBAR); 7386 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7387 ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n"); 7388 expected.left += 8; /* selection bar width */ 7389 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7390 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7391 wine_dbgstr_rect(&expected)); 7392 7393 rc = clientRect; 7394 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7395 expected = clientRect; 7396 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7397 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7398 wine_dbgstr_rect(&expected)); 7399 7400 /* Removing the selectionbar subtracts the selectionbar width from the left side, 7401 * even if the left side is already 0. */ 7402 SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_AND, ~ECO_SELECTIONBAR); 7403 options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); 7404 ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n"); 7405 expected.left -= 8; /* selection bar width */ 7406 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7407 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7408 wine_dbgstr_rect(&expected)); 7409 7410 /* Set the absolute value of the formatting rectangle. */ 7411 rc = clientRect; 7412 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7413 expected = clientRect; 7414 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7415 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc), 7416 wine_dbgstr_rect(&expected)); 7417 7418 /* MSDN documents the EM_SETRECT message as using the rectangle provided in 7419 * LPARAM as being a relative offset when the WPARAM value is 1, but these 7420 * tests show that this isn't true. */ 7421 rc.top = 15; 7422 rc.left = 15; 7423 rc.bottom = clientRect.bottom - 15; 7424 rc.right = clientRect.right - 15; 7425 expected = rc; 7426 SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); 7427 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7428 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7429 wine_dbgstr_rect(&expected)); 7430 7431 /* For some reason it does not limit the values to the client rect with 7432 * a WPARAM value of 1. */ 7433 rc.top = -15; 7434 rc.left = -15; 7435 rc.bottom = clientRect.bottom + 15; 7436 rc.right = clientRect.right + 15; 7437 expected = rc; 7438 SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); 7439 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7440 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7441 wine_dbgstr_rect(&expected)); 7442 7443 /* Reset to default rect and check how the format rect adjusts to window 7444 * resize and how it copes with very small windows */ 7445 SendMessageA(hwnd, EM_SETRECT, 0, 0); 7446 7447 MoveWindow(hwnd, 0, 0, 100, 30, FALSE); 7448 GetClientRect(hwnd, &clientRect); 7449 7450 expected = clientRect; 7451 InflateRect(&expected, -1, 0); 7452 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7453 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7454 wine_dbgstr_rect(&expected)); 7455 7456 MoveWindow(hwnd, 0, 0, 0, 30, FALSE); 7457 GetClientRect(hwnd, &clientRect); 7458 7459 expected = clientRect; 7460 InflateRect(&expected, -1, 0); 7461 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7462 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7463 wine_dbgstr_rect(&expected)); 7464 7465 MoveWindow(hwnd, 0, 0, 100, 0, FALSE); 7466 GetClientRect(hwnd, &clientRect); 7467 7468 expected = clientRect; 7469 InflateRect(&expected, -1, 0); 7470 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7471 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7472 wine_dbgstr_rect(&expected)); 7473 7474 DestroyWindow(hwnd); 7475 7476 /* The extended window style affects the formatting rectangle. */ 7477 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, RICHEDIT_CLASS20A, NULL, 7478 ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, 7479 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7480 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7481 7482 GetClientRect(hwnd, &clientRect); 7483 7484 expected = clientRect; 7485 expected.top += 1; 7486 InflateRect(&expected, -1, 0); 7487 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7488 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7489 wine_dbgstr_rect(&expected)); 7490 7491 rc = clientRect; 7492 InflateRect(&rc, -5, -5); 7493 expected = rc; 7494 expected.top -= 1; 7495 InflateRect(&expected, 1, 0); 7496 SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); 7497 SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); 7498 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc), 7499 wine_dbgstr_rect(&expected)); 7500 7501 DestroyWindow(hwnd); 7502 } 7503 7504 static void test_WM_GETDLGCODE(void) 7505 { 7506 HWND hwnd; 7507 UINT res, expected; 7508 MSG msg; 7509 7510 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7511 7512 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7513 ES_MULTILINE|ES_WANTRETURN|WS_POPUP, 7514 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7515 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7516 msg.hwnd = hwnd; 7517 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, 0); 7518 expected = expected | DLGC_WANTMESSAGE; 7519 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7520 res, expected); 7521 DestroyWindow(hwnd); 7522 7523 msg.message = WM_KEYDOWN; 7524 msg.wParam = VK_RETURN; 7525 msg.lParam = (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x0001; 7526 msg.pt.x = 0; 7527 msg.pt.y = 0; 7528 msg.time = GetTickCount(); 7529 7530 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7531 ES_MULTILINE|ES_WANTRETURN|WS_POPUP, 7532 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7533 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7534 msg.hwnd = hwnd; 7535 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7536 expected = expected | DLGC_WANTMESSAGE; 7537 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7538 res, expected); 7539 DestroyWindow(hwnd); 7540 7541 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7542 ES_MULTILINE|WS_POPUP, 7543 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7544 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7545 msg.hwnd = hwnd; 7546 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7547 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7548 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7549 res, expected); 7550 DestroyWindow(hwnd); 7551 7552 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7553 ES_WANTRETURN|WS_POPUP, 7554 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7555 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7556 msg.hwnd = hwnd; 7557 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7558 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7559 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7560 res, expected); 7561 DestroyWindow(hwnd); 7562 7563 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7564 WS_POPUP, 7565 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7566 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7567 msg.hwnd = hwnd; 7568 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7569 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7570 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7571 res, expected); 7572 DestroyWindow(hwnd); 7573 7574 msg.wParam = VK_TAB; 7575 msg.lParam = (MapVirtualKeyA(VK_TAB, MAPVK_VK_TO_VSC) << 16) | 0x0001; 7576 7577 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7578 ES_MULTILINE|WS_POPUP, 7579 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7580 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7581 msg.hwnd = hwnd; 7582 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7583 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7584 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7585 res, expected); 7586 DestroyWindow(hwnd); 7587 7588 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7589 WS_POPUP, 7590 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7591 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7592 msg.hwnd = hwnd; 7593 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7594 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7595 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7596 res, expected); 7597 DestroyWindow(hwnd); 7598 7599 hold_key(VK_CONTROL); 7600 7601 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7602 ES_MULTILINE|WS_POPUP, 7603 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7604 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7605 msg.hwnd = hwnd; 7606 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7607 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7608 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7609 res, expected); 7610 DestroyWindow(hwnd); 7611 7612 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7613 WS_POPUP, 7614 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7615 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7616 msg.hwnd = hwnd; 7617 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7618 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7619 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7620 res, expected); 7621 DestroyWindow(hwnd); 7622 7623 release_key(VK_CONTROL); 7624 7625 msg.wParam = 'a'; 7626 msg.lParam = (MapVirtualKeyA('a', MAPVK_VK_TO_VSC) << 16) | 0x0001; 7627 7628 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7629 ES_MULTILINE|WS_POPUP, 7630 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7631 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7632 msg.hwnd = hwnd; 7633 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7634 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7635 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7636 res, expected); 7637 DestroyWindow(hwnd); 7638 7639 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7640 WS_POPUP, 7641 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7642 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7643 msg.hwnd = hwnd; 7644 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7645 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7646 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7647 res, expected); 7648 DestroyWindow(hwnd); 7649 7650 msg.message = WM_CHAR; 7651 7652 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7653 ES_MULTILINE|WS_POPUP, 7654 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7655 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7656 msg.hwnd = hwnd; 7657 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7658 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; 7659 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7660 res, expected); 7661 DestroyWindow(hwnd); 7662 7663 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7664 WS_POPUP, 7665 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7666 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7667 msg.hwnd = hwnd; 7668 res = SendMessageA(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); 7669 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 7670 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7671 res, expected); 7672 DestroyWindow(hwnd); 7673 7674 hwnd = CreateWindowExA(0, RICHEDIT_CLASS20A, NULL, 7675 WS_POPUP|ES_SAVESEL, 7676 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); 7677 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 7678 res = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); 7679 expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS; 7680 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", 7681 res, expected); 7682 DestroyWindow(hwnd); 7683 } 7684 7685 static void test_zoom(void) 7686 { 7687 HWND hwnd; 7688 UINT ret; 7689 RECT rc; 7690 POINT pt; 7691 int numerator, denominator; 7692 7693 hwnd = new_richedit(NULL); 7694 GetClientRect(hwnd, &rc); 7695 pt.x = (rc.right - rc.left) / 2; 7696 pt.y = (rc.bottom - rc.top) / 2; 7697 ClientToScreen(hwnd, &pt); 7698 7699 /* Test initial zoom value */ 7700 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7701 ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator); 7702 ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator); 7703 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7704 7705 /* test scroll wheel */ 7706 hold_key(VK_CONTROL); 7707 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7708 MAKELPARAM(pt.x, pt.y)); 7709 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7710 release_key(VK_CONTROL); 7711 7712 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7713 ok(numerator == 110, "incorrect numerator is %d\n", numerator); 7714 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7715 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7716 7717 /* Test how much the mouse wheel can zoom in and out. */ 7718 ret = SendMessageA(hwnd, EM_SETZOOM, 490, 100); 7719 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7720 7721 hold_key(VK_CONTROL); 7722 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7723 MAKELPARAM(pt.x, pt.y)); 7724 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7725 release_key(VK_CONTROL); 7726 7727 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7728 ok(numerator == 500, "incorrect numerator is %d\n", numerator); 7729 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7730 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7731 7732 ret = SendMessageA(hwnd, EM_SETZOOM, 491, 100); 7733 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7734 7735 hold_key(VK_CONTROL); 7736 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7737 MAKELPARAM(pt.x, pt.y)); 7738 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7739 release_key(VK_CONTROL); 7740 7741 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7742 ok(numerator == 491, "incorrect numerator is %d\n", numerator); 7743 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7744 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7745 7746 ret = SendMessageA(hwnd, EM_SETZOOM, 20, 100); 7747 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7748 7749 hold_key(VK_CONTROL); 7750 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), 7751 MAKELPARAM(pt.x, pt.y)); 7752 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7753 release_key(VK_CONTROL); 7754 7755 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7756 ok(numerator == 10, "incorrect numerator is %d\n", numerator); 7757 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7758 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7759 7760 ret = SendMessageA(hwnd, EM_SETZOOM, 19, 100); 7761 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7762 7763 hold_key(VK_CONTROL); 7764 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), 7765 MAKELPARAM(pt.x, pt.y)); 7766 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7767 release_key(VK_CONTROL); 7768 7769 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7770 ok(numerator == 19, "incorrect numerator is %d\n", numerator); 7771 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7772 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7773 7774 /* Test how WM_SCROLLWHEEL treats our custom denominator. */ 7775 ret = SendMessageA(hwnd, EM_SETZOOM, 50, 13); 7776 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7777 7778 hold_key(VK_CONTROL); 7779 ret = SendMessageA(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), 7780 MAKELPARAM(pt.x, pt.y)); 7781 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); 7782 release_key(VK_CONTROL); 7783 7784 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7785 ok(numerator == 394, "incorrect numerator is %d\n", numerator); 7786 ok(denominator == 100, "incorrect denominator is %d\n", denominator); 7787 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7788 7789 /* Test bounds checking on EM_SETZOOM */ 7790 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 127); 7791 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); 7792 7793 ret = SendMessageA(hwnd, EM_SETZOOM, 127, 2); 7794 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); 7795 7796 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 128); 7797 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7798 7799 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7800 ok(numerator == 127, "incorrect numerator is %d\n", numerator); 7801 ok(denominator == 2, "incorrect denominator is %d\n", denominator); 7802 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7803 7804 ret = SendMessageA(hwnd, EM_SETZOOM, 128, 2); 7805 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7806 7807 /* See if negative numbers are accepted. */ 7808 ret = SendMessageA(hwnd, EM_SETZOOM, -100, -100); 7809 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); 7810 7811 /* See if negative numbers are accepted. */ 7812 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 100); 7813 ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret); 7814 7815 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); 7816 ok(numerator == 127, "incorrect numerator is %d\n", numerator); 7817 ok(denominator == 2, "incorrect denominator is %d\n", denominator); 7818 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); 7819 7820 /* Reset the zoom value */ 7821 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 0); 7822 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); 7823 7824 DestroyWindow(hwnd); 7825 } 7826 7827 struct dialog_mode_messages 7828 { 7829 int wm_getdefid, wm_close, wm_nextdlgctl; 7830 }; 7831 7832 static struct dialog_mode_messages dm_messages; 7833 7834 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \ 7835 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \ 7836 "got %d\n", wmclose, dm_messages.wm_close); \ 7837 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \ 7838 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\ 7839 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \ 7840 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl) 7841 7842 static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 7843 { 7844 switch (iMsg) 7845 { 7846 case DM_GETDEFID: 7847 dm_messages.wm_getdefid++; 7848 return MAKELONG(ID_RICHEDITTESTDBUTTON, DC_HASDEFID); 7849 case WM_NEXTDLGCTL: 7850 dm_messages.wm_nextdlgctl++; 7851 break; 7852 case WM_CLOSE: 7853 dm_messages.wm_close++; 7854 break; 7855 } 7856 7857 return DefWindowProcA(hwnd, iMsg, wParam, lParam); 7858 } 7859 7860 static void test_dialogmode(void) 7861 { 7862 HWND hwRichEdit, hwParent, hwButton; 7863 MSG msg= {0}; 7864 int lcount, r; 7865 WNDCLASSA cls; 7866 7867 cls.style = 0; 7868 cls.lpfnWndProc = dialog_mode_wnd_proc; 7869 cls.cbClsExtra = 0; 7870 cls.cbWndExtra = 0; 7871 cls.hInstance = GetModuleHandleA(0); 7872 cls.hIcon = 0; 7873 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 7874 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 7875 cls.lpszMenuName = NULL; 7876 cls.lpszClassName = "DialogModeParentClass"; 7877 if(!RegisterClassA(&cls)) assert(0); 7878 7879 hwParent = CreateWindowA("DialogModeParentClass", NULL, WS_OVERLAPPEDWINDOW, 7880 CW_USEDEFAULT, 0, 200, 120, NULL, NULL, GetModuleHandleA(0), NULL); 7881 7882 /* Test richedit(ES_MULTILINE) */ 7883 7884 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7885 7886 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7887 ok(0 == r, "expected 0, got %d\n", r); 7888 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7889 ok(2 == lcount, "expected 2, got %d\n", lcount); 7890 7891 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, 0); 7892 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7893 7894 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7895 ok(0 == r, "expected 0, got %d\n", r); 7896 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7897 ok(3 == lcount, "expected 3, got %d\n", lcount); 7898 7899 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7900 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7901 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7902 ok(0 == r, "expected 0, got %d\n", r); 7903 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7904 ok(3 == lcount, "expected 3, got %d\n", lcount); 7905 7906 DestroyWindow(hwRichEdit); 7907 7908 /* Test standalone richedit(ES_MULTILINE) */ 7909 7910 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, NULL); 7911 7912 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7913 ok(0 == r, "expected 0, got %d\n", r); 7914 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7915 ok(2 == lcount, "expected 2, got %d\n", lcount); 7916 7917 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7918 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7919 7920 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7921 ok(0 == r, "expected 0, got %d\n", r); 7922 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7923 ok(2 == lcount, "expected 2, got %d\n", lcount); 7924 7925 DestroyWindow(hwRichEdit); 7926 7927 /* Check a destination for messages */ 7928 7929 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7930 7931 SetWindowLongA(hwRichEdit, GWL_STYLE, GetWindowLongA(hwRichEdit, GWL_STYLE)& ~WS_POPUP); 7932 SetParent( hwRichEdit, NULL); 7933 7934 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7935 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7936 7937 memset(&dm_messages, 0, sizeof(dm_messages)); 7938 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7939 ok(0 == r, "expected 0, got %d\n", r); 7940 test_dm_messages(0, 1, 0); 7941 7942 memset(&dm_messages, 0, sizeof(dm_messages)); 7943 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7944 ok(0 == r, "expected 0, got %d\n", r); 7945 test_dm_messages(0, 0, 1); 7946 7947 DestroyWindow(hwRichEdit); 7948 7949 /* Check messages from richedit(ES_MULTILINE) */ 7950 7951 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent); 7952 7953 memset(&dm_messages, 0, sizeof(dm_messages)); 7954 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7955 ok(0 == r, "expected 0, got %d\n", r); 7956 test_dm_messages(0, 0, 0); 7957 7958 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7959 ok(2 == lcount, "expected 2, got %d\n", lcount); 7960 7961 memset(&dm_messages, 0, sizeof(dm_messages)); 7962 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 7963 ok(0 == r, "expected 0, got %d\n", r); 7964 test_dm_messages(0, 0, 0); 7965 7966 memset(&dm_messages, 0, sizeof(dm_messages)); 7967 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7968 ok(0 == r, "expected 0, got %d\n", r); 7969 test_dm_messages(0, 0, 0); 7970 7971 memset(&dm_messages, 0, sizeof(dm_messages)); 7972 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 7973 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 7974 test_dm_messages(0, 0, 0); 7975 7976 memset(&dm_messages, 0, sizeof(dm_messages)); 7977 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 7978 ok(0 == r, "expected 0, got %d\n", r); 7979 test_dm_messages(0, 1, 0); 7980 7981 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 7982 ok(2 == lcount, "expected 2, got %d\n", lcount); 7983 7984 memset(&dm_messages, 0, sizeof(dm_messages)); 7985 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 7986 ok(0 == r, "expected 0, got %d\n", r); 7987 test_dm_messages(0, 0, 0); 7988 7989 memset(&dm_messages, 0, sizeof(dm_messages)); 7990 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 7991 ok(0 == r, "expected 0, got %d\n", r); 7992 test_dm_messages(0, 0, 1); 7993 7994 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 7995 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 7996 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 7997 7998 memset(&dm_messages, 0, sizeof(dm_messages)); 7999 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8000 ok(0 == r, "expected 0, got %d\n", r); 8001 test_dm_messages(0, 1, 1); 8002 8003 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8004 ok(2 == lcount, "expected 2, got %d\n", lcount); 8005 8006 DestroyWindow(hwButton); 8007 DestroyWindow(hwRichEdit); 8008 8009 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */ 8010 8011 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_WANTRETURN, hwParent); 8012 8013 memset(&dm_messages, 0, sizeof(dm_messages)); 8014 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8015 ok(0 == r, "expected 0, got %d\n", r); 8016 test_dm_messages(0, 0, 0); 8017 8018 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8019 ok(2 == lcount, "expected 2, got %d\n", lcount); 8020 8021 memset(&dm_messages, 0, sizeof(dm_messages)); 8022 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8023 ok(0 == r, "expected 0, got %d\n", r); 8024 test_dm_messages(0, 0, 0); 8025 8026 memset(&dm_messages, 0, sizeof(dm_messages)); 8027 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8028 ok(0 == r, "expected 0, got %d\n", r); 8029 test_dm_messages(0, 0, 0); 8030 8031 memset(&dm_messages, 0, sizeof(dm_messages)); 8032 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8033 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r); 8034 test_dm_messages(0, 0, 0); 8035 8036 memset(&dm_messages, 0, sizeof(dm_messages)); 8037 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8038 ok(0 == r, "expected 0, got %d\n", r); 8039 test_dm_messages(0, 0, 0); 8040 8041 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8042 ok(3 == lcount, "expected 3, got %d\n", lcount); 8043 8044 memset(&dm_messages, 0, sizeof(dm_messages)); 8045 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8046 ok(0 == r, "expected 0, got %d\n", r); 8047 test_dm_messages(0, 0, 0); 8048 8049 memset(&dm_messages, 0, sizeof(dm_messages)); 8050 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8051 ok(0 == r, "expected 0, got %d\n", r); 8052 test_dm_messages(0, 0, 1); 8053 8054 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8055 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8056 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8057 8058 memset(&dm_messages, 0, sizeof(dm_messages)); 8059 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8060 ok(0 == r, "expected 0, got %d\n", r); 8061 test_dm_messages(0, 0, 0); 8062 8063 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0); 8064 ok(4 == lcount, "expected 4, got %d\n", lcount); 8065 8066 DestroyWindow(hwButton); 8067 DestroyWindow(hwRichEdit); 8068 8069 /* Check messages from richedit(0) */ 8070 8071 hwRichEdit = new_window(RICHEDIT_CLASS20A, 0, hwParent); 8072 8073 memset(&dm_messages, 0, sizeof(dm_messages)); 8074 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8075 ok(0 == r, "expected 0, got %d\n", r); 8076 test_dm_messages(0, 0, 0); 8077 8078 memset(&dm_messages, 0, sizeof(dm_messages)); 8079 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8080 ok(0 == r, "expected 0, got %d\n", r); 8081 test_dm_messages(0, 0, 0); 8082 8083 memset(&dm_messages, 0, sizeof(dm_messages)); 8084 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8085 ok(0 == r, "expected 0, got %d\n", r); 8086 test_dm_messages(0, 0, 0); 8087 8088 memset(&dm_messages, 0, sizeof(dm_messages)); 8089 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8090 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r); 8091 test_dm_messages(0, 0, 0); 8092 8093 memset(&dm_messages, 0, sizeof(dm_messages)); 8094 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8095 ok(0 == r, "expected 0, got %d\n", r); 8096 test_dm_messages(0, 1, 0); 8097 8098 memset(&dm_messages, 0, sizeof(dm_messages)); 8099 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); 8100 ok(0 == r, "expected 0, got %d\n", r); 8101 test_dm_messages(0, 0, 0); 8102 8103 memset(&dm_messages, 0, sizeof(dm_messages)); 8104 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001); 8105 ok(0 == r, "expected 0, got %d\n", r); 8106 test_dm_messages(0, 0, 1); 8107 8108 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8109 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8110 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8111 8112 memset(&dm_messages, 0, sizeof(dm_messages)); 8113 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8114 ok(0 == r, "expected 0, got %d\n", r); 8115 test_dm_messages(0, 1, 1); 8116 8117 DestroyWindow(hwRichEdit); 8118 8119 /* Check messages from richedit(ES_WANTRETURN) */ 8120 8121 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_WANTRETURN, hwParent); 8122 8123 memset(&dm_messages, 0, sizeof(dm_messages)); 8124 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8125 ok(0 == r, "expected 0, got %d\n", r); 8126 test_dm_messages(0, 0, 0); 8127 8128 memset(&dm_messages, 0, sizeof(dm_messages)); 8129 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg); 8130 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r); 8131 test_dm_messages(0, 0, 0); 8132 8133 memset(&dm_messages, 0, sizeof(dm_messages)); 8134 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8135 ok(0 == r, "expected 0, got %d\n", r); 8136 test_dm_messages(0, 0, 0); 8137 8138 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 8139 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL); 8140 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); 8141 8142 memset(&dm_messages, 0, sizeof(dm_messages)); 8143 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); 8144 ok(0 == r, "expected 0, got %d\n", r); 8145 test_dm_messages(0, 0, 0); 8146 8147 DestroyWindow(hwRichEdit); 8148 DestroyWindow(hwParent); 8149 } 8150 8151 static void test_EM_FINDWORDBREAK_W(void) 8152 { 8153 static const struct { 8154 WCHAR c; 8155 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */ 8156 } delimiter_tests[] = { 8157 {0x0a, FALSE}, /* newline */ 8158 {0x0b, FALSE}, /* vertical tab */ 8159 {0x0c, FALSE}, /* form feed */ 8160 {0x0d, FALSE}, /* carriage return */ 8161 {0x20, TRUE}, /* space */ 8162 {0x61, FALSE}, /* capital letter a */ 8163 {0xa0, FALSE}, /* no-break space */ 8164 {0x2000, FALSE}, /* en quad */ 8165 {0x3000, FALSE}, /* Ideographic space */ 8166 {0x1100, FALSE}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/ 8167 {0x11ff, FALSE}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/ 8168 {0x115f, FALSE}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */ 8169 {0xac00, FALSE}, /* Hangul character GA*/ 8170 {0xd7af, FALSE}, /* End of Hangul character chart */ 8171 {0xf020, TRUE}, /* MS private for CP_SYMBOL round trip?, see kb897872 */ 8172 {0xff20, FALSE}, /* fullwidth commercial @ */ 8173 {WCH_EMBEDDING, FALSE}, /* object replacement character*/ 8174 }; 8175 int i; 8176 HWND hwndRichEdit = new_richeditW(NULL); 8177 ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n"); 8178 for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) 8179 { 8180 WCHAR wbuf[2]; 8181 int result; 8182 8183 wbuf[0] = delimiter_tests[i].c; 8184 wbuf[1] = 0; 8185 SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)wbuf); 8186 result = SendMessageW(hwndRichEdit, EM_FINDWORDBREAK, WB_ISDELIMITER,0); 8187 todo_wine_if (wbuf[0] == 0x20 || wbuf[0] == 0xf020) 8188 ok(result == delimiter_tests[i].isdelimiter, 8189 "wanted ISDELIMITER_W(0x%x) %d, got %d\n", 8190 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result); 8191 } 8192 DestroyWindow(hwndRichEdit); 8193 } 8194 8195 static void test_EM_FINDWORDBREAK_A(void) 8196 { 8197 static const struct { 8198 WCHAR c; 8199 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */ 8200 } delimiter_tests[] = { 8201 {0x0a, FALSE}, /* newline */ 8202 {0x0b, FALSE}, /* vertical tab */ 8203 {0x0c, FALSE}, /* form feed */ 8204 {0x0d, FALSE}, /* carriage return */ 8205 {0x20, TRUE}, /* space */ 8206 {0x61, FALSE}, /* capital letter a */ 8207 }; 8208 int i; 8209 HWND hwndRichEdit = new_richedit(NULL); 8210 8211 ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n"); 8212 for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) 8213 { 8214 int result; 8215 char buf[2]; 8216 buf[0] = delimiter_tests[i].c; 8217 buf[1] = 0; 8218 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buf); 8219 result = SendMessageA(hwndRichEdit, EM_FINDWORDBREAK, WB_ISDELIMITER, 0); 8220 todo_wine_if (buf[0] == 0x20) 8221 ok(result == delimiter_tests[i].isdelimiter, 8222 "wanted ISDELIMITER_A(0x%x) %d, got %d\n", 8223 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result); 8224 } 8225 DestroyWindow(hwndRichEdit); 8226 } 8227 8228 /* 8229 * This test attempts to show the effect of enter on a richedit 8230 * control v1.0 inserts CRLF whereas for higher versions it only 8231 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT 8232 * and also shows that GT_USECRLF has no effect in richedit 1.0, but 8233 * does for higher. The same test is cloned in riched32 and riched20. 8234 */ 8235 static void test_enter(void) 8236 { 8237 static const struct { 8238 const char *initialtext; 8239 const int cursor; 8240 const char *expectedwmtext; 8241 const char *expectedemtext; 8242 const char *expectedemtextcrlf; 8243 } testenteritems[] = { 8244 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"}, 8245 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"}, 8246 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"}, 8247 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}, 8248 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"} 8249 }; 8250 8251 char expectedbuf[1024]; 8252 char resultbuf[1024]; 8253 HWND hwndRichEdit = new_richedit(NULL); 8254 UINT i,j; 8255 8256 for (i = 0; i < sizeof(testenteritems)/sizeof(testenteritems[0]); i++) { 8257 8258 char buf[1024] = {0}; 8259 LRESULT result; 8260 GETTEXTEX getText; 8261 const char *expected; 8262 8263 /* Set the text to the initial text */ 8264 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext); 8265 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result); 8266 8267 /* Send Enter */ 8268 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor); 8269 simulate_typing_characters(hwndRichEdit, "\r"); 8270 8271 /* 1. Retrieve with WM_GETTEXT */ 8272 buf[0] = 0x00; 8273 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); 8274 expected = testenteritems[i].expectedwmtext; 8275 8276 resultbuf[0]=0x00; 8277 for (j = 0; j < (UINT)result; j++) 8278 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8279 expectedbuf[0] = '\0'; 8280 for (j = 0; j < strlen(expected); j++) 8281 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8282 8283 result = strcmp(expected, buf); 8284 ok (result == 0, 8285 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n", 8286 i, resultbuf, expectedbuf); 8287 8288 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */ 8289 getText.cb = sizeof(buf); 8290 getText.flags = GT_DEFAULT; 8291 getText.codepage = CP_ACP; 8292 getText.lpDefaultChar = NULL; 8293 getText.lpUsedDefChar = NULL; 8294 buf[0] = 0x00; 8295 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 8296 expected = testenteritems[i].expectedemtext; 8297 8298 resultbuf[0]=0x00; 8299 for (j = 0; j < (UINT)result; j++) 8300 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8301 expectedbuf[0] = '\0'; 8302 for (j = 0; j < strlen(expected); j++) 8303 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8304 8305 result = strcmp(expected, buf); 8306 ok (result == 0, 8307 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", 8308 i, resultbuf, expectedbuf); 8309 8310 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */ 8311 getText.cb = sizeof(buf); 8312 getText.flags = GT_USECRLF; 8313 getText.codepage = CP_ACP; 8314 getText.lpDefaultChar = NULL; 8315 getText.lpUsedDefChar = NULL; 8316 buf[0] = 0x00; 8317 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); 8318 expected = testenteritems[i].expectedemtextcrlf; 8319 8320 resultbuf[0]=0x00; 8321 for (j = 0; j < (UINT)result; j++) 8322 sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); 8323 expectedbuf[0] = '\0'; 8324 for (j = 0; j < strlen(expected); j++) 8325 sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); 8326 8327 result = strcmp(expected, buf); 8328 ok (result == 0, 8329 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n", 8330 i, resultbuf, expectedbuf); 8331 } 8332 8333 DestroyWindow(hwndRichEdit); 8334 } 8335 8336 static void test_WM_CREATE(void) 8337 { 8338 static const WCHAR titleW[] = {'l','i','n','e','1','\n','l','i','n','e','2',0}; 8339 static const char title[] = "line1\nline2"; 8340 8341 HWND rich_edit; 8342 LRESULT res; 8343 char buf[64]; 8344 int len; 8345 8346 rich_edit = CreateWindowA(RICHEDIT_CLASS20A, title, WS_POPUP|WS_VISIBLE, 8347 0, 0, 200, 80, NULL, NULL, NULL, NULL); 8348 ok(rich_edit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError()); 8349 8350 len = GetWindowTextA(rich_edit, buf, sizeof(buf)); 8351 ok(len == 5, "GetWindowText returned %d\n", len); 8352 ok(!strcmp(buf, "line1"), "buf = %s\n", buf); 8353 8354 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0); 8355 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res); 8356 8357 DestroyWindow(rich_edit); 8358 8359 rich_edit = CreateWindowW(RICHEDIT_CLASS20W, titleW, WS_POPUP|WS_VISIBLE|ES_MULTILINE, 8360 0, 0, 200, 80, NULL, NULL, NULL, NULL); 8361 ok(rich_edit != NULL, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W), (int) GetLastError()); 8362 8363 len = GetWindowTextA(rich_edit, buf, sizeof(buf)); 8364 ok(len == 12, "GetWindowText returned %d\n", len); 8365 ok(!strcmp(buf, "line1\r\nline2"), "buf = %s\n", buf); 8366 8367 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0); 8368 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res); 8369 8370 DestroyWindow(rich_edit); 8371 } 8372 8373 /******************************************************************* 8374 * Test that after deleting all of the text, the first paragraph 8375 * format reverts to the default. 8376 */ 8377 static void test_reset_default_para_fmt( void ) 8378 { 8379 HWND richedit = new_richeditW( NULL ); 8380 PARAFORMAT2 fmt; 8381 WORD def_align, new_align; 8382 8383 memset( &fmt, 0, sizeof(fmt) ); 8384 fmt.cbSize = sizeof(PARAFORMAT2); 8385 fmt.dwMask = -1; 8386 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8387 def_align = fmt.wAlignment; 8388 new_align = (def_align == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT; 8389 8390 simulate_typing_characters( richedit, "123" ); 8391 8392 SendMessageA( richedit, EM_SETSEL, 0, -1 ); 8393 fmt.dwMask = PFM_ALIGNMENT; 8394 fmt.wAlignment = new_align; 8395 SendMessageA( richedit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt ); 8396 8397 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8398 ok( fmt.wAlignment == new_align, "got %d expect %d\n", fmt.wAlignment, new_align ); 8399 8400 SendMessageA( richedit, EM_SETSEL, 0, -1 ); 8401 SendMessageA( richedit, WM_CUT, 0, 0 ); 8402 8403 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8404 ok( fmt.wAlignment == def_align, "got %d expect %d\n", fmt.wAlignment, def_align ); 8405 8406 DestroyWindow( richedit ); 8407 } 8408 8409 static void test_EM_SETREADONLY(void) 8410 { 8411 HWND richedit = new_richeditW(NULL); 8412 DWORD dwStyle; 8413 LRESULT res; 8414 8415 res = SendMessageA(richedit, EM_SETREADONLY, TRUE, 0); 8416 ok(res == 1, "EM_SETREADONLY\n"); 8417 dwStyle = GetWindowLongA(richedit, GWL_STYLE); 8418 ok(dwStyle & ES_READONLY, "got wrong value: 0x%x\n", dwStyle); 8419 8420 res = SendMessageA(richedit, EM_SETREADONLY, FALSE, 0); 8421 ok(res == 1, "EM_SETREADONLY\n"); 8422 dwStyle = GetWindowLongA(richedit, GWL_STYLE); 8423 ok(!(dwStyle & ES_READONLY), "got wrong value: 0x%x\n", dwStyle); 8424 8425 DestroyWindow(richedit); 8426 } 8427 8428 static inline LONG twips2points(LONG value) 8429 { 8430 return value / 20; 8431 } 8432 8433 #define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \ 8434 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo) 8435 static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size, 8436 LRESULT expected_res, BOOL expected_undo) 8437 { 8438 CHARFORMAT2A cf; 8439 LRESULT res; 8440 BOOL isundo; 8441 8442 cf.cbSize = sizeof(cf); 8443 cf.dwMask = CFM_SIZE; 8444 8445 res = SendMessageA(hwnd, EM_SETFONTSIZE, size, 0); 8446 SendMessageA(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); 8447 isundo = SendMessageA(hwnd, EM_CANUNDO, 0, 0); 8448 ok_(__FILE__,line)(res == expected_res, "EM_SETFONTSIZE unexpected return value: %lx.\n", res); 8449 ok_(__FILE__,line)(twips2points(cf.yHeight) == expected_size, "got wrong font size: %d, expected: %d\n", 8450 twips2points(cf.yHeight), expected_size); 8451 ok_(__FILE__,line)(isundo == expected_undo, "get wrong undo mark: %d, expected: %d.\n", 8452 isundo, expected_undo); 8453 } 8454 8455 static void test_EM_SETFONTSIZE(void) 8456 { 8457 HWND richedit = new_richedit(NULL); 8458 CHAR text[] = "wine"; 8459 CHARFORMAT2A tmp_cf; 8460 LONG default_size; 8461 8462 tmp_cf.cbSize = sizeof(tmp_cf); 8463 tmp_cf.dwMask = CFM_SIZE; 8464 tmp_cf.yHeight = 9 * 20.0; 8465 SendMessageA(richedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf); 8466 8467 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)text); 8468 8469 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0); 8470 /* without selection */ 8471 TEST_EM_SETFONTSIZE(richedit, 1, 10, TRUE, FALSE); /* 9 + 1 -> 10 */ 8472 SendMessageA(richedit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf); 8473 default_size = twips2points(tmp_cf.yHeight); 8474 ok(default_size == 9, "Default font size should not be changed.\n"); 8475 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n"); 8476 8477 SendMessageA(richedit, EM_SETSEL, 0, 2); 8478 8479 TEST_EM_SETFONTSIZE(richedit, 0, 9, TRUE, TRUE); /* 9 + 0 -> 9 */ 8480 8481 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0); 8482 TEST_EM_SETFONTSIZE(richedit, 3, 12, TRUE, TRUE); /* 9 + 3 -> 12 */ 8483 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n"); 8484 8485 TEST_EM_SETFONTSIZE(richedit, 1, 14, TRUE, TRUE); /* 12 + 1 + 1 -> 14 */ 8486 TEST_EM_SETFONTSIZE(richedit, -1, 12, TRUE, TRUE); /* 14 - 1 - 1 -> 12 */ 8487 TEST_EM_SETFONTSIZE(richedit, 4, 16, TRUE, TRUE); /* 12 + 4 -> 16 */ 8488 TEST_EM_SETFONTSIZE(richedit, 3, 20, TRUE, TRUE); /* 16 + 3 + 1 -> 20 */ 8489 TEST_EM_SETFONTSIZE(richedit, 0, 20, TRUE, TRUE); /* 20 + 0 -> 20 */ 8490 TEST_EM_SETFONTSIZE(richedit, 8, 28, TRUE, TRUE); /* 20 + 8 -> 28 */ 8491 TEST_EM_SETFONTSIZE(richedit, 0, 28, TRUE, TRUE); /* 28 + 0 -> 28 */ 8492 TEST_EM_SETFONTSIZE(richedit, 1, 36, TRUE, TRUE); /* 28 + 1 -> 36 */ 8493 TEST_EM_SETFONTSIZE(richedit, 0, 36, TRUE, TRUE); /* 36 + 0 -> 36 */ 8494 TEST_EM_SETFONTSIZE(richedit, 1, 48, TRUE, TRUE); /* 36 + 1 -> 48 */ 8495 TEST_EM_SETFONTSIZE(richedit, 0, 48, TRUE, TRUE); /* 48 + 0 -> 48 */ 8496 TEST_EM_SETFONTSIZE(richedit, 1, 72, TRUE, TRUE); /* 48 + 1 -> 72 */ 8497 TEST_EM_SETFONTSIZE(richedit, 0, 72, TRUE, TRUE); /* 72 + 0 -> 72 */ 8498 TEST_EM_SETFONTSIZE(richedit, 1, 80, TRUE, TRUE); /* 72 + 1 -> 80 */ 8499 TEST_EM_SETFONTSIZE(richedit, 0, 80, TRUE, TRUE); /* 80 + 0 -> 80 */ 8500 TEST_EM_SETFONTSIZE(richedit, 1, 90, TRUE, TRUE); /* 80 + 1 -> 90 */ 8501 TEST_EM_SETFONTSIZE(richedit, 0, 90, TRUE, TRUE); /* 90 + 0 -> 90 */ 8502 TEST_EM_SETFONTSIZE(richedit, 1, 100, TRUE, TRUE); /* 90 + 1 -> 100 */ 8503 TEST_EM_SETFONTSIZE(richedit, 25, 130, TRUE, TRUE); /* 100 + 25 -> 130 */ 8504 TEST_EM_SETFONTSIZE(richedit, -1, 120, TRUE, TRUE); /* 130 - 1 -> 120 */ 8505 TEST_EM_SETFONTSIZE(richedit, -35, 80, TRUE, TRUE); /* 120 - 35 -> 80 */ 8506 TEST_EM_SETFONTSIZE(richedit, -7, 72, TRUE, TRUE); /* 80 - 7 -> 72 */ 8507 TEST_EM_SETFONTSIZE(richedit, -42, 28, TRUE, TRUE); /* 72 - 42 -> 28 */ 8508 TEST_EM_SETFONTSIZE(richedit, -16, 12, TRUE, TRUE); /* 28 - 16 -> 12 */ 8509 TEST_EM_SETFONTSIZE(richedit, -3, 9, TRUE, TRUE); /* 12 - 3 -> 9 */ 8510 TEST_EM_SETFONTSIZE(richedit, -8, 1, TRUE, TRUE); /* 9 - 8 -> 1 */ 8511 TEST_EM_SETFONTSIZE(richedit, -111, 1, TRUE, TRUE); /* 1 - 111 -> 1 */ 8512 TEST_EM_SETFONTSIZE(richedit, 10086, 1638, TRUE, TRUE); /* 1 + 10086 -> 1638 */ 8513 8514 /* return FALSE when richedit is TM_PLAINTEXT mode */ 8515 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)""); 8516 SendMessageA(richedit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0); 8517 TEST_EM_SETFONTSIZE(richedit, 0, 9, FALSE, FALSE); 8518 8519 DestroyWindow(richedit); 8520 } 8521 8522 static void test_alignment_style(void) 8523 { 8524 HWND richedit = NULL; 8525 PARAFORMAT2 pf; 8526 DWORD align_style[] = {ES_LEFT, ES_CENTER, ES_RIGHT, ES_RIGHT | ES_CENTER, 8527 ES_LEFT | ES_CENTER, ES_LEFT | ES_RIGHT, 8528 ES_LEFT | ES_RIGHT | ES_CENTER}; 8529 DWORD align_mask[] = {PFA_LEFT, PFA_CENTER, PFA_RIGHT, PFA_CENTER, PFA_CENTER, 8530 PFA_RIGHT, PFA_CENTER}; 8531 const char * streamtext = 8532 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" 8533 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" 8534 "}\r\n"; 8535 EDITSTREAM es; 8536 int i; 8537 8538 for (i = 0; i < sizeof(align_style) / sizeof(align_style[0]); i++) 8539 { 8540 DWORD dwStyle, new_align; 8541 8542 richedit = new_windowW(RICHEDIT_CLASS20W, align_style[i], NULL); 8543 memset(&pf, 0, sizeof(pf)); 8544 pf.cbSize = sizeof(PARAFORMAT2); 8545 pf.dwMask = -1; 8546 8547 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8548 ok(pf.wAlignment == align_mask[i], "(i = %d) got %d expected %d\n", 8549 i, pf.wAlignment, align_mask[i]); 8550 dwStyle = GetWindowLongW(richedit, GWL_STYLE); 8551 ok((i ? (dwStyle & align_style[i]) : (!(dwStyle & 0x0000000f))) , 8552 "(i = %d) didn't set right align style: 0x%x\n", i, dwStyle); 8553 8554 8555 /* Based on test_reset_default_para_fmt() */ 8556 new_align = (align_mask[i] == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT; 8557 simulate_typing_characters(richedit, "123"); 8558 8559 SendMessageW(richedit, EM_SETSEL, 0, -1); 8560 pf.dwMask = PFM_ALIGNMENT; 8561 pf.wAlignment = new_align; 8562 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); 8563 8564 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8565 ok(pf.wAlignment == new_align, "got %d expect %d\n", pf.wAlignment, new_align); 8566 8567 SendMessageW(richedit, EM_SETSEL, 0, -1); 8568 SendMessageW(richedit, WM_CUT, 0, 0); 8569 8570 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); 8571 ok(pf.wAlignment == align_mask[i], "got %d expect %d\n", pf.wAlignment, align_mask[i]); 8572 8573 DestroyWindow(richedit); 8574 } 8575 8576 /* test with EM_STREAMIN */ 8577 richedit = new_windowW(RICHEDIT_CLASS20W, ES_CENTER, NULL); 8578 simulate_typing_characters(richedit, "abc"); 8579 es.dwCookie = (DWORD_PTR)&streamtext; 8580 es.dwError = 0; 8581 es.pfnCallback = test_EM_STREAMIN_esCallback; 8582 SendMessageW(richedit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 8583 SendMessageW(richedit, EM_SETSEL, 0, -1); 8584 memset(&pf, 0, sizeof(pf)); 8585 pf.cbSize = sizeof(PARAFORMAT2); 8586 pf.dwMask = -1; 8587 SendMessageW(richedit, EM_GETPARAFORMAT, SCF_SELECTION, (LPARAM)&pf); 8588 ok(pf.wAlignment == PFA_LEFT, "got %d expected PFA_LEFT\n", pf.wAlignment); 8589 DestroyWindow(richedit); 8590 } 8591 8592 static void test_WM_GETTEXTLENGTH(void) 8593 { 8594 HWND hwndRichEdit = new_richedit(NULL); 8595 static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee"; 8596 static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n"; 8597 static const char text3[] = "abcdef\x8e\xf0"; 8598 int result; 8599 8600 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); 8601 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8602 ok(result == lstrlenA(text1), "WM_GETTEXTLENGTH returned %d, expected %d\n", 8603 result, lstrlenA(text1)); 8604 8605 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); 8606 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8607 ok(result == lstrlenA(text2), "WM_GETTEXTLENGTH returned %d, expected %d\n", 8608 result, lstrlenA(text2)); 8609 8610 /* Test with multibyte character */ 8611 if (!is_lang_japanese) 8612 skip("Skip multibyte character tests on non-Japanese platform\n"); 8613 else 8614 { 8615 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); 8616 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); 8617 todo_wine ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result); 8618 } 8619 8620 DestroyWindow(hwndRichEdit); 8621 } 8622 8623 static void test_rtf(void) 8624 { 8625 const char *specials = "{\\rtf1\\emspace\\enspace\\bullet\\lquote" 8626 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}"; 8627 const WCHAR expect_specials[] = {' ',' ',0x2022,0x2018,0x2019,0x201c, 8628 0x201d,0x200e,0x200f,0x200d,0x200c}; 8629 const char *pard = "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}"; 8630 const char *highlight = "{\\rtf1{\\colortbl;\\red0\\green0\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\\cf2\\highlight3 foo\\par}"; 8631 8632 HWND edit = new_richeditW( NULL ); 8633 EDITSTREAM es; 8634 WCHAR buf[80]; 8635 LRESULT result; 8636 PARAFORMAT2 fmt; 8637 CHARFORMAT2W cf; 8638 8639 /* Test rtf specials */ 8640 es.dwCookie = (DWORD_PTR)&specials; 8641 es.dwError = 0; 8642 es.pfnCallback = test_EM_STREAMIN_esCallback; 8643 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8644 ok( result == 11, "got %ld\n", result ); 8645 8646 result = SendMessageW( edit, WM_GETTEXT, sizeof(buf)/sizeof(buf[0]), (LPARAM)buf ); 8647 ok( result == sizeof(expect_specials)/sizeof(expect_specials[0]), "got %ld\n", result ); 8648 ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) ); 8649 8650 /* Show that \rtlpar propagates to the second paragraph and is 8651 reset by \pard in the third. */ 8652 es.dwCookie = (DWORD_PTR)&pard; 8653 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8654 ok( result == 11, "got %ld\n", result ); 8655 8656 fmt.cbSize = sizeof(fmt); 8657 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8658 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8659 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8660 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" ); 8661 SendMessageW( edit, EM_SETSEL, 5, 5 ); 8662 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8663 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8664 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" ); 8665 SendMessageW( edit, EM_SETSEL, 9, 9 ); 8666 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8667 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" ); 8668 ok( !(fmt.wEffects & PFE_RTLPARA), "rtl para set\n" ); 8669 8670 /* Test \highlight */ 8671 es.dwCookie = (DWORD_PTR)&highlight; 8672 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8673 ok( result == 3, "got %ld\n", result ); 8674 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8675 memset( &cf, 0, sizeof(cf) ); 8676 cf.cbSize = sizeof(cf); 8677 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8678 ok( (cf.dwEffects & (CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)) == 0, "got %08x\n", cf.dwEffects ); 8679 ok( cf.crTextColor == RGB(128,128,128), "got %08x\n", cf.crTextColor ); 8680 ok( cf.crBackColor == RGB(192,192,192), "got %08x\n", cf.crBackColor ); 8681 8682 DestroyWindow( edit ); 8683 } 8684 8685 static void test_background(void) 8686 { 8687 HWND hwndRichEdit = new_richedit(NULL); 8688 8689 /* set the background color to black */ 8690 ValidateRect(hwndRichEdit, NULL); 8691 SendMessageA(hwndRichEdit, EM_SETBKGNDCOLOR, FALSE, RGB(0, 0, 0)); 8692 ok(GetUpdateRect(hwndRichEdit, NULL, FALSE), "Update rectangle is empty!\n"); 8693 8694 DestroyWindow(hwndRichEdit); 8695 } 8696 8697 static void test_eop_char_fmt(void) 8698 { 8699 HWND edit = new_richedit( NULL ); 8700 const char *rtf = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}" 8701 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par" 8702 "\\f0\\fs25 Second\\par" 8703 "{\\f0\\fs26 Third}\\par" 8704 "{\\f0\\fs22 Fourth}\\par}}}"; 8705 EDITSTREAM es; 8706 CHARFORMAT2W cf; 8707 int i, num, expect_height; 8708 8709 es.dwCookie = (DWORD_PTR)&rtf; 8710 es.dwError = 0; 8711 es.pfnCallback = test_EM_STREAMIN_esCallback; 8712 num = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8713 ok( num == 25, "got %d\n", num ); 8714 8715 for (i = 0; i <= num; i++) 8716 { 8717 SendMessageW( edit, EM_SETSEL, i, i + 1 ); 8718 cf.cbSize = sizeof(cf); 8719 cf.dwMask = CFM_SIZE; 8720 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8721 ok( cf.dwMask & CFM_SIZE, "%d: got %08x\n", i, cf.dwMask ); 8722 if (i < 6) expect_height = 160; 8723 else if (i < 13) expect_height = 250; 8724 else if (i < 18) expect_height = 260; 8725 else if (i == 18 || i == 25) expect_height = 250; 8726 else expect_height = 220; 8727 ok( cf.yHeight == expect_height, "%d: got %d\n", i, cf.yHeight ); 8728 } 8729 8730 DestroyWindow( edit ); 8731 } 8732 8733 static void test_para_numbering(void) 8734 { 8735 HWND edit = new_richeditW( NULL ); 8736 const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}" 8737 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}" 8738 "\\fs20\\fi200\\li360\\f0 First\\par" 8739 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par" 8740 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}"; 8741 const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0}; 8742 EDITSTREAM es; 8743 WCHAR buf[80]; 8744 LRESULT result; 8745 PARAFORMAT2 fmt, fmt2; 8746 GETTEXTEX get_text; 8747 CHARFORMAT2W cf; 8748 8749 get_text.cb = sizeof(buf); 8750 get_text.flags = GT_RAWTEXT; 8751 get_text.codepage = 1200; 8752 get_text.lpDefaultChar = NULL; 8753 get_text.lpUsedDefChar = NULL; 8754 8755 es.dwCookie = (DWORD_PTR)&numbers; 8756 es.dwError = 0; 8757 es.pfnCallback = test_EM_STREAMIN_esCallback; 8758 result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); 8759 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result ); 8760 8761 result = SendMessageW( edit, EM_GETTEXTEX, (WPARAM)&get_text, (LPARAM)buf ); 8762 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result ); 8763 ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) ); 8764 8765 SendMessageW( edit, EM_SETSEL, 1, 1 ); 8766 memset( &fmt, 0, sizeof(fmt) ); 8767 fmt.cbSize = sizeof(fmt); 8768 fmt.dwMask = PFM_ALL2; 8769 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt ); 8770 ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering ); 8771 ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart ); 8772 ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle ); 8773 ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab ); 8774 ok( fmt.dxStartIndent == 560, "got %d\n", fmt.dxStartIndent ); 8775 ok( fmt.dxOffset == -200, "got %d\n", fmt.dxOffset ); 8776 8777 /* Second para should have identical fmt */ 8778 SendMessageW( edit, EM_SETSEL, 10, 10 ); 8779 memset( &fmt2, 0, sizeof(fmt2) ); 8780 fmt2.cbSize = sizeof(fmt2); 8781 fmt2.dwMask = PFM_ALL2; 8782 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 ); 8783 ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" ); 8784 8785 /* Check the eop heights - this determines the label height */ 8786 SendMessageW( edit, EM_SETSEL, 12, 13 ); 8787 cf.cbSize = sizeof(cf); 8788 cf.dwMask = CFM_SIZE; 8789 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8790 ok( cf.yHeight == 200, "got %d\n", cf.yHeight ); 8791 8792 SendMessageW( edit, EM_SETSEL, 18, 19 ); 8793 cf.cbSize = sizeof(cf); 8794 cf.dwMask = CFM_SIZE; 8795 SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf ); 8796 ok( cf.yHeight == 200, "got %d\n", cf.yHeight ); 8797 8798 DestroyWindow( edit ); 8799 } 8800 8801 static void test_window_classes(void) 8802 { 8803 static const struct 8804 { 8805 const char *class; 8806 BOOL success; 8807 } test[] = 8808 { 8809 { "RichEdit", FALSE }, 8810 { "RichEdit20A", TRUE }, 8811 { "RichEdit20W", TRUE }, 8812 { "RichEdit50A", FALSE }, 8813 { "RichEdit50W", FALSE } 8814 }; 8815 int i; 8816 HWND hwnd; 8817 8818 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++) 8819 { 8820 SetLastError(0xdeadbeef); 8821 hwnd = CreateWindowExA(0, test[i].class, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL); 8822 todo_wine_if(!strcmp(test[i].class, "RichEdit50A") || !strcmp(test[i].class, "RichEdit50W")) 8823 ok(!hwnd == !test[i].success, "CreateWindow(%s) should %s\n", 8824 test[i].class, test[i].success ? "succeed" : "fail"); 8825 if (!hwnd) 8826 todo_wine 8827 ok(GetLastError() == ERROR_CANNOT_FIND_WND_CLASS, "got %d\n", GetLastError()); 8828 else 8829 DestroyWindow(hwnd); 8830 } 8831 } 8832 8833 START_TEST( editor ) 8834 { 8835 BOOL ret; 8836 /* Must explicitly LoadLibrary(). The test has no references to functions in 8837 * RICHED20.DLL, so the linker doesn't actually link to it. */ 8838 hmoduleRichEdit = LoadLibraryA("riched20.dll"); 8839 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); 8840 is_lang_japanese = (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE); 8841 8842 test_window_classes(); 8843 test_WM_CHAR(); 8844 test_EM_FINDTEXT(FALSE); 8845 test_EM_FINDTEXT(TRUE); 8846 test_EM_GETLINE(); 8847 test_EM_POSFROMCHAR(); 8848 test_EM_SCROLLCARET(); 8849 test_EM_SCROLL(); 8850 test_scrollbar_visibility(); 8851 test_WM_SETTEXT(); 8852 test_EM_LINELENGTH(); 8853 test_EM_SETCHARFORMAT(); 8854 test_EM_SETTEXTMODE(); 8855 test_TM_PLAINTEXT(); 8856 test_EM_SETOPTIONS(); 8857 test_WM_GETTEXT(); 8858 test_EM_GETTEXTRANGE(); 8859 test_EM_GETSELTEXT(); 8860 test_EM_SETUNDOLIMIT(); 8861 test_ES_PASSWORD(); 8862 test_EM_SETTEXTEX(); 8863 test_EM_LIMITTEXT(); 8864 test_EM_EXLIMITTEXT(); 8865 test_EM_GETLIMITTEXT(); 8866 test_WM_SETFONT(); 8867 test_EM_GETMODIFY(); 8868 test_EM_SETSEL(); 8869 test_EM_EXSETSEL(); 8870 test_WM_PASTE(); 8871 test_EM_STREAMIN(); 8872 test_EM_STREAMOUT(); 8873 test_EM_STREAMOUT_FONTTBL(); 8874 test_EM_STREAMOUT_empty_para(); 8875 test_EM_StreamIn_Undo(); 8876 test_EM_FORMATRANGE(); 8877 test_unicode_conversions(); 8878 test_EM_GETTEXTLENGTHEX(); 8879 test_WM_GETTEXTLENGTH(); 8880 test_EM_REPLACESEL(1); 8881 test_EM_REPLACESEL(0); 8882 test_WM_NOTIFY(); 8883 test_EN_LINK(); 8884 test_EM_AUTOURLDETECT(); 8885 test_eventMask(); 8886 test_undo_coalescing(); 8887 test_word_movement(); 8888 test_EM_CHARFROMPOS(); 8889 test_SETPARAFORMAT(); 8890 test_word_wrap(); 8891 test_autoscroll(); 8892 test_format_rect(); 8893 test_WM_GETDLGCODE(); 8894 test_zoom(); 8895 test_dialogmode(); 8896 test_EM_FINDWORDBREAK_W(); 8897 test_EM_FINDWORDBREAK_A(); 8898 test_enter(); 8899 test_WM_CREATE(); 8900 test_reset_default_para_fmt(); 8901 test_EM_SETREADONLY(); 8902 test_EM_SETFONTSIZE(); 8903 test_alignment_style(); 8904 test_rtf(); 8905 test_background(); 8906 test_eop_char_fmt(); 8907 test_para_numbering(); 8908 8909 /* Set the environment variable WINETEST_RICHED20 to keep windows 8910 * responsive and open for 30 seconds. This is useful for debugging. 8911 */ 8912 if (getenv( "WINETEST_RICHED20" )) { 8913 keep_responsive(30); 8914 } 8915 8916 OleFlushClipboard(); 8917 ret = FreeLibrary(hmoduleRichEdit); 8918 ok(ret, "error: %d\n", (int) GetLastError()); 8919 } 8920