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