2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
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.
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.
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
35 #include <wine/test.h>
37 #define ID_RICHEDITTESTDBUTTON 0x123
39 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
], string3
[MAX_PATH
];
41 #define ok_w3(format, szString1, szString2, szString3) \
42 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
43 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
44 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \
45 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \
46 format, string1, string2, string3);
48 static HMODULE hmoduleRichEdit
;
50 static HWND
new_window(LPCSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
52 hwnd
= CreateWindowA(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
53 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
54 hmoduleRichEdit
, NULL
);
55 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
59 static HWND
new_windowW(LPCWSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
61 hwnd
= CreateWindowW(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
62 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
63 hmoduleRichEdit
, NULL
);
64 ok(hwnd
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName
), (int) GetLastError());
68 static HWND
new_richedit(HWND parent
) {
69 return new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, parent
);
72 static HWND
new_richeditW(HWND parent
) {
73 return new_windowW(RICHEDIT_CLASS20W
, ES_MULTILINE
, parent
);
76 /* Keeps the window reponsive for the deley_time in seconds.
77 * This is useful for debugging a test to see what is happening. */
78 static void keep_responsive(time_t delay_time
)
83 /* The message pump uses PeekMessage() to empty the queue and then
84 * sleeps for 50ms before retrying the queue. */
85 end
= time(NULL
) + delay_time
;
86 while (time(NULL
) < end
) {
87 if (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
88 TranslateMessage(&msg
);
89 DispatchMessageA(&msg
);
96 static void simulate_typing_characters(HWND hwnd
, const char* szChars
)
100 while (*szChars
!= '\0') {
101 SendMessageA(hwnd
, WM_KEYDOWN
, *szChars
, 1);
102 ret
= SendMessageA(hwnd
, WM_CHAR
, *szChars
, 1);
103 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *szChars
, ret
);
104 SendMessageA(hwnd
, WM_KEYUP
, *szChars
, 1);
109 static BOOL
hold_key(int vk
)
114 result
= GetKeyboardState(key_state
);
115 ok(result
, "GetKeyboardState failed.\n");
116 if (!result
) return FALSE
;
117 key_state
[vk
] |= 0x80;
118 result
= SetKeyboardState(key_state
);
119 ok(result
, "SetKeyboardState failed.\n");
123 static BOOL
release_key(int vk
)
128 result
= GetKeyboardState(key_state
);
129 ok(result
, "GetKeyboardState failed.\n");
130 if (!result
) return FALSE
;
131 key_state
[vk
] &= ~0x80;
132 result
= SetKeyboardState(key_state
);
133 ok(result
, "SetKeyboardState failed.\n");
137 static const char haystack
[] = "WINEWine wineWine wine WineWine";
149 static struct find_s find_tests
[] = {
150 /* Find in empty text */
151 {0, -1, "foo", FR_DOWN
, -1},
152 {0, -1, "foo", 0, -1},
153 {0, -1, "", FR_DOWN
, -1},
154 {20, 5, "foo", FR_DOWN
, -1},
155 {5, 20, "foo", FR_DOWN
, -1}
158 static struct find_s find_tests2
[] = {
160 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1},
161 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1},
163 /* Subsequent finds */
164 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4},
165 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13},
166 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
167 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
170 {19, 20, "Wine", FR_MATCHCASE
, 13},
171 {10, 20, "Wine", FR_MATCHCASE
, 4},
172 {20, 10, "Wine", FR_MATCHCASE
, 13},
174 /* Case-insensitive */
175 {1, 31, "wInE", FR_DOWN
, 4},
176 {1, 31, "Wine", FR_DOWN
, 4},
178 /* High-to-low ranges */
179 {20, 5, "Wine", FR_DOWN
, -1},
180 {2, 1, "Wine", FR_DOWN
, -1},
181 {30, 29, "Wine", FR_DOWN
, -1},
182 {20, 5, "Wine", 0, 13},
185 {5, 10, "", FR_DOWN
, -1},
186 {10, 5, "", FR_DOWN
, -1},
187 {0, -1, "", FR_DOWN
, -1},
190 /* Whole-word search */
191 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
192 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1},
193 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
194 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0},
195 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23},
196 {11, -1, "winewine", FR_WHOLEWORD
, 0},
197 {31, -1, "winewine", FR_WHOLEWORD
, 23},
200 {5, 200, "XXX", FR_DOWN
, -1},
201 {-20, 20, "Wine", FR_DOWN
, -1},
202 {-20, 20, "Wine", FR_DOWN
, -1},
203 {-15, -20, "Wine", FR_DOWN
, -1},
204 {1<<12, 1<<13, "Wine", FR_DOWN
, -1},
206 /* Check the case noted in bug 4479 where matches at end aren't recognized */
207 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
208 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
209 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
210 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
211 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
213 /* The backwards case of bug 4479; bounds look right
214 * Fails because backward find is wrong */
215 {19, 20, "WINE", FR_MATCHCASE
, 0},
216 {0, 20, "WINE", FR_MATCHCASE
, -1},
218 {0, -1, "wineWine wine", 0, -1},
221 static WCHAR
*atowstr(const char *str
)
225 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
226 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
227 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
231 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
, BOOL unicode
)
237 memset(&ftw
, 0, sizeof(ftw
));
238 ftw
.chrg
.cpMin
= f
->start
;
239 ftw
.chrg
.cpMax
= f
->end
;
240 ftw
.lpstrText
= atowstr(f
->needle
);
242 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&ftw
);
243 ok(findloc
== f
->expected_loc
,
244 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
245 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
247 findloc
= SendMessageA(hwnd
, EM_FINDTEXTW
, f
->flags
, (LPARAM
)&ftw
);
248 ok(findloc
== f
->expected_loc
,
249 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
250 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
252 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
255 memset(&fta
, 0, sizeof(fta
));
256 fta
.chrg
.cpMin
= f
->start
;
257 fta
.chrg
.cpMax
= f
->end
;
258 fta
.lpstrText
= f
->needle
;
260 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&fta
);
261 ok(findloc
== f
->expected_loc
,
262 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
263 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
267 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
268 int id
, BOOL unicode
)
271 int expected_end_loc
;
275 memset(&ftw
, 0, sizeof(ftw
));
276 ftw
.chrg
.cpMin
= f
->start
;
277 ftw
.chrg
.cpMax
= f
->end
;
278 ftw
.lpstrText
= atowstr(f
->needle
);
279 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&ftw
);
280 ok(findloc
== f
->expected_loc
,
281 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
282 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
283 ok(ftw
.chrgText
.cpMin
== f
->expected_loc
,
284 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
285 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMin
);
286 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
287 : f
->expected_loc
+ strlen(f
->needle
));
288 ok(ftw
.chrgText
.cpMax
== expected_end_loc
,
289 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
290 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMax
, expected_end_loc
);
291 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
294 memset(&fta
, 0, sizeof(fta
));
295 fta
.chrg
.cpMin
= f
->start
;
296 fta
.chrg
.cpMax
= f
->end
;
297 fta
.lpstrText
= f
->needle
;
298 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&fta
);
299 ok(findloc
== f
->expected_loc
,
300 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
301 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
302 ok(fta
.chrgText
.cpMin
== f
->expected_loc
,
303 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
304 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMin
);
305 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
306 : f
->expected_loc
+ strlen(f
->needle
));
307 ok(fta
.chrgText
.cpMax
== expected_end_loc
,
308 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
309 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMax
, expected_end_loc
);
313 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
314 int num_tests
, BOOL unicode
)
318 for (i
= 0; i
< num_tests
; i
++) {
319 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
, unicode
);
320 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
, unicode
);
324 static void test_EM_FINDTEXT(BOOL unicode
)
330 hwndRichEdit
= new_richeditW(NULL
);
332 hwndRichEdit
= new_richedit(NULL
);
334 /* Empty rich edit control */
335 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
336 sizeof(find_tests
)/sizeof(struct find_s
), unicode
);
338 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack
);
341 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
342 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
344 /* Setting a format on an arbitrary range should have no effect in search
345 results. This tests correct offset reporting across runs. */
346 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
347 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
348 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
349 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
350 SendMessageA(hwndRichEdit
, EM_SETSEL
, 6, 20);
351 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
353 /* Haystack text, again */
354 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bis", find_tests2
,
355 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
357 /* Yet another range */
358 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
359 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
360 SendMessageA(hwndRichEdit
, EM_SETSEL
, 11, 15);
361 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
363 /* Haystack text, again */
364 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bisbis", find_tests2
,
365 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
367 DestroyWindow(hwndRichEdit
);
370 static const struct getline_s
{
375 {0, 10, "foo bar\r"},
380 /* Buffer smaller than line length */
386 static void test_EM_GETLINE(void)
389 HWND hwndRichEdit
= new_richedit(NULL
);
390 static const int nBuf
= 1024;
391 char dest
[1024], origdest
[1024];
392 const char text
[] = "foo bar\n"
396 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
398 memset(origdest
, 0xBB, nBuf
);
399 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
402 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
403 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
404 memset(dest
, 0xBB, nBuf
);
405 *(WORD
*) dest
= gl
[i
].buffer_len
;
407 /* EM_GETLINE appends a "\r\0" to the end of the line
408 * nCopied counts up to and including the '\r' */
409 nCopied
= SendMessageA(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
)dest
);
410 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
412 /* two special cases since a parameter is passed via dest */
413 if (gl
[i
].buffer_len
== 0)
414 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
416 else if (gl
[i
].buffer_len
== 1)
417 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
418 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
421 /* Prepare hex strings of buffers to dump on failure. */
422 char expectedbuf
[1024];
423 char resultbuf
[1024];
426 for (j
= 0; j
< 32; j
++)
427 sprintf(resultbuf
+strlen(resultbuf
), "%02x", dest
[j
] & 0xFF);
428 expectedbuf
[0] = '\0';
429 for (j
= 0; j
< expected_bytes_written
; j
++) /* Written bytes */
430 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", gl
[i
].text
[j
] & 0xFF);
431 for (; j
< gl
[i
].buffer_len
; j
++) /* Ignored bytes */
432 sprintf(expectedbuf
+strlen(expectedbuf
), "??");
433 for (; j
< 32; j
++) /* Bytes after declared buffer size */
434 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", origdest
[j
] & 0xFF);
436 /* Test the part of the buffer that is expected to be written according
437 * to the MSDN documentation fo EM_GETLINE, which does not state that
438 * a NULL terminating character will be added unless no text is copied.
440 * Windows NT does not append a NULL terminating character, but
441 * Windows 2000 and up do append a NULL terminating character if there
442 * is space in the buffer. The test will ignore this difference. */
443 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
444 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
445 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
446 /* Test the part of the buffer after the declared length to make sure
447 * there are no buffer overruns. */
448 ok(!strncmp(dest
+ gl
[i
].buffer_len
, origdest
+ gl
[i
].buffer_len
,
449 nBuf
- gl
[i
].buffer_len
),
450 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
451 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
455 DestroyWindow(hwndRichEdit
);
458 static void test_EM_LINELENGTH(void)
460 HWND hwndRichEdit
= new_richedit(NULL
);
466 int offset_test
[10][2] = {
481 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
483 for (i
= 0; i
< 10; i
++) {
484 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
485 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
486 offset_test
[i
][0], result
, offset_test
[i
][1]);
489 DestroyWindow(hwndRichEdit
);
492 static int get_scroll_pos_y(HWND hwnd
)
495 SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&p
);
496 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
500 static void move_cursor(HWND hwnd
, LONG charindex
)
503 cr
.cpMax
= charindex
;
504 cr
.cpMin
= charindex
;
505 SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
508 static void line_scroll(HWND hwnd
, int amount
)
510 SendMessageA(hwnd
, EM_LINESCROLL
, 0, amount
);
513 static void test_EM_SCROLLCARET(void)
516 const char text
[] = "aa\n"
517 "this is a long line of text that should be longer than the "
525 /* The richedit window height needs to be large enough vertically to fit in
526 * more than two lines of text, so the new_richedit function can't be used
527 * since a height of 60 was not large enough on some systems.
529 HWND hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
530 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
531 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
532 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
534 /* Can't verify this */
535 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
537 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
539 /* Caret above visible window */
540 line_scroll(hwndRichEdit
, 3);
541 prevY
= get_scroll_pos_y(hwndRichEdit
);
542 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
543 curY
= get_scroll_pos_y(hwndRichEdit
);
544 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
546 /* Caret below visible window */
547 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
548 line_scroll(hwndRichEdit
, -3);
549 prevY
= get_scroll_pos_y(hwndRichEdit
);
550 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
551 curY
= get_scroll_pos_y(hwndRichEdit
);
552 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
554 /* Caret in visible window */
555 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
556 prevY
= get_scroll_pos_y(hwndRichEdit
);
557 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
558 curY
= get_scroll_pos_y(hwndRichEdit
);
559 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
561 /* Caret still in visible window */
562 line_scroll(hwndRichEdit
, -1);
563 prevY
= get_scroll_pos_y(hwndRichEdit
);
564 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
565 curY
= get_scroll_pos_y(hwndRichEdit
);
566 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
568 DestroyWindow(hwndRichEdit
);
571 static void test_EM_POSFROMCHAR(void)
573 HWND hwndRichEdit
= new_richedit(NULL
);
576 unsigned int height
= 0;
581 static const char text
[] = "aa\n"
582 "this is a long line of text that should be longer than the "
591 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
592 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
593 (sig
.lsUsb
[3] & 0x08000000) != 0);
595 /* Fill the control to lines to ensure that most of them are offscreen */
596 for (i
= 0; i
< 50; i
++)
598 /* Do not modify the string; it is exactly 16 characters long. */
599 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
600 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
604 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
605 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
606 Richedit 3.0 accepts either of the above API conventions.
609 /* Testing Richedit 2.0 API format */
611 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
612 Since all lines are identical and drawn with the same font,
613 they should have the same height... right?
615 for (i
= 0; i
< 50; i
++)
617 /* All the lines are 16 characters long */
618 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
621 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
622 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
623 xpos
= LOWORD(result
);
627 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
628 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
629 height
= HIWORD(result
);
633 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
634 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
638 /* Testing position at end of text */
639 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
640 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
641 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
643 /* Testing position way past end of text */
644 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
645 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
646 expected
= (rtl
? 8 : 1);
647 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
649 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
650 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
651 for (i
= 0; i
< 50; i
++)
653 /* All the lines are 16 characters long */
654 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
655 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
656 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
657 (signed short)(HIWORD(result
)), (i
- 1) * height
);
658 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
661 /* Testing position at end of text */
662 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
663 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
664 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
666 /* Testing position way past end of text */
667 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
668 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
669 expected
= (rtl
? 8 : 1);
670 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
672 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
673 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
674 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
676 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
677 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
678 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
679 xpos
= LOWORD(result
);
681 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
682 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
683 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
684 ok((signed short)(LOWORD(result
)) < xpos
,
685 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
686 (signed short)(LOWORD(result
)), xpos
);
687 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
689 /* Test around end of text that doesn't end in a newline. */
690 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"12345678901234");
691 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
692 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
693 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
695 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
696 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
697 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
698 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
699 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
700 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
701 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
703 /* Try a negative position. */
704 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
705 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
707 DestroyWindow(hwndRichEdit
);
710 static void test_EM_SETCHARFORMAT(void)
712 HWND hwndRichEdit
= new_richedit(NULL
);
715 int tested_effects
[] = {
731 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
732 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
733 (sig
.lsUsb
[3] & 0x08000000) != 0);
735 /* Invalid flags, CHARFORMAT2 structure blanked out */
736 memset(&cf2
, 0, sizeof(cf2
));
737 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
738 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
740 /* A valid flag, CHARFORMAT2 structure blanked out */
741 memset(&cf2
, 0, sizeof(cf2
));
742 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
743 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
745 /* A valid flag, CHARFORMAT2 structure blanked out */
746 memset(&cf2
, 0, sizeof(cf2
));
747 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
748 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
750 /* A valid flag, CHARFORMAT2 structure blanked out */
751 memset(&cf2
, 0, sizeof(cf2
));
752 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
753 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
755 /* A valid flag, CHARFORMAT2 structure blanked out */
756 memset(&cf2
, 0, sizeof(cf2
));
757 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
758 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
760 /* Invalid flags, CHARFORMAT2 structure minimally filled */
761 memset(&cf2
, 0, sizeof(cf2
));
762 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
763 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
764 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
765 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
766 ok(rc
== FALSE
, "Should not be able to undo here.\n");
767 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
769 /* A valid flag, CHARFORMAT2 structure minimally filled */
770 memset(&cf2
, 0, sizeof(cf2
));
771 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
772 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
773 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
774 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
775 ok(rc
== FALSE
, "Should not be able to undo here.\n");
776 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
778 /* A valid flag, CHARFORMAT2 structure minimally filled */
779 memset(&cf2
, 0, sizeof(cf2
));
780 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
781 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
782 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
783 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
784 ok(rc
== FALSE
, "Should not be able to undo here.\n");
785 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
787 /* A valid flag, CHARFORMAT2 structure minimally filled */
788 memset(&cf2
, 0, sizeof(cf2
));
789 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
790 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
791 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
792 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
793 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
794 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
796 /* A valid flag, CHARFORMAT2 structure minimally filled */
797 memset(&cf2
, 0, sizeof(cf2
));
798 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
799 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
800 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
801 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
802 ok(rc
== TRUE
, "Should not be able to undo here.\n");
803 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
805 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
806 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
808 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
809 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
810 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
811 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
812 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
814 /* wParam==0 is default char format, does not set modify */
815 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
816 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
817 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
818 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
819 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
822 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
823 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
826 skip("RTL language found\n");
828 /* wParam==SCF_SELECTION sets modify if nonempty selection */
829 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
830 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
831 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
832 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
833 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
834 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
835 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
837 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
838 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
839 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
840 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
841 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
842 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
843 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
844 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
845 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
846 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
847 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
848 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
850 /* wParam==SCF_ALL sets modify regardless of whether text is present */
851 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
852 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
853 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
854 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
855 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
856 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
857 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
859 DestroyWindow(hwndRichEdit
);
861 /* EM_GETCHARFORMAT tests */
862 for (i
= 0; tested_effects
[i
]; i
++)
864 hwndRichEdit
= new_richedit(NULL
);
865 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
867 /* Need to set a TrueType font to get consistent CFM_BOLD results */
868 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
869 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
870 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
872 strcpy(cf2
.szFaceName
, "Courier New");
873 cf2
.wWeight
= FW_DONTCARE
;
874 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
876 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
877 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
878 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 4);
879 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
880 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
881 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
883 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
884 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
885 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
886 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
888 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
889 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
890 cf2
.dwMask
= tested_effects
[i
];
891 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
892 cf2
.dwMask
= CFM_SUPERSCRIPT
;
893 cf2
.dwEffects
= tested_effects
[i
];
894 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
895 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
897 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
898 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
899 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
900 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
901 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
902 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
904 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
905 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
906 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
907 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
909 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
910 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
911 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
912 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
913 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
914 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
916 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
917 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
918 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
919 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
921 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
922 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
923 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
924 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
925 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
926 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
928 (cf2
.dwMask
& tested_effects
[i
]) == 0),
929 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
931 DestroyWindow(hwndRichEdit
);
934 for (i
= 0; tested_effects
[i
]; i
++)
936 hwndRichEdit
= new_richedit(NULL
);
937 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
939 /* Need to set a TrueType font to get consistent CFM_BOLD results */
940 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
941 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
942 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
944 strcpy(cf2
.szFaceName
, "Courier New");
945 cf2
.wWeight
= FW_DONTCARE
;
946 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
948 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
949 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
950 cf2
.dwMask
= tested_effects
[i
];
951 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
952 cf2
.dwMask
= CFM_SUPERSCRIPT
;
953 cf2
.dwEffects
= tested_effects
[i
];
954 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
955 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
957 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
958 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
959 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
960 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
961 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
962 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
964 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
965 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
966 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
967 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
969 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
970 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
971 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
972 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
973 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
974 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
976 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
977 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
978 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
979 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
981 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
982 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
983 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
984 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
985 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
986 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
988 (cf2
.dwMask
& tested_effects
[i
]) == 0),
989 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
990 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
991 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
993 DestroyWindow(hwndRichEdit
);
996 /* Effects applied on an empty selection should take effect when selection is
997 replaced with text */
998 hwndRichEdit
= new_richedit(NULL
);
999 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1000 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1002 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1003 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1004 cf2
.dwMask
= CFM_BOLD
;
1005 cf2
.dwEffects
= CFE_BOLD
;
1006 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1008 /* Selection is now nonempty */
1009 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1011 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1012 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1013 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1014 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1016 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1017 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1018 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1019 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1022 /* Set two effects on an empty selection */
1023 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1024 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1026 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1027 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1028 cf2
.dwMask
= CFM_BOLD
;
1029 cf2
.dwEffects
= CFE_BOLD
;
1030 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1031 cf2
.dwMask
= CFM_ITALIC
;
1032 cf2
.dwEffects
= CFE_ITALIC
;
1033 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1035 /* Selection is now nonempty */
1036 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1038 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1039 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1040 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1041 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1043 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
1044 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
1045 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
1046 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
1048 /* Setting the (empty) selection to exactly the same place as before should
1049 NOT clear the insertion style! */
1050 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1051 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1053 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1054 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1055 cf2
.dwMask
= CFM_BOLD
;
1056 cf2
.dwEffects
= CFE_BOLD
;
1057 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1059 /* Empty selection in same place, insert style should NOT be forgotten here. */
1060 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2);
1062 /* Selection is now nonempty */
1063 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1065 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1066 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1067 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1068 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1070 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1071 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1072 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1073 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1075 /* Ditto with EM_EXSETSEL */
1076 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1077 cr
.cpMin
= 2; cr
.cpMax
= 2;
1078 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1080 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1081 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1082 cf2
.dwMask
= CFM_BOLD
;
1083 cf2
.dwEffects
= CFE_BOLD
;
1084 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1086 /* Empty selection in same place, insert style should NOT be forgotten here. */
1087 cr
.cpMin
= 2; cr
.cpMax
= 2;
1088 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1090 /* Selection is now nonempty */
1091 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1093 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1094 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1095 cr
.cpMin
= 2; cr
.cpMax
= 6;
1096 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1097 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1099 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1100 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1101 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1102 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1104 DestroyWindow(hwndRichEdit
);
1107 static void test_EM_SETTEXTMODE(void)
1109 HWND hwndRichEdit
= new_richedit(NULL
);
1110 CHARFORMAT2A cf2
, cf2test
;
1114 /*Attempt to use mutually exclusive modes*/
1115 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1116 ok(rc
== E_INVALIDARG
,
1117 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1119 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1120 /*Insert text into the control*/
1122 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1124 /*Attempt to change the control to plain text mode*/
1125 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1126 ok(rc
== E_UNEXPECTED
,
1127 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1129 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1130 If rich text is pasted, it should have the same formatting as the rest
1131 of the text in the control*/
1133 /*Italicize the text
1134 *NOTE: If the default text was already italicized, the test will simply
1135 reverse; in other words, it will copy a regular "wine" into a plain
1136 text window that uses an italicized format*/
1137 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1138 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
1140 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1141 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1143 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1144 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1146 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1147 however, SCF_ALL has been implemented*/
1148 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1149 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1151 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1152 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1154 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1156 /*Select the string "wine"*/
1159 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1161 /*Copy the italicized "wine" to the clipboard*/
1162 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1164 /*Reset the formatting to default*/
1165 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1166 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1167 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1169 /*Clear the text in the control*/
1170 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1172 /*Switch to Plain Text Mode*/
1173 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1174 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1176 /*Input "wine" again in normal format*/
1177 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1179 /*Paste the italicized "wine" into the control*/
1180 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1182 /*Select a character from the first "wine" string*/
1185 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1187 /*Retrieve its formatting*/
1188 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1190 /*Select a character from the second "wine" string*/
1193 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1195 /*Retrieve its formatting*/
1196 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1197 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1199 /*Compare the two formattings*/
1200 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1201 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1202 cf2
.dwEffects
, cf2test
.dwEffects
);
1203 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1204 printing "wine" in the current format(normal)
1205 pasting "wine" from the clipboard(italicized)
1206 comparing the two formats(should differ)*/
1208 /*Attempt to switch with text in control*/
1209 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1210 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1213 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1215 /*Switch into Rich Text mode*/
1216 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1217 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1219 /*Print "wine" in normal formatting into the control*/
1220 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1222 /*Paste italicized "wine" into the control*/
1223 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1225 /*Select text from the first "wine" string*/
1228 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1230 /*Retrieve its formatting*/
1231 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1233 /*Select text from the second "wine" string*/
1236 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1238 /*Retrieve its formatting*/
1239 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1241 /*Test that the two formattings are not the same*/
1242 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1243 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1244 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1246 DestroyWindow(hwndRichEdit
);
1249 static void test_SETPARAFORMAT(void)
1251 HWND hwndRichEdit
= new_richedit(NULL
);
1254 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1255 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1256 fmt
.dwMask
= PFM_ALIGNMENT
;
1257 fmt
.wAlignment
= PFA_LEFT
;
1259 ret
= SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1260 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1262 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1264 ret
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1265 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1266 * between richedit different native builds of riched20.dll
1267 * used on different Windows versions. */
1268 ret
&= ~PFM_TABLEROWDELIMITER
;
1269 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1271 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1272 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1274 DestroyWindow(hwndRichEdit
);
1277 static void test_TM_PLAINTEXT(void)
1279 /*Tests plain text properties*/
1281 HWND hwndRichEdit
= new_richedit(NULL
);
1282 CHARFORMAT2A cf2
, cf2test
;
1286 /*Switch to plain text mode*/
1288 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1289 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1291 /*Fill control with text*/
1293 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Is Wine an emulator? No it's not");
1295 /*Select some text and bold it*/
1299 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1300 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1301 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1303 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1304 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1306 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1307 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1309 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1310 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1312 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1313 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1315 /*Get the formatting of those characters*/
1317 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1319 /*Get the formatting of some other characters*/
1320 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1323 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1324 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1326 /*Test that they are the same as plain text allows only one formatting*/
1328 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1329 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1330 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1332 /*Fill the control with a "wine" string, which when inserted will be bold*/
1334 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1336 /*Copy the bolded "wine" string*/
1340 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1341 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1343 /*Swap back to rich text*/
1345 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1346 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1348 /*Set the default formatting to bold italics*/
1350 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1351 cf2
.dwMask
|= CFM_ITALIC
;
1352 cf2
.dwEffects
^= CFE_ITALIC
;
1353 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1354 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1356 /*Set the text in the control to "wine", which will be bold and italicized*/
1358 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1360 /*Paste the plain text "wine" string, which should take the insert
1361 formatting, which at the moment is bold italics*/
1363 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1365 /*Select the first "wine" string and retrieve its formatting*/
1369 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1370 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1372 /*Select the second "wine" string and retrieve its formatting*/
1376 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1377 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1379 /*Compare the two formattings. They should be the same.*/
1381 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1382 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1383 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1384 DestroyWindow(hwndRichEdit
);
1387 static void test_WM_GETTEXT(void)
1389 HWND hwndRichEdit
= new_richedit(NULL
);
1390 static const char text
[] = "Hello. My name is RichEdit!";
1391 static const char text2
[] = "Hello. My name is RichEdit!\r";
1392 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1393 char buffer
[1024] = {0};
1396 /* Baseline test with normal-sized buffer */
1397 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1398 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1399 ok(result
== lstrlenA(buffer
),
1400 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1401 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1402 result
= strcmp(buffer
,text
);
1404 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1406 /* Test for returned value of WM_GETTEXTLENGTH */
1407 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1408 ok(result
== lstrlenA(text
),
1409 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1410 result
, lstrlenA(text
));
1412 /* Test for behavior in overflow case */
1413 memset(buffer
, 0, 1024);
1414 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1416 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1417 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1418 result
= strcmp(buffer
,text
);
1420 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1422 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1424 /* Baseline test with normal-sized buffer and carriage return */
1425 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1426 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1427 ok(result
== lstrlenA(buffer
),
1428 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1429 result
= strcmp(buffer
,text2_after
);
1431 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1433 /* Test for returned value of WM_GETTEXTLENGTH */
1434 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1435 ok(result
== lstrlenA(text2_after
),
1436 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1437 result
, lstrlenA(text2_after
));
1439 /* Test for behavior of CRLF conversion in case of overflow */
1440 memset(buffer
, 0, 1024);
1441 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1443 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1444 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1445 result
= strcmp(buffer
,text2
);
1447 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1449 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1451 DestroyWindow(hwndRichEdit
);
1454 static void test_EM_GETTEXTRANGE(void)
1456 HWND hwndRichEdit
= new_richedit(NULL
);
1457 const char * text1
= "foo bar\r\nfoo bar";
1458 const char * text2
= "foo bar\rfoo bar";
1459 const char * expect
= "bar\rfoo";
1460 char buffer
[1024] = {0};
1462 TEXTRANGEA textRange
;
1464 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1466 textRange
.lpstrText
= buffer
;
1467 textRange
.chrg
.cpMin
= 4;
1468 textRange
.chrg
.cpMax
= 11;
1469 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1470 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1471 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1473 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1475 textRange
.lpstrText
= buffer
;
1476 textRange
.chrg
.cpMin
= 4;
1477 textRange
.chrg
.cpMax
= 11;
1478 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1479 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1480 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1482 /* cpMax of text length is used instead of -1 in this case */
1483 textRange
.lpstrText
= buffer
;
1484 textRange
.chrg
.cpMin
= 0;
1485 textRange
.chrg
.cpMax
= -1;
1486 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1487 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1488 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1490 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1491 textRange
.lpstrText
= buffer
;
1492 textRange
.chrg
.cpMin
= -1;
1493 textRange
.chrg
.cpMax
= 1;
1494 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1495 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1496 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1498 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1499 textRange
.lpstrText
= buffer
;
1500 textRange
.chrg
.cpMin
= 1;
1501 textRange
.chrg
.cpMax
= -1;
1502 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1503 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1504 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1506 /* no end character is copied if cpMax - cpMin < 0 */
1507 textRange
.lpstrText
= buffer
;
1508 textRange
.chrg
.cpMin
= 5;
1509 textRange
.chrg
.cpMax
= 5;
1510 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1511 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1512 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1514 /* cpMax of text length is used if cpMax > text length*/
1515 textRange
.lpstrText
= buffer
;
1516 textRange
.chrg
.cpMin
= 0;
1517 textRange
.chrg
.cpMax
= 1000;
1518 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1519 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1520 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1522 DestroyWindow(hwndRichEdit
);
1525 static void test_EM_GETSELTEXT(void)
1527 HWND hwndRichEdit
= new_richedit(NULL
);
1528 const char * text1
= "foo bar\r\nfoo bar";
1529 const char * text2
= "foo bar\rfoo bar";
1530 const char * expect
= "bar\rfoo";
1531 char buffer
[1024] = {0};
1534 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1536 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1537 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1538 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1539 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1541 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1543 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1544 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1545 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1546 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1548 DestroyWindow(hwndRichEdit
);
1551 /* FIXME: need to test unimplemented options and robustly test wparam */
1552 static void test_EM_SETOPTIONS(void)
1555 static const char text
[] = "Hello. My name is RichEdit!";
1556 char buffer
[1024] = {0};
1557 DWORD dwStyle
, options
, oldOptions
;
1558 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1559 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1560 ES_SELECTIONBAR
|ES_VERTICAL
;
1562 /* Test initial options. */
1563 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, WS_POPUP
,
1564 0, 0, 200, 60, NULL
, NULL
,
1565 hmoduleRichEdit
, NULL
);
1566 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1567 RICHEDIT_CLASS20A
, (int) GetLastError());
1568 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1569 ok(options
== 0, "Incorrect initial options %x\n", options
);
1570 DestroyWindow(hwndRichEdit
);
1572 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
1573 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1574 0, 0, 200, 60, NULL
, NULL
,
1575 hmoduleRichEdit
, NULL
);
1576 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1577 RICHEDIT_CLASS20A
, (int) GetLastError());
1578 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1579 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1580 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1581 "Incorrect initial options %x\n", options
);
1583 /* NEGATIVE TESTING - NO OPTIONS SET */
1584 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1585 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1587 /* testing no readonly by sending 'a' to the control*/
1588 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1589 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1591 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1592 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1594 /* READONLY - sending 'a' to the control */
1595 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1596 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1597 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1598 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1599 ok(buffer
[0]==text
[0],
1600 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1602 /* EM_SETOPTIONS changes the window style, but changing the
1603 * window style does not change the options. */
1604 dwStyle
= GetWindowLongA(hwndRichEdit
, GWL_STYLE
);
1605 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1606 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1607 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1608 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1609 /* Confirm that the text is still read only. */
1610 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1611 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1612 ok(buffer
[0]==text
[0],
1613 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1615 oldOptions
= options
;
1616 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1617 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1618 ok(options
== oldOptions
,
1619 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1621 DestroyWindow(hwndRichEdit
);
1624 static BOOL
check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1626 CHARFORMAT2A text_format
;
1627 text_format
.cbSize
= sizeof(text_format
);
1628 SendMessageA(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1629 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&text_format
);
1630 return (text_format
.dwEffects
& CFE_LINK
) != 0;
1633 static void check_CFE_LINK_rcvd(HWND hwnd
, BOOL is_url
, const char * url
)
1635 BOOL link_present
= FALSE
;
1637 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1639 { /* control text is url; should get CFE_LINK */
1640 ok(link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1644 ok(!link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1648 static HWND
new_static_wnd(HWND parent
) {
1649 return new_window("Static", 0, parent
);
1652 static void test_EM_AUTOURLDETECT(void)
1654 /* DO NOT change the properties of the first two elements. To shorten the
1655 tests, all tests after WM_SETTEXT test just the first two elements -
1656 one non-URL and one URL */
1661 {"winehq.org", FALSE
},
1662 {"http://www.winehq.org", TRUE
},
1663 {"http//winehq.org", FALSE
},
1664 {"ww.winehq.org", FALSE
},
1665 {"www.winehq.org", TRUE
},
1666 {"ftp://192.168.1.1", TRUE
},
1667 {"ftp//192.168.1.1", FALSE
},
1668 {"mailto:your@email.com", TRUE
},
1669 {"prospero:prosperoserver", TRUE
},
1670 {"telnet:test", TRUE
},
1671 {"news:newserver", TRUE
},
1672 {"wais:waisserver", TRUE
}
1677 HWND hwndRichEdit
, parent
;
1679 /* All of the following should cause the URL to be detected */
1680 const char * templates_delim
[] = {
1681 "This is some text with X on it",
1682 "This is some text with (X) on it",
1683 "This is some text with X\r on it",
1684 "This is some text with ---X--- on it",
1685 "This is some text with \"X\" on it",
1686 "This is some text with 'X' on it",
1687 "This is some text with 'X' on it",
1688 "This is some text with :X: on it",
1690 "This text ends with X",
1692 "This is some text with X) on it",
1693 "This is some text with X--- on it",
1694 "This is some text with X\" on it",
1695 "This is some text with X' on it",
1696 "This is some text with X: on it",
1698 "This is some text with (X on it",
1699 "This is some text with \rX on it",
1700 "This is some text with ---X on it",
1701 "This is some text with \"X on it",
1702 "This is some text with 'X on it",
1703 "This is some text with :X on it",
1705 /* None of these should cause the URL to be detected */
1706 const char * templates_non_delim
[] = {
1707 "This is some text with |X| on it",
1708 "This is some text with *X* on it",
1709 "This is some text with /X/ on it",
1710 "This is some text with +X+ on it",
1711 "This is some text with %X% on it",
1712 "This is some text with #X# on it",
1713 "This is some text with @X@ on it",
1714 "This is some text with \\X\\ on it",
1715 "This is some text with |X on it",
1716 "This is some text with *X on it",
1717 "This is some text with /X on it",
1718 "This is some text with +X on it",
1719 "This is some text with %X on it",
1720 "This is some text with #X on it",
1721 "This is some text with @X on it",
1722 "This is some text with \\X on it",
1724 /* All of these cause the URL detection to be extended by one more byte,
1725 thus demonstrating that the tested character is considered as part
1727 const char * templates_xten_delim
[] = {
1728 "This is some text with X| on it",
1729 "This is some text with X* on it",
1730 "This is some text with X/ on it",
1731 "This is some text with X+ on it",
1732 "This is some text with X% on it",
1733 "This is some text with X# on it",
1734 "This is some text with X@ on it",
1735 "This is some text with X\\ on it",
1739 parent
= new_static_wnd(NULL
);
1740 hwndRichEdit
= new_richedit(parent
);
1741 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1742 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1743 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
1744 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
1745 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
1746 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1747 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
1748 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
1749 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
1750 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
1751 /* for each url, check the text to see if CFE_LINK effect is present */
1752 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1754 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1755 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1756 check_CFE_LINK_rcvd(hwndRichEdit
, FALSE
, urls
[i
].text
);
1758 /* Link detection should happen immediately upon WM_SETTEXT */
1759 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1760 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1761 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
1763 DestroyWindow(hwndRichEdit
);
1765 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1766 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1767 hwndRichEdit
= new_richedit(parent
);
1769 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
1774 at_pos
= strchr(templates_delim
[j
], 'X');
1775 at_offset
= at_pos
- templates_delim
[j
];
1776 memcpy(buffer
, templates_delim
[j
], at_offset
);
1777 buffer
[at_offset
] = '\0';
1778 strcat(buffer
, urls
[i
].text
);
1779 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
1780 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1782 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1783 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1785 /* This assumes no templates start with the URL itself, and that they
1786 have at least two characters before the URL text */
1787 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1788 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1789 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1790 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1791 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1792 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1796 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1797 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1798 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1799 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1803 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1804 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
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
-1, end_offset
, buffer
);
1808 if (buffer
[end_offset
] != '\0')
1810 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1811 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1812 if (buffer
[end_offset
+1] != '\0')
1814 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1815 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1820 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
1825 at_pos
= strchr(templates_non_delim
[j
], 'X');
1826 at_offset
= at_pos
- templates_non_delim
[j
];
1827 memcpy(buffer
, templates_non_delim
[j
], at_offset
);
1828 buffer
[at_offset
] = '\0';
1829 strcat(buffer
, urls
[i
].text
);
1830 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
1831 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1833 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1834 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1836 /* This assumes no templates start with the URL itself, and that they
1837 have at least two characters before the URL text */
1838 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1839 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1840 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1841 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1842 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1843 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1845 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1846 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1847 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1848 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1849 if (buffer
[end_offset
] != '\0')
1851 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1852 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1853 if (buffer
[end_offset
+1] != '\0')
1855 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1856 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1861 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
1866 at_pos
= strchr(templates_xten_delim
[j
], 'X');
1867 at_offset
= at_pos
- templates_xten_delim
[j
];
1868 memcpy(buffer
, templates_xten_delim
[j
], at_offset
);
1869 buffer
[at_offset
] = '\0';
1870 strcat(buffer
, urls
[i
].text
);
1871 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
1872 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1874 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1875 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1877 /* This assumes no templates start with the URL itself, and that they
1878 have at least two characters before the URL text */
1879 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1880 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1881 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1882 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1883 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1884 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1888 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1889 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1890 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1891 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1892 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1893 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1897 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1898 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1899 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1900 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1901 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1902 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1904 if (buffer
[end_offset
+1] != '\0')
1906 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1907 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
1908 if (buffer
[end_offset
+2] != '\0')
1910 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1911 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1916 DestroyWindow(hwndRichEdit
);
1917 hwndRichEdit
= NULL
;
1920 /* Test detection of URLs within normal text - WM_CHAR case. */
1921 /* Test only the first two URL examples for brevity */
1922 for (i
= 0; i
< 2; i
++) {
1923 hwndRichEdit
= new_richedit(parent
);
1925 /* Also for brevity, test only the first three delimiters */
1926 for (j
= 0; j
< 3; j
++) {
1932 at_pos
= strchr(templates_delim
[j
], 'X');
1933 at_offset
= at_pos
- templates_delim
[j
];
1934 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1936 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1937 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
1938 for (u
= 0; templates_delim
[j
][u
]; u
++) {
1939 if (templates_delim
[j
][u
] == '\r') {
1940 simulate_typing_characters(hwndRichEdit
, "\r");
1941 } else if (templates_delim
[j
][u
] != 'X') {
1942 SendMessageA(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
1944 for (v
= 0; urls
[i
].text
[v
]; v
++) {
1945 SendMessageA(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
1949 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
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
);
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
);
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
);
1974 if (buffer
[end_offset
] != '\0')
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')
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
);
1985 /* The following will insert a paragraph break after the first character
1986 of the URL candidate, thus breaking the URL. It is expected that the
1987 CFE_LINK attribute should break across both pieces of the URL */
1988 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
1989 simulate_typing_characters(hwndRichEdit
, "\r");
1990 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1992 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1993 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1994 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1995 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1996 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1997 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1999 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2000 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2001 /* end_offset moved because of paragraph break */
2002 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2003 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2004 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
2005 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
2007 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2008 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2009 if (buffer
[end_offset
+2] != '\0')
2011 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2012 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2016 /* The following will remove the just-inserted paragraph break, thus
2017 restoring the URL */
2018 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
2019 simulate_typing_characters(hwndRichEdit
, "\b");
2020 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2022 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2023 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2024 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2025 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2026 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2027 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2031 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2032 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2033 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2034 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2038 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2039 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2040 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2041 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2043 if (buffer
[end_offset
] != '\0')
2045 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2046 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2047 if (buffer
[end_offset
+1] != '\0')
2049 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2050 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2054 DestroyWindow(hwndRichEdit
);
2055 hwndRichEdit
= NULL
;
2058 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2059 /* Test just the first two URL examples for brevity */
2060 for (i
= 0; i
< 2; i
++) {
2063 hwndRichEdit
= new_richedit(parent
);
2065 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2067 1) Set entire text, a la WM_SETTEXT
2068 2) Set a selection of the text to the URL
2069 3) Set a portion of the text at a time, which eventually results in
2071 All of them should give equivalent results
2074 /* Set entire text in one go, like WM_SETTEXT */
2075 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2080 st
.codepage
= CP_ACP
;
2081 st
.flags
= ST_DEFAULT
;
2083 at_pos
= strchr(templates_delim
[j
], 'X');
2084 at_offset
= at_pos
- templates_delim
[j
];
2085 memcpy(buffer
, templates_delim
[j
], at_offset
);
2086 buffer
[at_offset
] = '\0';
2087 strcat(buffer
, urls
[i
].text
);
2088 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2089 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2091 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2092 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2094 /* This assumes no templates start with the URL itself, and that they
2095 have at least two characters before the URL text */
2096 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2097 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2098 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2099 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2100 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2101 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2105 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2106 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2107 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2108 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2112 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2113 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2114 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2115 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2117 if (buffer
[end_offset
] != '\0')
2119 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2120 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2121 if (buffer
[end_offset
+1] != '\0')
2123 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2124 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2129 /* Set selection with X to the URL */
2130 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2135 at_pos
= strchr(templates_delim
[j
], 'X');
2136 at_offset
= at_pos
- templates_delim
[j
];
2137 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2139 st
.codepage
= CP_ACP
;
2140 st
.flags
= ST_DEFAULT
;
2141 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2142 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2143 st
.flags
= ST_SELECTION
;
2144 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2145 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)urls
[i
].text
);
2146 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2148 /* This assumes no templates start with the URL itself, and that they
2149 have at least two characters before the URL text */
2150 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2151 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2152 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2153 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2154 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2155 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2159 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2160 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2161 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2162 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2166 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2167 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2168 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2169 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2171 if (buffer
[end_offset
] != '\0')
2173 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2174 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2175 if (buffer
[end_offset
+1] != '\0')
2177 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2178 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2183 /* Set selection with X to the first character of the URL, then the rest */
2184 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2189 at_pos
= strchr(templates_delim
[j
], 'X');
2190 at_offset
= at_pos
- templates_delim
[j
];
2191 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2193 strcpy(buffer
, "YY");
2194 buffer
[0] = urls
[i
].text
[0];
2196 st
.codepage
= CP_ACP
;
2197 st
.flags
= ST_DEFAULT
;
2198 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2199 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2200 st
.flags
= ST_SELECTION
;
2201 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2202 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2203 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2204 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2205 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2207 /* This assumes no templates start with the URL itself, and that they
2208 have at least two characters before the URL text */
2209 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2210 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2211 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2212 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2213 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2214 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2218 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2219 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2220 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2221 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2225 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2226 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2227 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2228 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2230 if (buffer
[end_offset
] != '\0')
2232 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2233 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2234 if (buffer
[end_offset
+1] != '\0')
2236 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2237 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2242 DestroyWindow(hwndRichEdit
);
2243 hwndRichEdit
= NULL
;
2246 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2247 /* Test just the first two URL examples for brevity */
2248 for (i
= 0; i
< 2; i
++) {
2249 hwndRichEdit
= new_richedit(parent
);
2251 /* Set selection with X to the URL */
2252 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2257 at_pos
= strchr(templates_delim
[j
], 'X');
2258 at_offset
= at_pos
- templates_delim
[j
];
2259 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2261 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2262 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2263 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2264 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urls
[i
].text
);
2265 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2267 /* This assumes no templates start with the URL itself, and that they
2268 have at least two characters before the URL text */
2269 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2270 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2271 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2272 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2273 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2274 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2278 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2279 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2280 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2281 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2285 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2286 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2287 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2288 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2290 if (buffer
[end_offset
] != '\0')
2292 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2293 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2294 if (buffer
[end_offset
+1] != '\0')
2296 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2297 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2302 /* Set selection with X to the first character of the URL, then the rest */
2303 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2308 at_pos
= strchr(templates_delim
[j
], 'X');
2309 at_offset
= at_pos
- templates_delim
[j
];
2310 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2312 strcpy(buffer
, "YY");
2313 buffer
[0] = urls
[i
].text
[0];
2315 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2316 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2317 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2318 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)buffer
);
2319 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2320 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2321 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2323 /* This assumes no templates start with the URL itself, and that they
2324 have at least two characters before the URL text */
2325 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2326 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2327 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2328 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2329 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2330 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2334 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2335 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2336 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2337 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2341 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2342 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2343 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2344 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2346 if (buffer
[end_offset
] != '\0')
2348 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2349 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2350 if (buffer
[end_offset
+1] != '\0')
2352 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2353 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2358 DestroyWindow(hwndRichEdit
);
2359 hwndRichEdit
= NULL
;
2362 DestroyWindow(parent
);
2365 static void test_EM_SCROLL(void)
2368 int r
; /* return value */
2369 int expr
; /* expected return value */
2370 HWND hwndRichEdit
= new_richedit(NULL
);
2371 int y_before
, y_after
; /* units of lines of text */
2373 /* test a richedit box containing a single line of text */
2374 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");/* one line of text */
2376 for (i
= 0; i
< 4; i
++) {
2377 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2379 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2380 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2381 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2382 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2383 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2384 "(i == %d)\n", y_after
, i
);
2388 * test a richedit box that will scroll. There are two general
2389 * cases: the case without any long lines and the case with a long
2392 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2394 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\nb\nc\nd\ne");
2396 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2397 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2398 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2399 "LONG LINE \nb\nc\nd\ne");
2400 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2401 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2403 /* get first visible line */
2404 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2405 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2407 /* get new current first visible line */
2408 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2410 ok(((r
& 0xffffff00) == 0x00010000) &&
2411 ((r
& 0x000000ff) != 0x00000000),
2412 "EM_SCROLL page down didn't scroll by a small positive number of "
2413 "lines (r == 0x%08x)\n", r
);
2414 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2415 "(line %d scrolled to line %d\n", y_before
, y_after
);
2419 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2420 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2421 ok(((r
& 0xffffff00) == 0x0001ff00),
2422 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2423 "(r == 0x%08x)\n", r
);
2424 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2425 "%d scrolled to line %d\n", y_before
, y_after
);
2429 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2431 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2433 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2434 "(r == 0x%08x)\n", r
);
2435 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2436 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2440 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2442 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2444 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2445 "(r == 0x%08x)\n", r
);
2446 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2447 "line (%d scrolled to %d)\n", y_before
, y_after
);
2451 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2452 SB_LINEUP
, 0); /* lineup beyond top */
2454 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2457 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2458 ok(y_before
== y_after
,
2459 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2463 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2464 SB_PAGEUP
, 0);/*page up beyond top */
2466 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2469 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2470 ok(y_before
== y_after
,
2471 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2473 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2474 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2475 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2476 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2477 SB_PAGEDOWN
, 0); /* page down beyond bot */
2478 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2481 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2482 ok(y_before
== y_after
,
2483 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2486 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2487 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2488 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2491 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2492 ok(y_before
== y_after
,
2493 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2496 DestroyWindow(hwndRichEdit
);
2499 static unsigned int recursionLevel
= 0;
2500 static unsigned int WM_SIZE_recursionLevel
= 0;
2501 static BOOL bailedOutOfRecursion
= FALSE
;
2502 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2504 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2508 if (bailedOutOfRecursion
) return 0;
2509 if (recursionLevel
>= 32) {
2510 bailedOutOfRecursion
= TRUE
;
2517 WM_SIZE_recursionLevel
++;
2518 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2519 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2520 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2521 WM_SIZE_recursionLevel
--;
2524 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2531 static void test_scrollbar_visibility(void)
2534 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2539 /* These tests show that richedit should temporarily refrain from automatically
2540 hiding or showing its scrollbars (vertical at least) when an explicit request
2541 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2542 Some applications depend on forced showing (when otherwise richedit would
2543 hide the vertical scrollbar) and are thrown on an endless recursive loop
2544 if richedit auto-hides the scrollbar again. Apparently they never heard of
2545 the ES_DISABLENOSCROLL style... */
2547 hwndRichEdit
= new_richedit(NULL
);
2549 /* Test default scrollbar visibility behavior */
2550 memset(&si
, 0, sizeof(si
));
2551 si
.cbSize
= sizeof(si
);
2552 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2553 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2554 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2555 "Vertical scrollbar is visible, should be invisible.\n");
2556 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2557 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2558 si
.nPage
, si
.nMin
, si
.nMax
);
2560 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2561 memset(&si
, 0, sizeof(si
));
2562 si
.cbSize
= sizeof(si
);
2563 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2564 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2565 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2566 "Vertical scrollbar is visible, should be invisible.\n");
2567 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2568 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2569 si
.nPage
, si
.nMin
, si
.nMax
);
2571 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2572 memset(&si
, 0, sizeof(si
));
2573 si
.cbSize
= sizeof(si
);
2574 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2575 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2576 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2577 "Vertical scrollbar is invisible, should be visible.\n");
2578 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2579 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2580 si
.nPage
, si
.nMin
, si
.nMax
);
2582 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2583 even though it hides the scrollbar */
2584 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2585 memset(&si
, 0, sizeof(si
));
2586 si
.cbSize
= sizeof(si
);
2587 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2588 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2589 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2590 "Vertical scrollbar is visible, should be invisible.\n");
2591 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2592 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2593 si
.nPage
, si
.nMin
, si
.nMax
);
2595 /* Setting non-scrolling text again does *not* reset scrollbar range */
2596 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2597 memset(&si
, 0, sizeof(si
));
2598 si
.cbSize
= sizeof(si
);
2599 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2600 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2601 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2602 "Vertical scrollbar is visible, should be invisible.\n");
2603 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2604 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2605 si
.nPage
, si
.nMin
, si
.nMax
);
2607 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2608 memset(&si
, 0, sizeof(si
));
2609 si
.cbSize
= sizeof(si
);
2610 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2611 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2612 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2613 "Vertical scrollbar is visible, should be invisible.\n");
2614 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2615 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2616 si
.nPage
, si
.nMin
, si
.nMax
);
2618 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2619 memset(&si
, 0, sizeof(si
));
2620 si
.cbSize
= sizeof(si
);
2621 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2622 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2623 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2624 "Vertical scrollbar is visible, should be invisible.\n");
2625 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2626 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2627 si
.nPage
, si
.nMin
, si
.nMax
);
2629 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2630 memset(&si
, 0, sizeof(si
));
2631 si
.cbSize
= sizeof(si
);
2632 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2633 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2634 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2635 "Vertical scrollbar is visible, should be invisible.\n");
2636 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2637 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2638 si
.nPage
, si
.nMin
, si
.nMax
);
2640 DestroyWindow(hwndRichEdit
);
2642 /* Test again, with ES_DISABLENOSCROLL style */
2643 hwndRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2645 /* Test default scrollbar visibility behavior */
2646 memset(&si
, 0, sizeof(si
));
2647 si
.cbSize
= sizeof(si
);
2648 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2649 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2650 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2651 "Vertical scrollbar is invisible, should be visible.\n");
2652 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2653 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2654 si
.nPage
, si
.nMin
, si
.nMax
);
2656 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2657 memset(&si
, 0, sizeof(si
));
2658 si
.cbSize
= sizeof(si
);
2659 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2660 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2661 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2662 "Vertical scrollbar is invisible, should be visible.\n");
2663 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2664 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2665 si
.nPage
, si
.nMin
, si
.nMax
);
2667 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2668 memset(&si
, 0, sizeof(si
));
2669 si
.cbSize
= sizeof(si
);
2670 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2671 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2672 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2673 "Vertical scrollbar is invisible, should be visible.\n");
2674 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2675 "reported page/range is %d (%d..%d)\n",
2676 si
.nPage
, si
.nMin
, si
.nMax
);
2678 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2679 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2680 memset(&si
, 0, sizeof(si
));
2681 si
.cbSize
= sizeof(si
);
2682 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2683 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2684 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2685 "Vertical scrollbar is invisible, should be visible.\n");
2686 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2687 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2688 si
.nPage
, si
.nMin
, si
.nMax
);
2690 /* Setting non-scrolling text again does *not* reset scrollbar range */
2691 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2692 memset(&si
, 0, sizeof(si
));
2693 si
.cbSize
= sizeof(si
);
2694 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2695 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2696 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2697 "Vertical scrollbar is invisible, should be visible.\n");
2698 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2699 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2700 si
.nPage
, si
.nMin
, si
.nMax
);
2702 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2703 memset(&si
, 0, sizeof(si
));
2704 si
.cbSize
= sizeof(si
);
2705 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2706 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2707 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2708 "Vertical scrollbar is invisible, should be visible.\n");
2709 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2710 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2711 si
.nPage
, si
.nMin
, si
.nMax
);
2713 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2714 memset(&si
, 0, sizeof(si
));
2715 si
.cbSize
= sizeof(si
);
2716 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2717 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2718 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2719 "Vertical scrollbar is invisible, should be visible.\n");
2720 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2721 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2722 si
.nPage
, si
.nMin
, si
.nMax
);
2724 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2725 memset(&si
, 0, sizeof(si
));
2726 si
.cbSize
= sizeof(si
);
2727 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2728 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2729 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2730 "Vertical scrollbar is invisible, should be visible.\n");
2731 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2732 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2733 si
.nPage
, si
.nMin
, si
.nMax
);
2735 DestroyWindow(hwndRichEdit
);
2737 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2738 hwndRichEdit
= new_richedit(NULL
);
2740 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2741 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
2742 memset(&si
, 0, sizeof(si
));
2743 si
.cbSize
= sizeof(si
);
2744 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2745 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2746 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2747 "Vertical scrollbar is invisible, should be visible.\n");
2749 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2750 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2751 si
.nPage
, si
.nMin
, si
.nMax
);
2754 /* Ditto, see above */
2755 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
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");
2763 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2764 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2765 si
.nPage
, si
.nMin
, si
.nMax
);
2768 /* Ditto, see above */
2769 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2770 memset(&si
, 0, sizeof(si
));
2771 si
.cbSize
= sizeof(si
);
2772 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2773 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2774 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2775 "Vertical scrollbar is invisible, should be visible.\n");
2777 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2778 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2779 si
.nPage
, si
.nMin
, si
.nMax
);
2782 /* Ditto, see above */
2783 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2784 memset(&si
, 0, sizeof(si
));
2785 si
.cbSize
= sizeof(si
);
2786 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2787 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2788 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2789 "Vertical scrollbar is invisible, should be visible.\n");
2791 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2792 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2793 si
.nPage
, si
.nMin
, si
.nMax
);
2796 /* Ditto, see above */
2797 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2798 memset(&si
, 0, sizeof(si
));
2799 si
.cbSize
= sizeof(si
);
2800 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2801 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2802 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2803 "Vertical scrollbar is invisible, should be visible.\n");
2805 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2806 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2807 si
.nPage
, si
.nMin
, si
.nMax
);
2810 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2811 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2812 memset(&si
, 0, sizeof(si
));
2813 si
.cbSize
= sizeof(si
);
2814 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2815 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2816 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2817 "Vertical scrollbar is visible, should be invisible.\n");
2818 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2819 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2820 si
.nPage
, si
.nMin
, si
.nMax
);
2822 DestroyWindow(hwndRichEdit
);
2824 hwndRichEdit
= new_richedit(NULL
);
2826 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
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 visible, should be invisible.\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
);
2837 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2838 memset(&si
, 0, sizeof(si
));
2839 si
.cbSize
= sizeof(si
);
2840 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2841 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2842 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2843 "Vertical scrollbar is visible, should be invisible.\n");
2844 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2845 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2846 si
.nPage
, si
.nMin
, si
.nMax
);
2848 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2849 memset(&si
, 0, sizeof(si
));
2850 si
.cbSize
= sizeof(si
);
2851 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2852 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2853 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2854 "Vertical scrollbar is visible, should be invisible.\n");
2855 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2856 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2857 si
.nPage
, si
.nMin
, si
.nMax
);
2859 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2860 memset(&si
, 0, sizeof(si
));
2861 si
.cbSize
= sizeof(si
);
2862 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2863 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2864 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2865 "Vertical scrollbar is visible, should be invisible.\n");
2866 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2867 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2868 si
.nPage
, si
.nMin
, si
.nMax
);
2870 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2871 memset(&si
, 0, sizeof(si
));
2872 si
.cbSize
= sizeof(si
);
2873 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2874 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2875 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2876 "Vertical scrollbar is invisible, should be visible.\n");
2877 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2878 "reported page/range is %d (%d..%d)\n",
2879 si
.nPage
, si
.nMin
, si
.nMax
);
2881 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2882 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2883 memset(&si
, 0, sizeof(si
));
2884 si
.cbSize
= sizeof(si
);
2885 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2886 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2887 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2888 "Vertical scrollbar is visible, should be invisible.\n");
2889 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2890 "reported page/range is %d (%d..%d)\n",
2891 si
.nPage
, si
.nMin
, si
.nMax
);
2893 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2894 memset(&si
, 0, sizeof(si
));
2895 si
.cbSize
= sizeof(si
);
2896 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2897 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2898 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2899 "Vertical scrollbar is visible, should be invisible.\n");
2900 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2901 "reported page/range is %d (%d..%d)\n",
2902 si
.nPage
, si
.nMin
, si
.nMax
);
2904 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2905 EM_SCROLL will make visible any forcefully invisible scrollbar */
2906 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
2907 memset(&si
, 0, sizeof(si
));
2908 si
.cbSize
= sizeof(si
);
2909 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2910 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2911 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2912 "Vertical scrollbar is invisible, should be visible.\n");
2913 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2914 "reported page/range is %d (%d..%d)\n",
2915 si
.nPage
, si
.nMin
, si
.nMax
);
2917 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2918 memset(&si
, 0, sizeof(si
));
2919 si
.cbSize
= sizeof(si
);
2920 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2921 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2922 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2923 "Vertical scrollbar is visible, should be invisible.\n");
2924 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2925 "reported page/range is %d (%d..%d)\n",
2926 si
.nPage
, si
.nMin
, si
.nMax
);
2928 /* Again, EM_SCROLL, with SB_LINEUP */
2929 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
2930 memset(&si
, 0, sizeof(si
));
2931 si
.cbSize
= sizeof(si
);
2932 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2933 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2934 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2935 "Vertical scrollbar is invisible, should be visible.\n");
2936 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2937 "reported page/range is %d (%d..%d)\n",