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