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 <assert.h>
25 #include <windef.h>
26 #include <winbase.h>
27 #include <wingdi.h>
28 #include <winuser.h>
29 #include <winnls.h>
30 #include <ole2.h>
31 #include <richedit.h>
32 #include <time.h>
33 #include <wine/test.h>
34
35 static CHAR string1[MAX_PATH], string2[MAX_PATH];
36
37 #define ok_w2(format, szString1, szString2) \
38 \
39 if (lstrcmpW(szString1, szString2) != 0) \
40 { \
41 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
42 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
43 ok(0, format, string1, string2); \
44 }
45
46 static HMODULE hmoduleRichEdit;
47
48 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
49 HWND hwnd;
50 hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
51 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
52 hmoduleRichEdit, NULL);
53 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
54 return hwnd;
55 }
56
57 static HWND new_richedit(HWND parent) {
58 return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
59 }
60
61 static void processPendingMessages(void)
62 {
63 MSG msg;
64 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
65 TranslateMessage(&msg);
66 DispatchMessage(&msg);
67 }
68 }
69
70 static void pressKeyWithModifier(HWND hwnd, BYTE mod_vk, BYTE vk)
71 {
72 BYTE mod_scan_code = MapVirtualKey(mod_vk, MAPVK_VK_TO_VSC);
73 BYTE scan_code = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
74 SetFocus(hwnd);
75 keybd_event(mod_vk, mod_scan_code, 0, 0);
76 keybd_event(vk, scan_code, 0, 0);
77 keybd_event(vk, scan_code, KEYEVENTF_KEYUP, 0);
78 keybd_event(mod_vk, mod_scan_code, KEYEVENTF_KEYUP, 0);
79 processPendingMessages();
80 }
81
82 static void simulate_typing_characters(HWND hwnd, const char* szChars)
83 {
84 int ret;
85
86 while (*szChars != '\0') {
87 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
88 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
89 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
90 SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
91 szChars++;
92 }
93 }
94
95 static const char haystack[] = "WINEWine wineWine wine WineWine";
96 /* ^0 ^10 ^20 ^30 */
97
98 struct find_s {
99 int start;
100 int end;
101 const char *needle;
102 int flags;
103 int expected_loc;
104 int _todo_wine;
105 };
106
107
108 struct find_s find_tests[] = {
109 /* Find in empty text */
110 {0, -1, "foo", FR_DOWN, -1, 0},
111 {0, -1, "foo", 0, -1, 0},
112 {0, -1, "", FR_DOWN, -1, 0},
113 {20, 5, "foo", FR_DOWN, -1, 0},
114 {5, 20, "foo", FR_DOWN, -1, 0}
115 };
116
117 struct find_s find_tests2[] = {
118 /* No-result find */
119 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
120 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
121
122 /* Subsequent finds */
123 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
124 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
125 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
126 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
127
128 /* Find backwards */
129 {19, 20, "Wine", FR_MATCHCASE, 13, 0},
130 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
131 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
132
133 /* Case-insensitive */
134 {1, 31, "wInE", FR_DOWN, 4, 0},
135 {1, 31, "Wine", FR_DOWN, 4, 0},
136
137 /* High-to-low ranges */
138 {20, 5, "Wine", FR_DOWN, -1, 0},
139 {2, 1, "Wine", FR_DOWN, -1, 0},
140 {30, 29, "Wine", FR_DOWN, -1, 0},
141 {20, 5, "Wine", 0, 13, 0},
142
143 /* Find nothing */
144 {5, 10, "", FR_DOWN, -1, 0},
145 {10, 5, "", FR_DOWN, -1, 0},
146 {0, -1, "", FR_DOWN, -1, 0},
147 {10, 5, "", 0, -1, 0},
148
149 /* Whole-word search */
150 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
151 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
152 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
153 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
154 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
155 {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
156 {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
157
158 /* Bad ranges */
159 {5, 200, "XXX", FR_DOWN, -1, 0},
160 {-20, 20, "Wine", FR_DOWN, -1, 0},
161 {-20, 20, "Wine", FR_DOWN, -1, 0},
162 {-15, -20, "Wine", FR_DOWN, -1, 0},
163 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
164
165 /* Check the case noted in bug 4479 where matches at end aren't recognized */
166 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
167 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
168 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
169 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
170 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
171
172 /* The backwards case of bug 4479; bounds look right
173 * Fails because backward find is wrong */
174 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
175 {0, 20, "WINE", FR_MATCHCASE, -1, 0},
176
177 {0, -1, "wineWine wine", 0, -1, 0},
178 };
179
180 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
181 int findloc;
182 FINDTEXT ft;
183 memset(&ft, 0, sizeof(ft));
184 ft.chrg.cpMin = f->start;
185 ft.chrg.cpMax = f->end;
186 ft.lpstrText = f->needle;
187 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
188 ok(findloc == f->expected_loc,
189 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
190 name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
191 }
192
193 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
194 int id) {
195 int findloc;
196 FINDTEXTEX ft;
197 int expected_end_loc;
198
199 memset(&ft, 0, sizeof(ft));
200 ft.chrg.cpMin = f->start;
201 ft.chrg.cpMax = f->end;
202 ft.lpstrText = f->needle;
203 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
204 ok(findloc == f->expected_loc,
205 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
206 name, id, f->needle, f->start, f->end, f->flags, findloc);
207 ok(ft.chrgText.cpMin == f->expected_loc,
208 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
209 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
210 expected_end_loc = ((f->expected_loc == -1) ? -1
211 : f->expected_loc + strlen(f->needle));
212 ok(ft.chrgText.cpMax == expected_end_loc,
213 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
214 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
215 }
216
217 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
218 int num_tests)
219 {
220 int i;
221
222 for (i = 0; i < num_tests; i++) {
223 if (find[i]._todo_wine) {
224 todo_wine {
225 check_EM_FINDTEXT(hwnd, name, &find[i], i);
226 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
227 }
228 } else {
229 check_EM_FINDTEXT(hwnd, name, &find[i], i);
230 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
231 }
232 }
233 }
234
235 static void test_EM_FINDTEXT(void)
236 {
237 HWND hwndRichEdit = new_richedit(NULL);
238 CHARFORMAT2 cf2;
239
240 /* Empty rich edit control */
241 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
242 sizeof(find_tests)/sizeof(struct find_s));
243
244 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
245
246 /* Haystack text */
247 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
248 sizeof(find_tests2)/sizeof(struct find_s));
249
250 /* Setting a format on an arbitrary range should have no effect in search
251 results. This tests correct offset reporting across runs. */
252 cf2.cbSize = sizeof(CHARFORMAT2);
253 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
254 (LPARAM) &cf2);
255 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
256 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
257 SendMessage(hwndRichEdit, EM_SETSEL, 6, 20);
258 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
259
260 /* Haystack text, again */
261 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2,
262 sizeof(find_tests2)/sizeof(struct find_s));
263
264 /* Yet another range */
265 cf2.dwMask = CFM_BOLD | cf2.dwMask;
266 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
267 SendMessage(hwndRichEdit, EM_SETSEL, 11, 15);
268 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
269
270 /* Haystack text, again */
271 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2,
272 sizeof(find_tests2)/sizeof(struct find_s));
273
274 DestroyWindow(hwndRichEdit);
275 }
276
277 static const struct getline_s {
278 int line;
279 size_t buffer_len;
280 const char *text;
281 } gl[] = {
282 {0, 10, "foo bar\r"},
283 {1, 10, "\r"},
284 {2, 10, "bar\r"},
285 {3, 10, "\r"},
286
287 /* Buffer smaller than line length */
288 {0, 2, "foo bar\r"},
289 {0, 1, "foo bar\r"},
290 {0, 0, "foo bar\r"}
291 };
292
293 static void test_EM_GETLINE(void)
294 {
295 int i;
296 HWND hwndRichEdit = new_richedit(NULL);
297 static const int nBuf = 1024;
298 char dest[1024], origdest[1024];
299 const char text[] = "foo bar\n"
300 "\n"
301 "bar\n";
302
303 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
304
305 memset(origdest, 0xBB, nBuf);
306 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
307 {
308 int nCopied;
309 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
310 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
311 memset(dest, 0xBB, nBuf);
312 *(WORD *) dest = gl[i].buffer_len;
313
314 /* EM_GETLINE appends a "\r\0" to the end of the line
315 * nCopied counts up to and including the '\r' */
316 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
317 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
318 expected_nCopied);
319 /* two special cases since a parameter is passed via dest */
320 if (gl[i].buffer_len == 0)
321 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
322 "buffer_len=0\n");
323 else if (gl[i].buffer_len == 1)
324 ok(dest[0] == gl[i].text[0] && !dest[1] &&
325 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
326 else
327 {
328 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
329 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
330 ok(!strncmp(dest + expected_bytes_written, origdest
331 + expected_bytes_written, nBuf - expected_bytes_written),
332 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
333 }
334 }
335
336 DestroyWindow(hwndRichEdit);
337 }
338
339 static void test_EM_LINELENGTH(void)
340 {
341 HWND hwndRichEdit = new_richedit(NULL);
342 const char * text =
343 "richedit1\r"
344 "richedit1\n"
345 "richedit1\r\n"
346 "richedit1";
347 int offset_test[10][2] = {
348 {0, 9},
349 {5, 9},
350 {10, 9},
351 {15, 9},
352 {20, 9},
353 {25, 9},
354 {30, 9},
355 {35, 9},
356 {40, 0},
357 {45, 0},
358 };
359 int i;
360 LRESULT result;
361
362 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
363
364 for (i = 0; i < 10; i++) {
365 result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
366 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
367 offset_test[i][0], result, offset_test[i][1]);
368 }
369
370 DestroyWindow(hwndRichEdit);
371 }
372
373 static int get_scroll_pos_y(HWND hwnd)
374 {
375 POINT p = {-1, -1};
376 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
377 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
378 return p.y;
379 }
380
381 static void move_cursor(HWND hwnd, long charindex)
382 {
383 CHARRANGE cr;
384 cr.cpMax = charindex;
385 cr.cpMin = charindex;
386 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
387 }
388
389 static void line_scroll(HWND hwnd, int amount)
390 {
391 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
392 }
393
394 static void test_EM_SCROLLCARET(void)
395 {
396 int prevY, curY;
397 HWND hwndRichEdit = new_richedit(NULL);
398 const char text[] = "aa\n"
399 "this is a long line of text that should be longer than the "
400 "control's width\n"
401 "cc\n"
402 "dd\n"
403 "ee\n"
404 "ff\n"
405 "gg\n"
406 "hh\n";
407
408 /* Can't verify this */
409 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
410
411 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
412
413 /* Caret above visible window */
414 line_scroll(hwndRichEdit, 3);
415 prevY = get_scroll_pos_y(hwndRichEdit);
416 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
417 curY = get_scroll_pos_y(hwndRichEdit);
418 ok(prevY != curY, "%d == %d\n", prevY, curY);
419
420 /* Caret below visible window */
421 move_cursor(hwndRichEdit, sizeof(text) - 1);
422 line_scroll(hwndRichEdit, -3);
423 prevY = get_scroll_pos_y(hwndRichEdit);
424 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
425 curY = get_scroll_pos_y(hwndRichEdit);
426 ok(prevY != curY, "%d == %d\n", prevY, curY);
427
428 /* Caret in visible window */
429 move_cursor(hwndRichEdit, sizeof(text) - 2);
430 prevY = get_scroll_pos_y(hwndRichEdit);
431 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
432 curY = get_scroll_pos_y(hwndRichEdit);
433 ok(prevY == curY, "%d != %d\n", prevY, curY);
434
435 /* Caret still in visible window */
436 line_scroll(hwndRichEdit, -1);
437 prevY = get_scroll_pos_y(hwndRichEdit);
438 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
439 curY = get_scroll_pos_y(hwndRichEdit);
440 ok(prevY == curY, "%d != %d\n", prevY, curY);
441
442 DestroyWindow(hwndRichEdit);
443 }
444
445 static void test_EM_POSFROMCHAR(void)
446 {
447 HWND hwndRichEdit = new_richedit(NULL);
448 int i;
449 LRESULT result;
450 unsigned int height = 0;
451 int xpos = 0;
452 static const char text[] = "aa\n"
453 "this is a long line of text that should be longer than the "
454 "control's width\n"
455 "cc\n"
456 "dd\n"
457 "ee\n"
458 "ff\n"
459 "gg\n"
460 "hh\n";
461
462 /* Fill the control to lines to ensure that most of them are offscreen */
463 for (i = 0; i < 50; i++)
464 {
465 /* Do not modify the string; it is exactly 16 characters long. */
466 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
467 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n");
468 }
469
470 /*
471 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
472 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
473 Richedit 3.0 accepts either of the above API conventions.
474 */
475
476 /* Testing Richedit 2.0 API format */
477
478 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
479 Since all lines are identical and drawn with the same font,
480 they should have the same height... right?
481 */
482 for (i = 0; i < 50; i++)
483 {
484 /* All the lines are 16 characters long */
485 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
486 if (i == 0)
487 {
488 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
489 todo_wine {
490 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
491 }
492 xpos = LOWORD(result);
493 }
494 else if (i == 1)
495 {
496 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result));
497 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
498 height = HIWORD(result);
499 }
500 else
501 {
502 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height);
503 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
504 }
505 }
506
507 /* Testing position at end of text */
508 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
509 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
510 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
511
512 /* Testing position way past end of text */
513 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
514 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
515 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
516
517 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
518 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
519 for (i = 0; i < 50; i++)
520 {
521 /* All the lines are 16 characters long */
522 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
523 ok((signed short)(HIWORD(result)) == (i - 1) * height,
524 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
525 (signed short)(HIWORD(result)), (i - 1) * height);
526 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
527 }
528
529 /* Testing position at end of text */
530 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
531 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
532 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
533
534 /* Testing position way past end of text */
535 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
536 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
537 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
538
539 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
540 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
541 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
542
543 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
544 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
545 todo_wine {
546 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
547 }
548 xpos = LOWORD(result);
549
550 SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
551 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
552 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
553 todo_wine {
554 /* Fails on builtin because horizontal scrollbar is not being shown */
555 ok((signed short)(LOWORD(result)) < xpos,
556 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
557 (signed short)(LOWORD(result)), xpos);
558 }
559 DestroyWindow(hwndRichEdit);
560 }
561
562 static void test_EM_SETCHARFORMAT(void)
563 {
564 HWND hwndRichEdit = new_richedit(NULL);
565 CHARFORMAT2 cf2;
566 int rc = 0;
567 int tested_effects[] = {
568 CFE_BOLD,
569 CFE_ITALIC,
570 CFE_UNDERLINE,
571 CFE_STRIKEOUT,
572 CFE_PROTECTED,
573 CFE_LINK,
574 CFE_SUBSCRIPT,
575 CFE_SUPERSCRIPT,
576 0
577 };
578 int i;
579 CHARRANGE cr;
580
581 /* Invalid flags, CHARFORMAT2 structure blanked out */
582 memset(&cf2, 0, sizeof(cf2));
583 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
584 (LPARAM) &cf2);
585 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
586
587 /* A valid flag, CHARFORMAT2 structure blanked out */
588 memset(&cf2, 0, sizeof(cf2));
589 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
590 (LPARAM) &cf2);
591 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
592
593 /* A valid flag, CHARFORMAT2 structure blanked out */
594 memset(&cf2, 0, sizeof(cf2));
595 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
596 (LPARAM) &cf2);
597 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
598
599 /* A valid flag, CHARFORMAT2 structure blanked out */
600 memset(&cf2, 0, sizeof(cf2));
601 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
602 (LPARAM) &cf2);
603 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
604
605 /* A valid flag, CHARFORMAT2 structure blanked out */
606 memset(&cf2, 0, sizeof(cf2));
607 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
608 (LPARAM) &cf2);
609 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
610
611 /* Invalid flags, CHARFORMAT2 structure minimally filled */
612 memset(&cf2, 0, sizeof(cf2));
613 cf2.cbSize = sizeof(CHARFORMAT2);
614 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
615 (LPARAM) &cf2);
616 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
617 rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
618 ok(rc == FALSE, "Should not be able to undo here.\n");
619 SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
620
621 /* A valid flag, CHARFORMAT2 structure minimally filled */
622 memset(&cf2, 0, sizeof(cf2));
623 cf2.cbSize = sizeof(CHARFORMAT2);
624 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
625 (LPARAM) &cf2);
626 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
627 rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
628 ok(rc == FALSE, "Should not be able to undo here.\n");
629 SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
630
631 /* A valid flag, CHARFORMAT2 structure minimally filled */
632 memset(&cf2, 0, sizeof(cf2));
633 cf2.cbSize = sizeof(CHARFORMAT2);
634 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
635 (LPARAM) &cf2);
636 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
637 rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
638 ok(rc == FALSE, "Should not be able to undo here.\n");
639 SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
640
641 /* A valid flag, CHARFORMAT2 structure minimally filled */
642 memset(&cf2, 0, sizeof(cf2));
643 cf2.cbSize = sizeof(CHARFORMAT2);
644 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
645 (LPARAM) &cf2);
646 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
647 rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
648 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n");
649 SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
650
651 /* A valid flag, CHARFORMAT2 structure minimally filled */
652 memset(&cf2, 0, sizeof(cf2));
653 cf2.cbSize = sizeof(CHARFORMAT2);
654 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
655 (LPARAM) &cf2);
656 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
657 rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
658 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n");
659 SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
660
661 cf2.cbSize = sizeof(CHARFORMAT2);
662 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
663 (LPARAM) &cf2);
664
665 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
666 cf2.cbSize = sizeof(CHARFORMAT2);
667 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
668 (LPARAM) &cf2);
669 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
670 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
671
672 /* wParam==0 is default char format, does not set modify */
673 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
674 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
675 ok(rc == 0, "Text marked as modified, expected not modified!\n");
676 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf2);
677 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
678 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
679 ok(rc == 0, "Text marked as modified, expected not modified!\n");
680
681 /* wParam==SCF_SELECTION sets modify if nonempty selection */
682 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
683 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
684 ok(rc == 0, "Text marked as modified, expected not modified!\n");
685 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
686 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
687 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
688 ok(rc == 0, "Text marked as modified, expected not modified!\n");
689
690 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
691 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
692 ok(rc == 0, "Text marked as modified, expected not modified!\n");
693 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
694 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
695 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
696 ok(rc == 0, "Text marked as modified, expected not modified!\n");
697 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
698 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
699 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
700 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
701 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
702
703 /* wParam==SCF_ALL sets modify regardless of whether text is present */
704 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
705 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
706 ok(rc == 0, "Text marked as modified, expected not modified!\n");
707 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
708 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
709 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
710 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
711
712 DestroyWindow(hwndRichEdit);
713
714 /* EM_GETCHARFORMAT tests */
715 for (i = 0; tested_effects[i]; i++)
716 {
717 hwndRichEdit = new_richedit(NULL);
718 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
719
720 /* Need to set a TrueType font to get consistent CFM_BOLD results */
721 memset(&cf2, 0, sizeof(CHARFORMAT2));
722 cf2.cbSize = sizeof(CHARFORMAT2);
723 cf2.dwMask = CFM_FACE|CFM_WEIGHT;
724 cf2.dwEffects = 0;
725 strcpy(cf2.szFaceName, "Courier New");
726 cf2.wWeight = FW_DONTCARE;
727 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf2);
728
729 memset(&cf2, 0, sizeof(CHARFORMAT2));
730 cf2.cbSize = sizeof(CHARFORMAT2);
731 SendMessage(hwndRichEdit, EM_SETSEL, 0, 4);
732 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
733 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
734 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
735 ||
736 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
737 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
738 ok((cf2.dwEffects & tested_effects[i]) == 0,
739 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
740
741 memset(&cf2, 0, sizeof(CHARFORMAT2));
742 cf2.cbSize = sizeof(CHARFORMAT2);
743 cf2.dwMask = tested_effects[i];
744 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
745 cf2.dwMask = CFM_SUPERSCRIPT;
746 cf2.dwEffects = tested_effects[i];
747 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
748 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
749
750 memset(&cf2, 0, sizeof(CHARFORMAT2));
751 cf2.cbSize = sizeof(CHARFORMAT2);
752 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
753 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
754 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
755 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
756 ||
757 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
758 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
759 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
760 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
761
762 memset(&cf2, 0, sizeof(CHARFORMAT2));
763 cf2.cbSize = sizeof(CHARFORMAT2);
764 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
765 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
766 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
767 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
768 ||
769 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
770 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
771 ok((cf2.dwEffects & tested_effects[i]) == 0,
772 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
773
774 memset(&cf2, 0, sizeof(CHARFORMAT2));
775 cf2.cbSize = sizeof(CHARFORMAT2);
776 SendMessage(hwndRichEdit, EM_SETSEL, 1, 3);
777 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
778 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
779 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
780 ||
781 (cf2.dwMask & tested_effects[i]) == 0),
782 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
783
784 DestroyWindow(hwndRichEdit);
785 }
786
787 for (i = 0; tested_effects[i]; i++)
788 {
789 hwndRichEdit = new_richedit(NULL);
790 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
791
792 /* Need to set a TrueType font to get consistent CFM_BOLD results */
793 memset(&cf2, 0, sizeof(CHARFORMAT2));
794 cf2.cbSize = sizeof(CHARFORMAT2);
795 cf2.dwMask = CFM_FACE|CFM_WEIGHT;
796 cf2.dwEffects = 0;
797 strcpy(cf2.szFaceName, "Courier New");
798 cf2.wWeight = FW_DONTCARE;
799 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf2);
800
801 memset(&cf2, 0, sizeof(CHARFORMAT2));
802 cf2.cbSize = sizeof(CHARFORMAT2);
803 cf2.dwMask = tested_effects[i];
804 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
805 cf2.dwMask = CFM_SUPERSCRIPT;
806 cf2.dwEffects = tested_effects[i];
807 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
808 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
809
810 memset(&cf2, 0, sizeof(CHARFORMAT2));
811 cf2.cbSize = sizeof(CHARFORMAT2);
812 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
813 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
814 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
815 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
816 ||
817 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
818 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
819 ok((cf2.dwEffects & tested_effects[i]) == 0,
820 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
821
822 memset(&cf2, 0, sizeof(CHARFORMAT2));
823 cf2.cbSize = sizeof(CHARFORMAT2);
824 SendMessage(hwndRichEdit, EM_SETSEL, 2, 4);
825 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
826 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
827 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
828 ||
829 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
830 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
831 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
832 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
833
834 memset(&cf2, 0, sizeof(CHARFORMAT2));
835 cf2.cbSize = sizeof(CHARFORMAT2);
836 SendMessage(hwndRichEdit, EM_SETSEL, 1, 3);
837 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
838 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
839 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
840 ||
841 (cf2.dwMask & tested_effects[i]) == 0),
842 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
843 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
844 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]);
845
846 DestroyWindow(hwndRichEdit);
847 }
848
849 /* Effects applied on an empty selection should take effect when selection is
850 replaced with text */
851 hwndRichEdit = new_richedit(NULL);
852 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
853 SendMessage(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
854
855 memset(&cf2, 0, sizeof(CHARFORMAT2));
856 cf2.cbSize = sizeof(CHARFORMAT2);
857 cf2.dwMask = CFM_BOLD;
858 cf2.dwEffects = CFE_BOLD;
859 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
860
861 /* Selection is now nonempty */
862 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
863
864 memset(&cf2, 0, sizeof(CHARFORMAT2));
865 cf2.cbSize = sizeof(CHARFORMAT2);
866 SendMessage(hwndRichEdit, EM_SETSEL, 2, 6);
867 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
868
869 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
870 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
871 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
872 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
873
874
875 /* Set two effects on an empty selection */
876 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
877 SendMessage(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
878
879 memset(&cf2, 0, sizeof(CHARFORMAT2));
880 cf2.cbSize = sizeof(CHARFORMAT2);
881 cf2.dwMask = CFM_BOLD;
882 cf2.dwEffects = CFE_BOLD;
883 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
884 cf2.dwMask = CFM_ITALIC;
885 cf2.dwEffects = CFE_ITALIC;
886 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
887
888 /* Selection is now nonempty */
889 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
890
891 memset(&cf2, 0, sizeof(CHARFORMAT2));
892 cf2.cbSize = sizeof(CHARFORMAT2);
893 SendMessage(hwndRichEdit, EM_SETSEL, 2, 6);
894 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
895
896 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)),
897 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC));
898 ok((cf2.dwEffects & (CFE_BOLD|CFE_ITALIC)) == (CFE_BOLD|CFE_ITALIC),
899 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC));
900
901 /* Setting the (empty) selection to exactly the same place as before should
902 NOT clear the insertion style! */
903 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
904 SendMessage(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
905
906 memset(&cf2, 0, sizeof(CHARFORMAT2));
907 cf2.cbSize = sizeof(CHARFORMAT2);
908 cf2.dwMask = CFM_BOLD;
909 cf2.dwEffects = CFE_BOLD;
910 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
911
912 /* Empty selection in same place, insert style should NOT be forgotten here. */
913 SendMessage(hwndRichEdit, EM_SETSEL, 2, 2);
914
915 /* Selection is now nonempty */
916 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
917
918 memset(&cf2, 0, sizeof(CHARFORMAT2));
919 cf2.cbSize = sizeof(CHARFORMAT2);
920 SendMessage(hwndRichEdit, EM_SETSEL, 2, 6);
921 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
922
923 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
924 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
925 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
926 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
927
928 /* Ditto with EM_EXSETSEL */
929 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
930 cr.cpMin = 2; cr.cpMax = 2;
931 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
932
933 memset(&cf2, 0, sizeof(CHARFORMAT2));
934 cf2.cbSize = sizeof(CHARFORMAT2);
935 cf2.dwMask = CFM_BOLD;
936 cf2.dwEffects = CFE_BOLD;
937 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
938
939 /* Empty selection in same place, insert style should NOT be forgotten here. */
940 cr.cpMin = 2; cr.cpMax = 2;
941 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
942
943 /* Selection is now nonempty */
944 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
945
946 memset(&cf2, 0, sizeof(CHARFORMAT2));
947 cf2.cbSize = sizeof(CHARFORMAT2);
948 cr.cpMin = 2; cr.cpMax = 6;
949 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
950 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2);
951
952 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
953 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
954 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
955 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
956
957 DestroyWindow(hwndRichEdit);
958 }
959
960 static void test_EM_SETTEXTMODE(void)
961 {
962 HWND hwndRichEdit = new_richedit(NULL);
963 CHARFORMAT2 cf2, cf2test;
964 CHARRANGE cr;
965 int rc = 0;
966
967 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
968 /*Insert text into the control*/
969
970 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
971
972 /*Attempt to change the control to plain text mode*/
973 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
974 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
975
976 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
977 If rich text is pasted, it should have the same formatting as the rest
978 of the text in the control*/
979
980 /*Italicize the text
981 *NOTE: If the default text was already italicized, the test will simply
982 reverse; in other words, it will copy a regular "wine" into a plain
983 text window that uses an italicized format*/
984 cf2.cbSize = sizeof(CHARFORMAT2);
985 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
986 (LPARAM) &cf2);
987
988 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
989 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
990
991 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
992 ok(rc == 0, "Text marked as modified, expected not modified!\n");
993
994 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
995 however, SCF_ALL has been implemented*/
996 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
997 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
998
999 rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1000 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
1001
1002 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
1003
1004 /*Select the string "wine"*/
1005 cr.cpMin = 0;
1006 cr.cpMax = 4;
1007 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1008
1009 /*Copy the italicized "wine" to the clipboard*/
1010 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1011
1012 /*Reset the formatting to default*/
1013 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
1014 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1015 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1016
1017 /*Clear the text in the control*/
1018 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
1019
1020 /*Switch to Plain Text Mode*/
1021 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
1022 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
1023
1024 /*Input "wine" again in normal format*/
1025 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
1026
1027 /*Paste the italicized "wine" into the control*/
1028 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1029
1030 /*Select a character from the first "wine" string*/
1031 cr.cpMin = 2;
1032 cr.cpMax = 3;
1033 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1034
1035 /*Retrieve its formatting*/
1036 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
1037 (LPARAM) &cf2);
1038
1039 /*Select a character from the second "wine" string*/
1040 cr.cpMin = 5;
1041 cr.cpMax = 6;
1042 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1043
1044 /*Retrieve its formatting*/
1045 cf2test.cbSize = sizeof(CHARFORMAT2);
1046 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
1047 (LPARAM) &cf2test);
1048
1049 /*Compare the two formattings*/
1050 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1051 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1052 cf2.dwEffects, cf2test.dwEffects);
1053 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1054 printing "wine" in the current format(normal)
1055 pasting "wine" from the clipboard(italicized)
1056 comparing the two formats(should differ)*/
1057
1058 /*Attempt to switch with text in control*/
1059 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
1060 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
1061
1062 /*Clear control*/
1063 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
1064
1065 /*Switch into Rich Text mode*/
1066 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
1067 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
1068
1069 /*Print "wine" in normal formatting into the control*/
1070 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
1071
1072 /*Paste italicized "wine" into the control*/
1073 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1074
1075 /*Select text from the first "wine" string*/
1076 cr.cpMin = 1;
1077 cr.cpMax = 3;
1078 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1079
1080 /*Retrieve its formatting*/
1081 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
1082 (LPARAM) &cf2);
1083
1084 /*Select text from the second "wine" string*/
1085 cr.cpMin = 6;
1086 cr.cpMax = 7;
1087 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1088
1089 /*Retrieve its formatting*/
1090 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
1091 (LPARAM) &cf2test);
1092
1093 /*Test that the two formattings are not the same*/
1094 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
1095 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1096 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1097
1098 DestroyWindow(hwndRichEdit);
1099 }
1100
1101 static void test_SETPARAFORMAT(void)
1102 {
1103 HWND hwndRichEdit = new_richedit(NULL);
1104 PARAFORMAT2 fmt;
1105 HRESULT ret;
1106 fmt.cbSize = sizeof(PARAFORMAT2);
1107 fmt.dwMask = PFM_ALIGNMENT;
1108 fmt.wAlignment = PFA_LEFT;
1109
1110 ret = SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &fmt);
1111 ok(ret != 0, "expected non-zero got %d\n", ret);
1112
1113 fmt.cbSize = sizeof(PARAFORMAT2);
1114 fmt.dwMask = -1;
1115 ret = SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM) &fmt);
1116 ok(ret == PFM_ALL2, "expected %x got %x\n", PFM_ALL2, ret);
1117 ok(fmt.dwMask == PFM_ALL2, "expected %x got %x\n", PFM_ALL2, fmt.dwMask);
1118
1119 DestroyWindow(hwndRichEdit);
1120 }
1121
1122 static void test_TM_PLAINTEXT(void)
1123 {
1124 /*Tests plain text properties*/
1125
1126 HWND hwndRichEdit = new_richedit(NULL);
1127 CHARFORMAT2 cf2, cf2test;
1128 CHARRANGE cr;
1129 int rc = 0;
1130
1131 /*Switch to plain text mode*/
1132
1133 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
1134 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
1135
1136 /*Fill control with text*/
1137
1138 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
1139
1140 /*Select some text and bold it*/
1141
1142 cr.cpMin = 10;
1143 cr.cpMax = 20;
1144 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1145 cf2.cbSize = sizeof(CHARFORMAT2);
1146 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1147 (LPARAM) &cf2);
1148
1149 cf2.dwMask = CFM_BOLD | cf2.dwMask;
1150 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
1151
1152 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
1153 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1154
1155 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD | SCF_SELECTION, (LPARAM) &cf2);
1156 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1157
1158 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM)&cf2);
1159 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1160
1161 /*Get the formatting of those characters*/
1162
1163 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
1164
1165 /*Get the formatting of some other characters*/
1166 cf2test.cbSize = sizeof(CHARFORMAT2);
1167 cr.cpMin = 21;
1168 cr.cpMax = 30;
1169 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1170 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
1171
1172 /*Test that they are the same as plain text allows only one formatting*/
1173
1174 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1175 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1176 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1177
1178 /*Fill the control with a "wine" string, which when inserted will be bold*/
1179
1180 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
1181
1182 /*Copy the bolded "wine" string*/
1183
1184 cr.cpMin = 0;
1185 cr.cpMax = 4;
1186 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1187 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1188
1189 /*Swap back to rich text*/
1190
1191 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
1192 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
1193
1194 /*Set the default formatting to bold italics*/
1195
1196 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
1197 cf2.dwMask |= CFM_ITALIC;
1198 cf2.dwEffects ^= CFE_ITALIC;
1199 rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1200 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1201
1202 /*Set the text in the control to "wine", which will be bold and italicized*/
1203
1204 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
1205
1206 /*Paste the plain text "wine" string, which should take the insert
1207 formatting, which at the moment is bold italics*/
1208
1209 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1210
1211 /*Select the first "wine" string and retrieve its formatting*/
1212
1213 cr.cpMin = 1;
1214 cr.cpMax = 3;
1215 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1216 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
1217
1218 /*Select the second "wine" string and retrieve its formatting*/
1219
1220 cr.cpMin = 5;
1221 cr.cpMax = 7;
1222 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1223 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
1224
1225 /*Compare the two formattings. They should be the same.*/
1226
1227 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1228 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1229 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1230 DestroyWindow(hwndRichEdit);
1231 }
1232
1233 static void test_WM_GETTEXT(void)
1234 {
1235 HWND hwndRichEdit = new_richedit(NULL);
1236 static const char text[] = "Hello. My name is RichEdit!";
1237 static const char text2[] = "Hello. My name is RichEdit!\r";
1238 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
1239 char buffer[1024] = {0};
1240 int result;
1241
1242 /* Baseline test with normal-sized buffer */
1243 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1244 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1245 ok(result == lstrlen(buffer),
1246 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
1247 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1248 result = strcmp(buffer,text);
1249 ok(result == 0,
1250 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1251
1252 /* Test for returned value of WM_GETTEXTLENGTH */
1253 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1254 ok(result == lstrlen(text),
1255 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1256 result, lstrlen(text));
1257
1258 /* Test for behavior in overflow case */
1259 memset(buffer, 0, 1024);
1260 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
1261 ok(result == 0 ||
1262 result == lstrlenA(text) - 1, /* XP, win2k3 */
1263 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
1264 result = strcmp(buffer,text);
1265 if (result)
1266 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
1267 ok(result == 0,
1268 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1269
1270 /* Baseline test with normal-sized buffer and carriage return */
1271 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
1272 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1273 ok(result == lstrlen(buffer),
1274 "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
1275 result = strcmp(buffer,text2_after);
1276 ok(result == 0,
1277 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1278
1279 /* Test for returned value of WM_GETTEXTLENGTH */
1280 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1281 ok(result == lstrlen(text2_after),
1282 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1283 result, lstrlen(text2_after));
1284
1285 /* Test for behavior of CRLF conversion in case of overflow */
1286 memset(buffer, 0, 1024);
1287 result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
1288 ok(result == 0 ||
1289 result == lstrlenA(text2) - 1, /* XP, win2k3 */
1290 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
1291 result = strcmp(buffer,text2);
1292 if (result)
1293 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
1294 ok(result == 0,
1295 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1296
1297 DestroyWindow(hwndRichEdit);
1298 }
1299
1300 static void test_EM_GETTEXTRANGE(void)
1301 {
1302 HWND hwndRichEdit = new_richedit(NULL);
1303 const char * text1 = "foo bar\r\nfoo bar";
1304 const char * text2 = "foo bar\rfoo bar";
1305 const char * expect = "bar\rfoo";
1306 char buffer[1024] = {0};
1307 LRESULT result;
1308 TEXTRANGEA textRange;
1309
1310 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1311
1312 textRange.lpstrText = buffer;
1313 textRange.chrg.cpMin = 4;
1314 textRange.chrg.cpMax = 11;
1315 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1316 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1317 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1318
1319 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1320
1321 textRange.lpstrText = buffer;
1322 textRange.chrg.cpMin = 4;
1323 textRange.chrg.cpMax = 11;
1324 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1325 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1326 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1327
1328 DestroyWindow(hwndRichEdit);
1329 }
1330
1331 static void test_EM_GETSELTEXT(void)
1332 {
1333 HWND hwndRichEdit = new_richedit(NULL);
1334 const char * text1 = "foo bar\r\nfoo bar";
1335 const char * text2 = "foo bar\rfoo bar";
1336 const char * expect = "bar\rfoo";
1337 char buffer[1024] = {0};
1338 LRESULT result;
1339
1340 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1341
1342 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
1343 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1344 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1345 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1346
1347 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1348
1349 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
1350 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1351 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1352 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1353
1354 DestroyWindow(hwndRichEdit);
1355 }
1356
1357 /* FIXME: need to test unimplemented options and robustly test wparam */
1358 static void test_EM_SETOPTIONS(void)
1359 {
1360 HWND hwndRichEdit = new_richedit(NULL);
1361 static const char text[] = "Hello. My name is RichEdit!";
1362 char buffer[1024] = {0};
1363
1364 /* NEGATIVE TESTING - NO OPTIONS SET */
1365 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1366 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
1367
1368 /* testing no readonly by sending 'a' to the control*/
1369 SetFocus(hwndRichEdit);
1370 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1371 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1372 ok(buffer[0]=='a',
1373 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
1374 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1375
1376 /* READONLY - sending 'a' to the control */
1377 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1378 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
1379 SetFocus(hwndRichEdit);
1380 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1381 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1382 ok(buffer[0]==text[0],
1383 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1384
1385 DestroyWindow(hwndRichEdit);
1386 }
1387
1388 static int check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
1389 {
1390 CHARFORMAT2W text_format;
1391 text_format.cbSize = sizeof(text_format);
1392 SendMessage(hwnd, EM_SETSEL, sel_start, sel_end);
1393 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
1394 return (text_format.dwEffects & CFE_LINK) ? 1 : 0;
1395 }
1396
1397 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url, const char * url)
1398 {
1399 int link_present = 0;
1400
1401 link_present = check_CFE_LINK_selection(hwnd, 0, 1);
1402 if (is_url)
1403 { /* control text is url; should get CFE_LINK */
1404 ok(0 != link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
1405 }
1406 else
1407 {
1408 ok(0 == link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
1409 }
1410 }
1411
1412 static HWND new_static_wnd(HWND parent) {
1413 return new_window("Static", 0, parent);
1414 }
1415
1416 static void test_EM_AUTOURLDETECT(void)
1417 {
1418 /* DO NOT change the properties of the first two elements. To shorten the
1419 tests, all tests after WM_SETTEXT test just the first two elements -
1420 one non-URL and one URL */
1421 struct urls_s {
1422 const char *text;
1423 int is_url;
1424 } urls[12] = {
1425 {"winehq.org", 0},
1426 {"http://www.winehq.org", 1},
1427 {"http//winehq.org", 0},
1428 {"ww.winehq.org", 0},
1429 {"www.winehq.org", 1},
1430 {"ftp://192.168.1.1", 1},
1431 {"ftp//192.168.1.1", 0},
1432 {"mailto:your@email.com", 1},
1433 {"prospero:prosperoserver", 1},
1434 {"telnet:test", 1},
1435 {"news:newserver", 1},
1436 {"wais:waisserver", 1}
1437 };
1438
1439 int i, j;
1440 int urlRet=-1;
1441 HWND hwndRichEdit, parent;
1442
1443 /* All of the following should cause the URL to be detected */
1444 const char * templates_delim[] = {
1445 "This is some text with X on it",
1446 "This is some text with (X) on it",
1447 "This is some text with X\r on it",
1448 "This is some text with ---X--- on it",
1449 "This is some text with \"X\" on it",
1450 "This is some text with 'X' on it",
1451 "This is some text with 'X' on it",
1452 "This is some text with :X: on it",
1453
1454 "This text ends with X",
1455
1456 "This is some text with X) on it",
1457 "This is some text with X--- on it",
1458 "This is some text with X\" on it",
1459 "This is some text with X' on it",
1460 "This is some text with X: on it",
1461
1462 "This is some text with (X on it",
1463 "This is some text with \rX on it",
1464 "This is some text with ---X on it",
1465 "This is some text with \"X on it",
1466 "This is some text with 'X on it",
1467 "This is some text with :X on it",
1468 };
1469 /* None of these should cause the URL to be detected */
1470 const char * templates_non_delim[] = {
1471 "This is some text with |X| on it",
1472 "This is some text with *X* on it",
1473 "This is some text with /X/ on it",
1474 "This is some text with +X+ on it",
1475 "This is some text with %X% on it",
1476 "This is some text with #X# on it",
1477 "This is some text with @X@ on it",
1478 "This is some text with \\X\\ on it",
1479 "This is some text with |X on it",
1480 "This is some text with *X on it",
1481 "This is some text with /X on it",
1482 "This is some text with +X on it",
1483 "This is some text with %X on it",
1484 "This is some text with #X on it",
1485 "This is some text with @X on it",
1486 "This is some text with \\X on it",
1487 };
1488 /* All of these cause the URL detection to be extended by one more byte,
1489 thus demonstrating that the tested character is considered as part
1490 of the URL. */
1491 const char * templates_xten_delim[] = {
1492 "This is some text with X| on it",
1493 "This is some text with X* on it",
1494 "This is some text with X/ on it",
1495 "This is some text with X+ on it",
1496 "This is some text with X% on it",
1497 "This is some text with X# on it",
1498 "This is some text with X@ on it",
1499 "This is some text with X\\ on it",
1500 };
1501 char buffer[1024];
1502
1503 parent = new_static_wnd(NULL);
1504 hwndRichEdit = new_richedit(parent);
1505 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1506 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
1507 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
1508 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
1509 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
1510 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1511 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
1512 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
1513 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
1514 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
1515 /* for each url, check the text to see if CFE_LINK effect is present */
1516 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1517
1518 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
1519 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
1520 check_CFE_LINK_rcvd(hwndRichEdit, 0, urls[i].text);
1521
1522 /* Link detection should happen immediately upon WM_SETTEXT */
1523 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1524 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
1525 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
1526 }
1527 DestroyWindow(hwndRichEdit);
1528
1529 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1530 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
1531 hwndRichEdit = new_richedit(parent);
1532
1533 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1534 char * at_pos;
1535 int at_offset;
1536 int end_offset;
1537
1538 at_pos = strchr(templates_delim[j], 'X');
1539 at_offset = at_pos - templates_delim[j];
1540 strncpy(buffer, templates_delim[j], at_offset);
1541 buffer[at_offset] = '\0';
1542 strcat(buffer, urls[i].text);
1543 strcat(buffer, templates_delim[j] + at_offset + 1);
1544 end_offset = at_offset + strlen(urls[i].text);
1545
1546 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1547 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1548
1549 /* This assumes no templates start with the URL itself, and that they
1550 have at least two characters before the URL text */
1551 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1552 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1553 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1554 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1555 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1556 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1557
1558 if (urls[i].is_url)
1559 {
1560 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1561 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1562 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1563 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1564 }
1565 else
1566 {
1567 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1568 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1569 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1570 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1571 }
1572 if (buffer[end_offset] != '\0')
1573 {
1574 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1575 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1576 if (buffer[end_offset +1] != '\0')
1577 {
1578 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1579 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1580 }
1581 }
1582 }
1583
1584 for (j = 0; j < sizeof(templates_non_delim) / sizeof(const char *); j++) {
1585 char * at_pos;
1586 int at_offset;
1587 int end_offset;
1588
1589 at_pos = strchr(templates_non_delim[j], 'X');
1590 at_offset = at_pos - templates_non_delim[j];
1591 strncpy(buffer, templates_non_delim[j], at_offset);
1592 buffer[at_offset] = '\0';
1593 strcat(buffer, urls[i].text);
1594 strcat(buffer, templates_non_delim[j] + at_offset + 1);
1595 end_offset = at_offset + strlen(urls[i].text);
1596
1597 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1598 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1599
1600 /* This assumes no templates start with the URL itself, and that they
1601 have at least two characters before the URL text */
1602 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1603 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1604 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1605 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1606 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1607 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1608
1609 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1610 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1611 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1612 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1613 if (buffer[end_offset] != '\0')
1614 {
1615 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1616 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1617 if (buffer[end_offset +1] != '\0')
1618 {
1619 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1620 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1621 }
1622 }
1623 }
1624
1625 for (j = 0; j < sizeof(templates_xten_delim) / sizeof(const char *); j++) {
1626 char * at_pos;
1627 int at_offset;
1628 int end_offset;
1629
1630 at_pos = strchr(templates_xten_delim[j], 'X');
1631 at_offset = at_pos - templates_xten_delim[j];
1632 strncpy(buffer, templates_xten_delim[j], at_offset);
1633 buffer[at_offset] = '\0';
1634 strcat(buffer, urls[i].text);
1635 strcat(buffer, templates_xten_delim[j] + at_offset + 1);
1636 end_offset = at_offset + strlen(urls[i].text);
1637
1638 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1639 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) buffer);
1640
1641 /* This assumes no templates start with the URL itself, and that they
1642 have at least two characters before the URL text */
1643 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1644 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1645 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1646 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1647 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1648 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1649
1650 if (urls[i].is_url)
1651 {
1652 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1653 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1654 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1655 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1656 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1657 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
1658 }
1659 else
1660 {
1661 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1662 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1663 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1664 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1665 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1666 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
1667 }
1668 if (buffer[end_offset +1] != '\0')
1669 {
1670 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1671 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer);
1672 if (buffer[end_offset +2] != '\0')
1673 {
1674 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
1675 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
1676 }
1677 }
1678 }
1679
1680 DestroyWindow(hwndRichEdit);
1681 hwndRichEdit = NULL;
1682 }
1683
1684 /* Test detection of URLs within normal text - WM_CHAR case. */
1685 /* Test only the first two URL examples for brevity */
1686 for (i = 0; i < 2; i++) {
1687 hwndRichEdit = new_richedit(parent);
1688
1689 /* Also for brevity, test only the first three delimiters */
1690 for (j = 0; j < 3; j++) {
1691 char * at_pos;
1692 int at_offset;
1693 int end_offset;
1694 int u, v;
1695
1696 at_pos = strchr(templates_delim[j], 'X');
1697 at_offset = at_pos - templates_delim[j];
1698 end_offset = at_offset + strlen(urls[i].text);
1699
1700 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1701 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
1702 for (u = 0; templates_delim[j][u]; u++) {
1703 if (templates_delim[j][u] == '\r') {
1704 simulate_typing_characters(hwndRichEdit, "\r");
1705 } else if (templates_delim[j][u] != 'X') {
1706 SendMessage(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
1707 } else {
1708 for (v = 0; urls[i].text[v]; v++) {
1709 SendMessage(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
1710 }
1711 }
1712 }
1713 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1714
1715 /* This assumes no templates start with the URL itself, and that they
1716 have at least two characters before the URL text */
1717 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1718 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1719 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1720 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1721 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1722 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1723
1724 if (urls[i].is_url)
1725 {
1726 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1727 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1728 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1729 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1730 }
1731 else
1732 {
1733 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1734 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1735 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1736 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1737 }
1738 if (buffer[end_offset] != '\0')
1739 {
1740 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1741 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1742 if (buffer[end_offset +1] != '\0')
1743 {
1744 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1745 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1746 }
1747 }
1748
1749 /* The following will insert a paragraph break after the first character
1750 of the URL candidate, thus breaking the URL. It is expected that the
1751 CFE_LINK attribute should break across both pieces of the URL */
1752 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
1753 simulate_typing_characters(hwndRichEdit, "\r");
1754 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1755
1756 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1757 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1758 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1759 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1760 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1761 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1762
1763 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1764 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1765 /* end_offset moved because of paragraph break */
1766 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1767 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
1768 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer);
1769 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0')
1770 {
1771 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
1772 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
1773 if (buffer[end_offset +2] != '\0')
1774 {
1775 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
1776 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
1777 }
1778 }
1779
1780 /* The following will remove the just-inserted paragraph break, thus
1781 restoring the URL */
1782 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
1783 simulate_typing_characters(hwndRichEdit, "\b");
1784 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1785
1786 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1787 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1788 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1789 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1790 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1791 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1792
1793 if (urls[i].is_url)
1794 {
1795 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1796 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1797 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1798 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1799 }
1800 else
1801 {
1802 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1803 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1804 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1805 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1806 }
1807 if (buffer[end_offset] != '\0')
1808 {
1809 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1810 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1811 if (buffer[end_offset +1] != '\0')
1812 {
1813 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1814 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1815 }
1816 }
1817 }
1818 DestroyWindow(hwndRichEdit);
1819 hwndRichEdit = NULL;
1820 }
1821
1822 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
1823 /* Test just the first two URL examples for brevity */
1824 for (i = 0; i < 2; i++) {
1825 SETTEXTEX st;
1826
1827 hwndRichEdit = new_richedit(parent);
1828
1829 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
1830 be detected:
1831 1) Set entire text, a la WM_SETTEXT
1832 2) Set a selection of the text to the URL
1833 3) Set a portion of the text at a time, which eventually results in
1834 an URL
1835 All of them should give equivalent results
1836 */
1837
1838 /* Set entire text in one go, like WM_SETTEXT */
1839 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1840 char * at_pos;
1841 int at_offset;
1842 int end_offset;
1843
1844 st.codepage = CP_ACP;
1845 st.flags = ST_DEFAULT;
1846
1847 at_pos = strchr(templates_delim[j], 'X');
1848 at_offset = at_pos - templates_delim[j];
1849 strncpy(buffer, templates_delim[j], at_offset);
1850 buffer[at_offset] = '\0';
1851 strcat(buffer, urls[i].text);
1852 strcat(buffer, templates_delim[j] + at_offset + 1);
1853 end_offset = at_offset + strlen(urls[i].text);
1854
1855 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1856 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) buffer);
1857
1858 /* This assumes no templates start with the URL itself, and that they
1859 have at least two characters before the URL text */
1860 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1861 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1862 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1863 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1864 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1865 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1866
1867 if (urls[i].is_url)
1868 {
1869 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1870 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1871 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1872 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1873 }
1874 else
1875 {
1876 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1877 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1878 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1879 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1880 }
1881 if (buffer[end_offset] != '\0')
1882 {
1883 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1884 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1885 if (buffer[end_offset +1] != '\0')
1886 {
1887 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1888 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1889 }
1890 }
1891 }
1892
1893 /* Set selection with X to the URL */
1894 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1895 char * at_pos;
1896 int at_offset;
1897 int end_offset;
1898
1899 at_pos = strchr(templates_delim[j], 'X');
1900 at_offset = at_pos - templates_delim[j];
1901 end_offset = at_offset + strlen(urls[i].text);
1902
1903 st.codepage = CP_ACP;
1904 st.flags = ST_DEFAULT;
1905 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1906 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) templates_delim[j]);
1907 st.flags = ST_SELECTION;
1908 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
1909 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) urls[i].text);
1910 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1911
1912 /* This assumes no templates start with the URL itself, and that they
1913 have at least two characters before the URL text */
1914 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1915 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1916 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1917 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1918 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1919 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1920
1921 if (urls[i].is_url)
1922 {
1923 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1924 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1925 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1926 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1927 }
1928 else
1929 {
1930 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1931 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1932 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1933 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1934 }
1935 if (buffer[end_offset] != '\0')
1936 {
1937 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1938 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1939 if (buffer[end_offset +1] != '\0')
1940 {
1941 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
1942 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
1943 }
1944 }
1945 }
1946
1947 /* Set selection with X to the first character of the URL, then the rest */
1948 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
1949 char * at_pos;
1950 int at_offset;
1951 int end_offset;
1952
1953 at_pos = strchr(templates_delim[j], 'X');
1954 at_offset = at_pos - templates_delim[j];
1955 end_offset = at_offset + strlen(urls[i].text);
1956
1957 strcpy(buffer, "YY");
1958 buffer[0] = urls[i].text[0];
1959
1960 st.codepage = CP_ACP;
1961 st.flags = ST_DEFAULT;
1962 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
1963 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) templates_delim[j]);
1964 st.flags = ST_SELECTION;
1965 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
1966 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM) buffer);
1967 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
1968 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1));
1969 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1970
1971 /* This assumes no templates start with the URL itself, and that they
1972 have at least two characters before the URL text */
1973 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
1974 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
1975 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
1976 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
1977 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
1978 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
1979
1980 if (urls[i].is_url)
1981 {
1982 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1983 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
1984 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1985 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1986 }
1987 else
1988 {
1989 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
1990 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
1991 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
1992 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
1993 }
1994 if (buffer[end_offset] != '\0')
1995 {
1996 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
1997 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
1998 if (buffer[end_offset +1] != '\0')
1999 {
2000 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2001 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2002 }
2003 }
2004 }
2005
2006 DestroyWindow(hwndRichEdit);
2007 hwndRichEdit = NULL;
2008 }
2009
2010 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2011 /* Test just the first two URL examples for brevity */
2012 for (i = 0; i < 2; i++) {
2013 hwndRichEdit = new_richedit(parent);
2014
2015 /* Set selection with X to the URL */
2016 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
2017 char * at_pos;
2018 int at_offset;
2019 int end_offset;
2020
2021 at_pos = strchr(templates_delim[j], 'X');
2022 at_offset = at_pos - templates_delim[j];
2023 end_offset = at_offset + strlen(urls[i].text);
2024
2025 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2026 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) templates_delim[j]);
2027 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2028 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) urls[i].text);
2029 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2030
2031 /* This assumes no templates start with the URL itself, and that they
2032 have at least two characters before the URL text */
2033 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2034 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2035 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2036 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2037 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2038 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2039
2040 if (urls[i].is_url)
2041 {
2042 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2043 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2044 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2045 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2046 }
2047 else
2048 {
2049 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2050 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2051 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2052 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2053 }
2054 if (buffer[end_offset] != '\0')
2055 {
2056 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2057 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2058 if (buffer[end_offset +1] != '\0')
2059 {
2060 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2061 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2062 }
2063 }
2064 }
2065
2066 /* Set selection with X to the first character of the URL, then the rest */
2067 for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
2068 char * at_pos;
2069 int at_offset;
2070 int end_offset;
2071
2072 at_pos = strchr(templates_delim[j], 'X');
2073 at_offset = at_pos - templates_delim[j];
2074 end_offset = at_offset + strlen(urls[i].text);
2075
2076 strcpy(buffer, "YY");
2077 buffer[0] = urls[i].text[0];
2078
2079 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2080 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) templates_delim[j]);
2081 SendMessage(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2082 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) buffer);
2083 SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2084 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1));
2085 SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2086
2087 /* This assumes no templates start with the URL itself, and that they
2088 have at least two characters before the URL text */
2089 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2090 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2091 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2092 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2093 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2094 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2095
2096 if (urls[i].is_url)
2097 {
2098 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2099 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2100 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2101 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2102 }
2103 else
2104 {
2105 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2106 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2107 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2108 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2109 }
2110 if (buffer[end_offset] != '\0')
2111 {
2112 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2113 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2114 if (buffer[end_offset +1] != '\0')
2115 {
2116 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2117 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2118 }
2119 }
2120 }
2121
2122 DestroyWindow(hwndRichEdit);
2123 hwndRichEdit = NULL;
2124 }
2125
2126 DestroyWindow(parent);
2127 }
2128
2129 static void test_EM_SCROLL(void)
2130 {
2131 int i, j;
2132 int r; /* return value */
2133 int expr; /* expected return value */
2134 HWND hwndRichEdit = new_richedit(NULL);
2135 int y_before, y_after; /* units of lines of text */
2136
2137 /* test a richedit box containing a single line of text */
2138 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
2139 expr = 0x00010000;
2140 for (i = 0; i < 4; i++) {
2141 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
2142
2143 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
2144 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2145 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
2146 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
2147 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2148 "(i == %d)\n", y_after, i);
2149 }
2150
2151 /*
2152 * test a richedit box that will scroll. There are two general
2153 * cases: the case without any long lines and the case with a long
2154 * line.
2155 */
2156 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
2157 if (i == 0)
2158 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
2159 else
2160 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
2161 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2162 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2163 "LONG LINE \nb\nc\nd\ne");
2164 for (j = 0; j < 12; j++) /* reset scroll position to top */
2165 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
2166
2167 /* get first visible line */
2168 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2169 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
2170
2171 /* get new current first visible line */
2172 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2173
2174 ok(((r & 0xffffff00) == 0x00010000) &&
2175 ((r & 0x000000ff) != 0x00000000),
2176 "EM_SCROLL page down didn't scroll by a small positive number of "
2177 "lines (r == 0x%08x)\n", r);
2178 ok(y_after > y_before, "EM_SCROLL page down not functioning "
2179 "(line %d scrolled to line %d\n", y_before, y_after);
2180
2181 y_before = y_after;
2182
2183 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
2184 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2185 ok(((r & 0xffffff00) == 0x0001ff00),
2186 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2187 "(r == 0x%08x)\n", r);
2188 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
2189 "%d scrolled to line %d\n", y_before, y_after);
2190
2191 y_before = y_after;
2192
2193 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
2194
2195 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2196
2197 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2198 "(r == 0x%08x)\n", r);
2199 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
2200 "1 line (%d scrolled to %d)\n", y_before, y_after);
2201
2202 y_before = y_after;
2203
2204 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
2205
2206 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2207
2208 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2209 "(r == 0x%08x)\n", r);
2210 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
2211 "line (%d scrolled to %d)\n", y_before, y_after);
2212
2213 y_before = y_after;
2214
2215 r = SendMessage(hwndRichEdit, EM_SCROLL,
2216 SB_LINEUP, 0); /* lineup beyond top */
2217
2218 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2219
2220 ok(r == 0x00010000,
2221 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
2222 ok(y_before == y_after,
2223 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
2224
2225 y_before = y_after;
2226
2227 r = SendMessage(hwndRichEdit, EM_SCROLL,
2228 SB_PAGEUP, 0);/*page up beyond top */
2229
2230 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2231
2232 ok(r == 0x00010000,
2233 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
2234 ok(y_before == y_after,
2235 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
2236
2237 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
2238 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
2239 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2240 r = SendMessage(hwndRichEdit, EM_SCROLL,
2241 SB_PAGEDOWN, 0); /* page down beyond bot */
2242 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2243
2244 ok(r == 0x00010000,
2245 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
2246 ok(y_before == y_after,
2247 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2248 y_before, y_after);
2249
2250 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2251 SendMessage(hwndRichEdit, EM_SCROLL,
2252 SB_LINEDOWN, 0); /* line down beyond bot */
2253 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2254
2255 ok(r == 0x00010000,
2256 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
2257 ok(y_before == y_after,
2258 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2259 y_before, y_after);
2260 }
2261 DestroyWindow(hwndRichEdit);
2262 }
2263
2264 unsigned int recursionLevel = 0;
2265 unsigned int WM_SIZE_recursionLevel = 0;
2266 BOOL bailedOutOfRecursion = FALSE;
2267 LRESULT WINAPI (*richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
2268
2269 static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2270 {
2271 LRESULT r;
2272
2273 if (bailedOutOfRecursion) return 0;
2274 if (recursionLevel >= 32) {
2275 bailedOutOfRecursion = TRUE;
2276 return 0;
2277 }
2278
2279 recursionLevel++;
2280 switch (message) {
2281 case WM_SIZE:
2282 WM_SIZE_recursionLevel++;
2283 r = richeditProc(hwnd, message, wParam, lParam);
2284 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2285 ShowScrollBar(hwnd, SB_VERT, TRUE);
2286 WM_SIZE_recursionLevel--;
2287 break;
2288 default:
2289 r = richeditProc(hwnd, message, wParam, lParam);
2290 break;
2291 }
2292 recursionLevel--;
2293 return r;
2294 }
2295
2296 static void test_scrollbar_visibility(void)
2297 {
2298 HWND hwndRichEdit;
2299 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2300 SCROLLINFO si;
2301 WNDCLASSA cls;
2302 BOOL r;
2303
2304 /* These tests show that richedit should temporarily refrain from automatically
2305 hiding or showing its scrollbars (vertical at least) when an explicit request
2306 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2307 Some applications depend on forced showing (when otherwise richedit would
2308 hide the vertical scrollbar) and are thrown on an endless recursive loop
2309 if richedit auto-hides the scrollbar again. Apparently they never heard of
2310 the ES_DISABLENOSCROLL style... */
2311
2312 hwndRichEdit = new_richedit(NULL);
2313
2314 /* Test default scrollbar visibility behavior */
2315 memset(&si, 0, sizeof(si));
2316 si.cbSize = sizeof(si);
2317 si.fMask = SIF_PAGE | SIF_RANGE;
2318 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2319 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2320 "Vertical scrollbar is visible, should be invisible.\n");
2321 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2322 "reported page/range is %d (%d..%d) expected all 0\n",
2323 si.nPage, si.nMin, si.nMax);
2324
2325 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2326 memset(&si, 0, sizeof(si));
2327 si.cbSize = sizeof(si);
2328 si.fMask = SIF_PAGE | SIF_RANGE;
2329 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2330 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2331 "Vertical scrollbar is visible, should be invisible.\n");
2332 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2333 "reported page/range is %d (%d..%d) expected all 0\n",
2334 si.nPage, si.nMin, si.nMax);
2335
2336 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2337 memset(&si, 0, sizeof(si));
2338 si.cbSize = sizeof(si);
2339 si.fMask = SIF_PAGE | SIF_RANGE;
2340 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2341 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2342 "Vertical scrollbar is invisible, should be visible.\n");
2343 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2344 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2345 si.nPage, si.nMin, si.nMax);
2346
2347 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2348 even though it hides the scrollbar */
2349 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2350 memset(&si, 0, sizeof(si));
2351 si.cbSize = sizeof(si);
2352 si.fMask = SIF_PAGE | SIF_RANGE;
2353 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2354 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2355 "Vertical scrollbar is visible, should be invisible.\n");
2356 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2357 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2358 si.nPage, si.nMin, si.nMax);
2359
2360 /* Setting non-scrolling text again does *not* reset scrollbar range */
2361 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2362 memset(&si, 0, sizeof(si));
2363 si.cbSize = sizeof(si);
2364 si.fMask = SIF_PAGE | SIF_RANGE;
2365 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2366 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2367 "Vertical scrollbar is visible, should be invisible.\n");
2368 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2369 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2370 si.nPage, si.nMin, si.nMax);
2371
2372 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2373 memset(&si, 0, sizeof(si));
2374 si.cbSize = sizeof(si);
2375 si.fMask = SIF_PAGE | SIF_RANGE;
2376 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2377 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2378 "Vertical scrollbar is visible, should be invisible.\n");
2379 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2380 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2381 si.nPage, si.nMin, si.nMax);
2382
2383 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2384 memset(&si, 0, sizeof(si));
2385 si.cbSize = sizeof(si);
2386 si.fMask = SIF_PAGE | SIF_RANGE;
2387 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2388 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2389 "Vertical scrollbar is visible, should be invisible.\n");
2390 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2391 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2392 si.nPage, si.nMin, si.nMax);
2393
2394 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
2395 memset(&si, 0, sizeof(si));
2396 si.cbSize = sizeof(si);
2397 si.fMask = SIF_PAGE | SIF_RANGE;
2398 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2399 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2400 "Vertical scrollbar is visible, should be invisible.\n");
2401 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2402 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2403 si.nPage, si.nMin, si.nMax);
2404
2405 DestroyWindow(hwndRichEdit);
2406
2407 /* Test again, with ES_DISABLENOSCROLL style */
2408 hwndRichEdit = new_window(RICHEDIT_CLASS, ES_MULTILINE|ES_DISABLENOSCROLL, NULL);
2409
2410 /* Test default scrollbar visibility behavior */
2411 memset(&si, 0, sizeof(si));
2412 si.cbSize = sizeof(si);
2413 si.fMask = SIF_PAGE | SIF_RANGE;
2414 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2415 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2416 "Vertical scrollbar is invisible, should be visible.\n");
2417 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
2418 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2419 si.nPage, si.nMin, si.nMax);
2420
2421 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2422 memset(&si, 0, sizeof(si));
2423 si.cbSize = sizeof(si);
2424 si.fMask = SIF_PAGE | SIF_RANGE;
2425 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2426 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2427 "Vertical scrollbar is invisible, should be visible.\n");
2428 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
2429 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2430 si.nPage, si.nMin, si.nMax);
2431
2432 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2433 memset(&si, 0, sizeof(si));
2434 si.cbSize = sizeof(si);
2435 si.fMask = SIF_PAGE | SIF_RANGE;
2436 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2437 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2438 "Vertical scrollbar is invisible, should be visible.\n");
2439 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2440 "reported page/range is %d (%d..%d)\n",
2441 si.nPage, si.nMin, si.nMax);
2442
2443 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2444 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2445 memset(&si, 0, sizeof(si));
2446 si.cbSize = sizeof(si);
2447 si.fMask = SIF_PAGE | SIF_RANGE;
2448 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2449 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2450 "Vertical scrollbar is invisible, should be visible.\n");
2451 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2452 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2453 si.nPage, si.nMin, si.nMax);
2454
2455 /* Setting non-scrolling text again does *not* reset scrollbar range */
2456 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2457 memset(&si, 0, sizeof(si));
2458 si.cbSize = sizeof(si);
2459 si.fMask = SIF_PAGE | SIF_RANGE;
2460 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2461 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2462 "Vertical scrollbar is invisible, should be visible.\n");
2463 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2464 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2465 si.nPage, si.nMin, si.nMax);
2466
2467 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2468 memset(&si, 0, sizeof(si));
2469 si.cbSize = sizeof(si);
2470 si.fMask = SIF_PAGE | SIF_RANGE;
2471 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2472 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2473 "Vertical scrollbar is invisible, should be visible.\n");
2474 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2475 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2476 si.nPage, si.nMin, si.nMax);
2477
2478 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2479 memset(&si, 0, sizeof(si));
2480 si.cbSize = sizeof(si);
2481 si.fMask = SIF_PAGE | SIF_RANGE;
2482 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2483 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2484 "Vertical scrollbar is invisible, should be visible.\n");
2485 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2486 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2487 si.nPage, si.nMin, si.nMax);
2488
2489 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
2490 memset(&si, 0, sizeof(si));
2491 si.cbSize = sizeof(si);
2492 si.fMask = SIF_PAGE | SIF_RANGE;
2493 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2494 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2495 "Vertical scrollbar is invisible, should be visible.\n");
2496 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
2497 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2498 si.nPage, si.nMin, si.nMax);
2499
2500 DestroyWindow(hwndRichEdit);
2501
2502 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2503 hwndRichEdit = new_richedit(NULL);
2504
2505 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2506 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE);
2507 memset(&si, 0, sizeof(si));
2508 si.cbSize = sizeof(si);
2509 si.fMask = SIF_PAGE | SIF_RANGE;
2510 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2511 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2512 "Vertical scrollbar is invisible, should be visible.\n");
2513 todo_wine {
2514 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
2515 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2516 si.nPage, si.nMin, si.nMax);
2517 }
2518
2519 /* Ditto, see above */
2520 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2521 memset(&si, 0, sizeof(si));
2522 si.cbSize = sizeof(si);
2523 si.fMask = SIF_PAGE | SIF_RANGE;
2524 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2525 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2526 "Vertical scrollbar is invisible, should be visible.\n");
2527 todo_wine {
2528 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
2529 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2530 si.nPage, si.nMin, si.nMax);
2531 }
2532
2533 /* Ditto, see above */
2534 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2535 memset(&si, 0, sizeof(si));
2536 si.cbSize = sizeof(si);
2537 si.fMask = SIF_PAGE | SIF_RANGE;
2538 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2539 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2540 "Vertical scrollbar is invisible, should be visible.\n");
2541 todo_wine {
2542 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
2543 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2544 si.nPage, si.nMin, si.nMax);
2545 }
2546
2547 /* Ditto, see above */
2548 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
2549 memset(&si, 0, sizeof(si));
2550 si.cbSize = sizeof(si);
2551 si.fMask = SIF_PAGE | SIF_RANGE;
2552 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2553 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2554 "Vertical scrollbar is invisible, should be visible.\n");
2555 todo_wine {
2556 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
2557 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2558 si.nPage, si.nMin, si.nMax);
2559 }
2560
2561 /* Ditto, see above */
2562 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2563 memset(&si, 0, sizeof(si));
2564 si.cbSize = sizeof(si);
2565 si.fMask = SIF_PAGE | SIF_RANGE;
2566 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2567 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2568 "Vertical scrollbar is invisible, should be visible.\n");
2569 todo_wine {
2570 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
2571 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2572 si.nPage, si.nMin, si.nMax);
2573 }
2574
2575 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2576 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2577 memset(&si, 0, sizeof(si));
2578 si.cbSize = sizeof(si);
2579 si.fMask = SIF_PAGE | SIF_RANGE;
2580 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2581 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2582 "Vertical scrollbar is visible, should be invisible.\n");
2583 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2584 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2585 si.nPage, si.nMin, si.nMax);
2586
2587 DestroyWindow(hwndRichEdit);
2588
2589 hwndRichEdit = new_richedit(NULL);
2590
2591 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
2592 memset(&si, 0, sizeof(si));
2593 si.cbSize = sizeof(si);
2594 si.fMask = SIF_PAGE | SIF_RANGE;
2595 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2596 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2597 "Vertical scrollbar is visible, should be invisible.\n");
2598 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2599 "reported page/range is %d (%d..%d) expected all 0\n",
2600 si.nPage, si.nMin, si.nMax);
2601
2602 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2603 memset(&si, 0, sizeof(si));
2604 si.cbSize = sizeof(si);
2605 si.fMask = SIF_PAGE | SIF_RANGE;
2606 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2607 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2608 "Vertical scrollbar is visible, should be invisible.\n");
2609 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2610 "reported page/range is %d (%d..%d) expected all 0\n",
2611 si.nPage, si.nMin, si.nMax);
2612
2613 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2614 memset(&si, 0, sizeof(si));
2615 si.cbSize = sizeof(si);
2616 si.fMask = SIF_PAGE | SIF_RANGE;
2617 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2618 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2619 "Vertical scrollbar is visible, should be invisible.\n");
2620 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2621 "reported page/range is %d (%d..%d) expected all 0\n",
2622 si.nPage, si.nMin, si.nMax);
2623
2624 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2625 memset(&si, 0, sizeof(si));
2626 si.cbSize = sizeof(si);
2627 si.fMask = SIF_PAGE | SIF_RANGE;
2628 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2629 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2630 "Vertical scrollbar is visible, should be invisible.\n");
2631 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2632 "reported page/range is %d (%d..%d) expected all 0\n",
2633 si.nPage, si.nMin, si.nMax);
2634
2635 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2636 memset(&si, 0, sizeof(si));
2637 si.cbSize = sizeof(si);
2638 si.fMask = SIF_PAGE | SIF_RANGE;
2639 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2640 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2641 "Vertical scrollbar is invisible, should be visible.\n");
2642 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2643 "reported page/range is %d (%d..%d)\n",
2644 si.nPage, si.nMin, si.nMax);
2645
2646 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2647 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
2648 memset(&si, 0, sizeof(si));
2649 si.cbSize = sizeof(si);
2650 si.fMask = SIF_PAGE | SIF_RANGE;
2651 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2652 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2653 "Vertical scrollbar is visible, should be invisible.\n");
2654 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2655 "reported page/range is %d (%d..%d)\n",
2656 si.nPage, si.nMin, si.nMax);
2657
2658 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2659 memset(&si, 0, sizeof(si));
2660 si.cbSize = sizeof(si);
2661 si.fMask = SIF_PAGE | SIF_RANGE;
2662 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2663 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2664 "Vertical scrollbar is visible, should be invisible.\n");
2665 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2666 "reported page/range is %d (%d..%d)\n",
2667 si.nPage, si.nMin, si.nMax);
2668
2669 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2670 EM_SCROLL will make visible any forcefully invisible scrollbar */
2671 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
2672 memset(&si, 0, sizeof(si));
2673 si.cbSize = sizeof(si);
2674 si.fMask = SIF_PAGE | SIF_RANGE;
2675 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2676 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2677 "Vertical scrollbar is invisible, should be visible.\n");
2678 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2679 "reported page/range is %d (%d..%d)\n",
2680 si.nPage, si.nMin, si.nMax);
2681
2682 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
2683 memset(&si, 0, sizeof(si));
2684 si.cbSize = sizeof(si);
2685 si.fMask = SIF_PAGE | SIF_RANGE;
2686 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2687 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2688 "Vertical scrollbar is visible, should be invisible.\n");
2689 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2690 "reported page/range is %d (%d..%d)\n",
2691 si.nPage, si.nMin, si.nMax);
2692
2693 /* Again, EM_SCROLL, with SB_LINEUP */
2694 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
2695 memset(&si, 0, sizeof(si));
2696 si.cbSize = sizeof(si);
2697 si.fMask = SIF_PAGE | SIF_RANGE;
2698 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2699 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2700 "Vertical scrollbar is invisible, should be visible.\n");
2701 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2702 "reported page/range is %d (%d..%d)\n",
2703 si.nPage, si.nMin, si.nMax);
2704
2705 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2706 memset(&si, 0, sizeof(si));
2707 si.cbSize = sizeof(si);
2708 si.fMask = SIF_PAGE | SIF_RANGE;
2709 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2710 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2711 "Vertical scrollbar is visible, should be invisible.\n");
2712 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2713 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2714 si.nPage, si.nMin, si.nMax);
2715
2716 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2717 memset(&si, 0, sizeof(si));
2718 si.cbSize = sizeof(si);
2719 si.fMask = SIF_PAGE | SIF_RANGE;
2720 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2721 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2722 "Vertical scrollbar is invisible, should be visible.\n");
2723 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2724 "reported page/range is %d (%d..%d)\n",
2725 si.nPage, si.nMin, si.nMax);
2726
2727 DestroyWindow(hwndRichEdit);
2728
2729
2730 /* Test behavior with explicit visibility request, using SetWindowLong()() */
2731 hwndRichEdit = new_richedit(NULL);
2732
2733 #define ENABLE_WS_VSCROLL(hwnd) \
2734 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
2735 #define DISABLE_WS_VSCROLL(hwnd) \
2736 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
2737
2738 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2739 ENABLE_WS_VSCROLL(hwndRichEdit);
2740 memset(&si, 0, sizeof(si));
2741 si.cbSize = sizeof(si);
2742 si.fMask = SIF_PAGE | SIF_RANGE;
2743 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2744 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2745 "Vertical scrollbar is invisible, should be visible.\n");
2746 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2747 "reported page/range is %d (%d..%d) expected all 0\n",
2748 si.nPage, si.nMin, si.nMax);
2749
2750 /* Ditto, see above */
2751 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2752 memset(&si, 0, sizeof(si));
2753 si.cbSize = sizeof(si);
2754 si.fMask = SIF_PAGE | SIF_RANGE;
2755 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2756 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2757 "Vertical scrollbar is invisible, should be visible.\n");
2758 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2759 "reported page/range is %d (%d..%d) expected all 0\n",
2760 si.nPage, si.nMin, si.nMax);
2761
2762 /* Ditto, see above */
2763 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2764 memset(&si, 0, sizeof(si));
2765 si.cbSize = sizeof(si);
2766 si.fMask = SIF_PAGE | SIF_RANGE;
2767 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2768 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2769 "Vertical scrollbar is invisible, should be visible.\n");
2770 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2771 "reported page/range is %d (%d..%d) expected all 0\n",
2772 si.nPage, si.nMin, si.nMax);
2773
2774 /* Ditto, see above */
2775 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
2776 memset(&si, 0, sizeof(si));
2777 si.cbSize = sizeof(si);
2778 si.fMask = SIF_PAGE | SIF_RANGE;
2779 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2780 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2781 "Vertical scrollbar is invisible, should be visible.\n");
2782 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2783 "reported page/range is %d (%d..%d) expected all 0\n",
2784 si.nPage, si.nMin, si.nMax);
2785
2786 /* Ditto, see above */
2787 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2788 memset(&si, 0, sizeof(si));
2789 si.cbSize = sizeof(si);
2790 si.fMask = SIF_PAGE | SIF_RANGE;
2791 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2792 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2793 "Vertical scrollbar is invisible, should be visible.\n");
2794 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2795 "reported page/range is %d (%d..%d) expected all 0\n",
2796 si.nPage, si.nMin, si.nMax);
2797
2798 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2799 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2800 memset(&si, 0, sizeof(si));
2801 si.cbSize = sizeof(si);
2802 si.fMask = SIF_PAGE | SIF_RANGE;
2803 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2804 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2805 "Vertical scrollbar is visible, should be invisible.\n");
2806 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2807 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2808 si.nPage, si.nMin, si.nMax);
2809
2810 DestroyWindow(hwndRichEdit);
2811
2812 hwndRichEdit = new_richedit(NULL);
2813
2814 DISABLE_WS_VSCROLL(hwndRichEdit);
2815 memset(&si, 0, sizeof(si));
2816 si.cbSize = sizeof(si);
2817 si.fMask = SIF_PAGE | SIF_RANGE;
2818 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2819 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2820 "Vertical scrollbar is visible, should be invisible.\n");
2821 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2822 "reported page/range is %d (%d..%d) expected all 0\n",
2823 si.nPage, si.nMin, si.nMax);
2824
2825 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2826 memset(&si, 0, sizeof(si));
2827 si.cbSize = sizeof(si);
2828 si.fMask = SIF_PAGE | SIF_RANGE;
2829 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2830 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2831 "Vertical scrollbar is visible, should be invisible.\n");
2832 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2833 "reported page/range is %d (%d..%d) expected all 0\n",
2834 si.nPage, si.nMin, si.nMax);
2835
2836 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2837 memset(&si, 0, sizeof(si));
2838 si.cbSize = sizeof(si);
2839 si.fMask = SIF_PAGE | SIF_RANGE;
2840 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2841 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2842 "Vertical scrollbar is visible, should be invisible.\n");
2843 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2844 "reported page/range is %d (%d..%d) expected all 0\n",
2845 si.nPage, si.nMin, si.nMax);
2846
2847 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2848 memset(&si, 0, sizeof(si));
2849 si.cbSize = sizeof(si);
2850 si.fMask = SIF_PAGE | SIF_RANGE;
2851 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2852 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2853 "Vertical scrollbar is visible, should be invisible.\n");
2854 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
2855 "reported page/range is %d (%d..%d) expected all 0\n",
2856 si.nPage, si.nMin, si.nMax);
2857
2858 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2859 memset(&si, 0, sizeof(si));
2860 si.cbSize = sizeof(si);
2861 si.fMask = SIF_PAGE | SIF_RANGE;
2862 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2863 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2864 "Vertical scrollbar is invisible, should be visible.\n");
2865 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2866 "reported page/range is %d (%d..%d)\n",
2867 si.nPage, si.nMin, si.nMax);
2868
2869 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2870 DISABLE_WS_VSCROLL(hwndRichEdit);
2871 memset(&si, 0, sizeof(si));
2872 si.cbSize = sizeof(si);
2873 si.fMask = SIF_PAGE | SIF_RANGE;
2874 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2875 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2876 "Vertical scrollbar is visible, should be invisible.\n");
2877 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2878 "reported page/range is %d (%d..%d)\n",
2879 si.nPage, si.nMin, si.nMax);
2880
2881 SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
2882 memset(&si, 0, sizeof(si));
2883 si.cbSize = sizeof(si);
2884 si.fMask = SIF_PAGE | SIF_RANGE;
2885 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2886 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2887 "Vertical scrollbar is visible, should be invisible.\n");
2888 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2889 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2890 si.nPage, si.nMin, si.nMax);
2891
2892 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2893 memset(&si, 0, sizeof(si));
2894 si.cbSize = sizeof(si);
2895 si.fMask = SIF_PAGE | SIF_RANGE;
2896 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2897 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2898 "Vertical scrollbar is invisible, should be visible.\n");
2899 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2900 "reported page/range is %d (%d..%d)\n",
2901 si.nPage, si.nMin, si.nMax);
2902
2903 DISABLE_WS_VSCROLL(hwndRichEdit);
2904 memset(&si, 0, sizeof(si));
2905 si.cbSize = sizeof(si);
2906 si.fMask = SIF_PAGE | SIF_RANGE;
2907 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2908 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2909 "Vertical scrollbar is visible, should be invisible.\n");
2910 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2911 "reported page/range is %d (%d..%d)\n",
2912 si.nPage, si.nMin, si.nMax);
2913
2914 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2915 EM_SCROLL will make visible any forcefully invisible scrollbar */
2916 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
2917 memset(&si, 0, sizeof(si));
2918 si.cbSize = sizeof(si);
2919 si.fMask = SIF_PAGE | SIF_RANGE;
2920 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2921 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2922 "Vertical scrollbar is invisible, should be visible.\n");
2923 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2924 "reported page/range is %d (%d..%d)\n",
2925 si.nPage, si.nMin, si.nMax);
2926
2927 DISABLE_WS_VSCROLL(hwndRichEdit);
2928 memset(&si, 0, sizeof(si));
2929 si.cbSize = sizeof(si);
2930 si.fMask = SIF_PAGE | SIF_RANGE;
2931 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2932 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2933 "Vertical scrollbar is visible, should be invisible.\n");
2934 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2935 "reported page/range is %d (%d..%d)\n",
2936 si.nPage, si.nMin, si.nMax);
2937
2938 /* Again, EM_SCROLL, with SB_LINEUP */
2939 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
2940 memset(&si, 0, sizeof(si));
2941 si.cbSize = sizeof(si);
2942 si.fMask = SIF_PAGE | SIF_RANGE;
2943 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2944 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2945 "Vertical scrollbar is invisible, should be visible.\n");
2946 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2947 "reported page/range is %d (%d..%d)\n",
2948 si.nPage, si.nMin, si.nMax);
2949
2950 DestroyWindow(hwndRichEdit);
2951
2952 /* This window proc models what is going on with Corman Lisp 3.0.
2953 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
2954 force the scrollbar into visibility. Recursion should NOT happen
2955 as a result of this action.
2956 */
2957 r = GetClassInfoA(NULL, RICHEDIT_CLASS, &cls);
2958 if (r) {
2959 richeditProc = cls.lpfnWndProc;
2960 cls.lpfnWndProc = RicheditStupidOverrideProcA;
2961 cls.lpszClassName = "RicheditStupidOverride";
2962 if(!RegisterClassA(&cls)) assert(0);
2963
2964 recursionLevel = 0;
2965 WM_SIZE_recursionLevel = 0;
2966 bailedOutOfRecursion = FALSE;
2967 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
2968 ok(!bailedOutOfRecursion,
2969 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
2970
2971 recursionLevel = 0;
2972 WM_SIZE_recursionLevel = 0;
2973 bailedOutOfRecursion = FALSE;
2974 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
2975 ok(!bailedOutOfRecursion,
2976 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
2977
2978 /* Unblock window in order to process WM_DESTROY */
2979 recursionLevel = 0;
2980 bailedOutOfRecursion = FALSE;
2981 WM_SIZE_recursionLevel = 0;
2982 DestroyWindow(hwndRichEdit);
2983 }
2984 }
2985
2986 static void test_EM_SETUNDOLIMIT(void)
2987 {
2988 /* cases we test for:
2989 * default behaviour - limiting at 100 undo's
2990 * undo disabled - setting a limit of 0
2991 * undo limited - undo limit set to some to some number, like 2
2992 * bad input - sending a negative number should default to 100 undo's */
2993
2994 HWND hwndRichEdit = new_richedit(NULL);
2995 CHARRANGE cr;
2996 int i;
2997 int result;
2998
2999 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
3000 cr.cpMin = 0;
3001 cr.cpMax = 1;
3002 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
3003 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3004 also, multiple pastes don't combine like WM_CHAR would */
3005 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
3006
3007 /* first case - check the default */
3008 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3009 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
3010 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
3011 for (i=0; i<100; i++) /* Undo 100 of them */
3012 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);