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
;
49 static BOOL is_lang_japanese
;
51 static HWND
new_window(LPCSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
53 hwnd
= CreateWindowA(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
54 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
55 hmoduleRichEdit
, NULL
);
56 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
60 static HWND
new_windowW(LPCWSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
62 hwnd
= CreateWindowW(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
63 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
64 hmoduleRichEdit
, NULL
);
65 ok(hwnd
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName
), (int) GetLastError());
69 static HWND
new_richedit(HWND parent
) {
70 return new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, parent
);
73 static HWND
new_richeditW(HWND parent
) {
74 return new_windowW(RICHEDIT_CLASS20W
, ES_MULTILINE
, parent
);
77 /* Keeps the window reponsive for the deley_time in seconds.
78 * This is useful for debugging a test to see what is happening. */
79 static void keep_responsive(time_t delay_time
)
84 /* The message pump uses PeekMessage() to empty the queue and then
85 * sleeps for 50ms before retrying the queue. */
86 end
= time(NULL
) + delay_time
;
87 while (time(NULL
) < end
) {
88 if (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
89 TranslateMessage(&msg
);
90 DispatchMessageA(&msg
);
97 static void simulate_typing_characters(HWND hwnd
, const char* szChars
)
101 while (*szChars
!= '\0') {
102 SendMessageA(hwnd
, WM_KEYDOWN
, *szChars
, 1);
103 ret
= SendMessageA(hwnd
, WM_CHAR
, *szChars
, 1);
104 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *szChars
, ret
);
105 SendMessageA(hwnd
, WM_KEYUP
, *szChars
, 1);
110 static BOOL
hold_key(int vk
)
115 result
= GetKeyboardState(key_state
);
116 ok(result
, "GetKeyboardState failed.\n");
117 if (!result
) return FALSE
;
118 key_state
[vk
] |= 0x80;
119 result
= SetKeyboardState(key_state
);
120 ok(result
, "SetKeyboardState failed.\n");
124 static BOOL
release_key(int vk
)
129 result
= GetKeyboardState(key_state
);
130 ok(result
, "GetKeyboardState failed.\n");
131 if (!result
) return FALSE
;
132 key_state
[vk
] &= ~0x80;
133 result
= SetKeyboardState(key_state
);
134 ok(result
, "SetKeyboardState failed.\n");
138 static const char haystack
[] = "WINEWine wineWine wine WineWine";
150 static struct find_s find_tests
[] = {
151 /* Find in empty text */
152 {0, -1, "foo", FR_DOWN
, -1},
153 {0, -1, "foo", 0, -1},
154 {0, -1, "", FR_DOWN
, -1},
155 {20, 5, "foo", FR_DOWN
, -1},
156 {5, 20, "foo", FR_DOWN
, -1}
159 static struct find_s find_tests2
[] = {
161 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1},
162 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1},
164 /* Subsequent finds */
165 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4},
166 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13},
167 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
168 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
171 {19, 20, "Wine", FR_MATCHCASE
, 13},
172 {10, 20, "Wine", FR_MATCHCASE
, 4},
173 {20, 10, "Wine", FR_MATCHCASE
, 13},
175 /* Case-insensitive */
176 {1, 31, "wInE", FR_DOWN
, 4},
177 {1, 31, "Wine", FR_DOWN
, 4},
179 /* High-to-low ranges */
180 {20, 5, "Wine", FR_DOWN
, -1},
181 {2, 1, "Wine", FR_DOWN
, -1},
182 {30, 29, "Wine", FR_DOWN
, -1},
183 {20, 5, "Wine", 0, 13},
186 {5, 10, "", FR_DOWN
, -1},
187 {10, 5, "", FR_DOWN
, -1},
188 {0, -1, "", FR_DOWN
, -1},
191 /* Whole-word search */
192 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
193 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1},
194 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
195 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0},
196 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23},
197 {11, -1, "winewine", FR_WHOLEWORD
, 0},
198 {31, -1, "winewine", FR_WHOLEWORD
, 23},
201 {5, 200, "XXX", FR_DOWN
, -1},
202 {-20, 20, "Wine", FR_DOWN
, -1},
203 {-20, 20, "Wine", FR_DOWN
, -1},
204 {-15, -20, "Wine", FR_DOWN
, -1},
205 {1<<12, 1<<13, "Wine", FR_DOWN
, -1},
207 /* Check the case noted in bug 4479 where matches at end aren't recognized */
208 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
209 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
210 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
211 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
212 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
214 /* The backwards case of bug 4479; bounds look right
215 * Fails because backward find is wrong */
216 {19, 20, "WINE", FR_MATCHCASE
, 0},
217 {0, 20, "WINE", FR_MATCHCASE
, -1},
219 {0, -1, "wineWine wine", 0, -1},
222 static WCHAR
*atowstr(const char *str
)
226 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
227 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
228 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
232 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
, BOOL unicode
)
238 memset(&ftw
, 0, sizeof(ftw
));
239 ftw
.chrg
.cpMin
= f
->start
;
240 ftw
.chrg
.cpMax
= f
->end
;
241 ftw
.lpstrText
= atowstr(f
->needle
);
243 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&ftw
);
244 ok(findloc
== f
->expected_loc
,
245 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
246 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
248 findloc
= SendMessageA(hwnd
, EM_FINDTEXTW
, f
->flags
, (LPARAM
)&ftw
);
249 ok(findloc
== f
->expected_loc
,
250 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
251 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
253 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
256 memset(&fta
, 0, sizeof(fta
));
257 fta
.chrg
.cpMin
= f
->start
;
258 fta
.chrg
.cpMax
= f
->end
;
259 fta
.lpstrText
= f
->needle
;
261 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&fta
);
262 ok(findloc
== f
->expected_loc
,
263 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
264 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
268 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
269 int id
, BOOL unicode
)
272 int expected_end_loc
;
276 memset(&ftw
, 0, sizeof(ftw
));
277 ftw
.chrg
.cpMin
= f
->start
;
278 ftw
.chrg
.cpMax
= f
->end
;
279 ftw
.lpstrText
= atowstr(f
->needle
);
280 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&ftw
);
281 ok(findloc
== f
->expected_loc
,
282 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
283 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
284 ok(ftw
.chrgText
.cpMin
== f
->expected_loc
,
285 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
286 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMin
);
287 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
288 : f
->expected_loc
+ strlen(f
->needle
));
289 ok(ftw
.chrgText
.cpMax
== expected_end_loc
,
290 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
291 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMax
, expected_end_loc
);
292 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
295 memset(&fta
, 0, sizeof(fta
));
296 fta
.chrg
.cpMin
= f
->start
;
297 fta
.chrg
.cpMax
= f
->end
;
298 fta
.lpstrText
= f
->needle
;
299 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&fta
);
300 ok(findloc
== f
->expected_loc
,
301 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
302 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
303 ok(fta
.chrgText
.cpMin
== f
->expected_loc
,
304 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
305 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMin
);
306 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
307 : f
->expected_loc
+ strlen(f
->needle
));
308 ok(fta
.chrgText
.cpMax
== expected_end_loc
,
309 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
310 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMax
, expected_end_loc
);
314 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
315 int num_tests
, BOOL unicode
)
319 for (i
= 0; i
< num_tests
; i
++) {
320 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
, unicode
);
321 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
, unicode
);
325 static void test_EM_FINDTEXT(BOOL unicode
)
331 hwndRichEdit
= new_richeditW(NULL
);
333 hwndRichEdit
= new_richedit(NULL
);
335 /* Empty rich edit control */
336 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
337 sizeof(find_tests
)/sizeof(struct find_s
), unicode
);
339 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack
);
342 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
343 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
345 /* Setting a format on an arbitrary range should have no effect in search
346 results. This tests correct offset reporting across runs. */
347 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
348 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
349 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
350 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
351 SendMessageA(hwndRichEdit
, EM_SETSEL
, 6, 20);
352 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
354 /* Haystack text, again */
355 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bis", find_tests2
,
356 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
358 /* Yet another range */
359 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
360 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
361 SendMessageA(hwndRichEdit
, EM_SETSEL
, 11, 15);
362 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
364 /* Haystack text, again */
365 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bisbis", find_tests2
,
366 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
368 DestroyWindow(hwndRichEdit
);
371 static const struct getline_s
{
376 {0, 10, "foo bar\r"},
381 /* Buffer smaller than line length */
387 static void test_EM_GETLINE(void)
390 HWND hwndRichEdit
= new_richedit(NULL
);
391 static const int nBuf
= 1024;
392 char dest
[1024], origdest
[1024];
393 const char text
[] = "foo bar\n"
397 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
399 memset(origdest
, 0xBB, nBuf
);
400 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
403 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
404 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
405 memset(dest
, 0xBB, nBuf
);
406 *(WORD
*) dest
= gl
[i
].buffer_len
;
408 /* EM_GETLINE appends a "\r\0" to the end of the line
409 * nCopied counts up to and including the '\r' */
410 nCopied
= SendMessageA(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
)dest
);
411 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
413 /* two special cases since a parameter is passed via dest */
414 if (gl
[i
].buffer_len
== 0)
415 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
417 else if (gl
[i
].buffer_len
== 1)
418 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
419 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
422 /* Prepare hex strings of buffers to dump on failure. */
423 char expectedbuf
[1024];
424 char resultbuf
[1024];
427 for (j
= 0; j
< 32; j
++)
428 sprintf(resultbuf
+strlen(resultbuf
), "%02x", dest
[j
] & 0xFF);
429 expectedbuf
[0] = '\0';
430 for (j
= 0; j
< expected_bytes_written
; j
++) /* Written bytes */
431 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", gl
[i
].text
[j
] & 0xFF);
432 for (; j
< gl
[i
].buffer_len
; j
++) /* Ignored bytes */
433 sprintf(expectedbuf
+strlen(expectedbuf
), "??");
434 for (; j
< 32; j
++) /* Bytes after declared buffer size */
435 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", origdest
[j
] & 0xFF);
437 /* Test the part of the buffer that is expected to be written according
438 * to the MSDN documentation fo EM_GETLINE, which does not state that
439 * a NULL terminating character will be added unless no text is copied.
441 * Windows NT does not append a NULL terminating character, but
442 * Windows 2000 and up do append a NULL terminating character if there
443 * is space in the buffer. The test will ignore this difference. */
444 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
445 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
446 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
447 /* Test the part of the buffer after the declared length to make sure
448 * there are no buffer overruns. */
449 ok(!strncmp(dest
+ gl
[i
].buffer_len
, origdest
+ gl
[i
].buffer_len
,
450 nBuf
- gl
[i
].buffer_len
),
451 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
452 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
456 DestroyWindow(hwndRichEdit
);
459 static void test_EM_LINELENGTH(void)
461 HWND hwndRichEdit
= new_richedit(NULL
);
467 int offset_test
[10][2] = {
482 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
484 for (i
= 0; i
< 10; i
++) {
485 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
486 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
487 offset_test
[i
][0], result
, offset_test
[i
][1]);
490 /* Test with multibyte character */
491 if (!is_lang_japanese
)
492 skip("Skip multibyte character tests on non-Japanese platform\n");
499 int offset_test1
[3][2] = {
500 {0, 4}, /* Line 1: |wine\n */
501 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */
502 {15, 4}, /* Line 3: |wine */
504 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
505 for (i
= 0; i
< sizeof(offset_test1
)/sizeof(offset_test1
[0]); i
++) {
506 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test1
[i
][0], 0);
507 ok(result
== offset_test1
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
508 offset_test1
[i
][0], result
, offset_test1
[i
][1]);
512 DestroyWindow(hwndRichEdit
);
515 static int get_scroll_pos_y(HWND hwnd
)
518 SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&p
);
519 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
523 static void move_cursor(HWND hwnd
, LONG charindex
)
526 cr
.cpMax
= charindex
;
527 cr
.cpMin
= charindex
;
528 SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
531 static void line_scroll(HWND hwnd
, int amount
)
533 SendMessageA(hwnd
, EM_LINESCROLL
, 0, amount
);
536 static void test_EM_SCROLLCARET(void)
539 const char text
[] = "aa\n"
540 "this is a long line of text that should be longer than the "
548 /* The richedit window height needs to be large enough vertically to fit in
549 * more than two lines of text, so the new_richedit function can't be used
550 * since a height of 60 was not large enough on some systems.
552 HWND hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
553 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
554 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
555 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
557 /* Can't verify this */
558 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
560 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
562 /* Caret above visible window */
563 line_scroll(hwndRichEdit
, 3);
564 prevY
= get_scroll_pos_y(hwndRichEdit
);
565 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
566 curY
= get_scroll_pos_y(hwndRichEdit
);
567 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
569 /* Caret below visible window */
570 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
571 line_scroll(hwndRichEdit
, -3);
572 prevY
= get_scroll_pos_y(hwndRichEdit
);
573 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
574 curY
= get_scroll_pos_y(hwndRichEdit
);
575 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
577 /* Caret in visible window */
578 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
579 prevY
= get_scroll_pos_y(hwndRichEdit
);
580 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
581 curY
= get_scroll_pos_y(hwndRichEdit
);
582 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
584 /* Caret still in visible window */
585 line_scroll(hwndRichEdit
, -1);
586 prevY
= get_scroll_pos_y(hwndRichEdit
);
587 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
588 curY
= get_scroll_pos_y(hwndRichEdit
);
589 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
591 DestroyWindow(hwndRichEdit
);
594 static void test_EM_POSFROMCHAR(void)
596 HWND hwndRichEdit
= new_richedit(NULL
);
599 unsigned int height
= 0;
604 static const char text
[] = "aa\n"
605 "this is a long line of text that should be longer than the "
614 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
615 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
616 (sig
.lsUsb
[3] & 0x08000000) != 0);
618 /* Fill the control to lines to ensure that most of them are offscreen */
619 for (i
= 0; i
< 50; i
++)
621 /* Do not modify the string; it is exactly 16 characters long. */
622 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
623 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
627 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
628 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
629 Richedit 3.0 accepts either of the above API conventions.
632 /* Testing Richedit 2.0 API format */
634 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
635 Since all lines are identical and drawn with the same font,
636 they should have the same height... right?
638 for (i
= 0; i
< 50; i
++)
640 /* All the lines are 16 characters long */
641 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
644 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
645 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
646 xpos
= LOWORD(result
);
650 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
651 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
652 height
= HIWORD(result
);
656 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
657 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 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * 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 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * 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 vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
673 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
674 for (i
= 0; i
< 50; i
++)
676 /* All the lines are 16 characters long */
677 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
678 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
679 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
680 (signed short)(HIWORD(result
)), (i
- 1) * height
);
681 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
684 /* Testing position at end of text */
685 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
686 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
687 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
689 /* Testing position way past end of text */
690 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
691 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
692 expected
= (rtl
? 8 : 1);
693 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
695 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
696 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
697 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
699 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
700 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
701 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
702 xpos
= LOWORD(result
);
704 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
705 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
706 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
707 ok((signed short)(LOWORD(result
)) < xpos
,
708 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
709 (signed short)(LOWORD(result
)), xpos
);
710 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
712 /* Test around end of text that doesn't end in a newline. */
713 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"12345678901234");
714 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
715 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
716 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
718 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
719 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
720 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
721 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
722 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
723 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
724 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
726 /* Try a negative position. */
727 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
728 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
730 DestroyWindow(hwndRichEdit
);
733 static void test_EM_SETCHARFORMAT(void)
735 HWND hwndRichEdit
= new_richedit(NULL
);
738 int tested_effects
[] = {
754 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
755 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
756 (sig
.lsUsb
[3] & 0x08000000) != 0);
758 /* Invalid flags, CHARFORMAT2 structure blanked out */
759 memset(&cf2
, 0, sizeof(cf2
));
760 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
761 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
763 /* A valid flag, CHARFORMAT2 structure blanked out */
764 memset(&cf2
, 0, sizeof(cf2
));
765 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
766 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
768 /* A valid flag, CHARFORMAT2 structure blanked out */
769 memset(&cf2
, 0, sizeof(cf2
));
770 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
771 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
773 /* A valid flag, CHARFORMAT2 structure blanked out */
774 memset(&cf2
, 0, sizeof(cf2
));
775 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
776 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
778 /* A valid flag, CHARFORMAT2 structure blanked out */
779 memset(&cf2
, 0, sizeof(cf2
));
780 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
781 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
783 /* Invalid flags, CHARFORMAT2 structure minimally filled */
784 memset(&cf2
, 0, sizeof(cf2
));
785 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
786 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
787 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
788 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
789 ok(rc
== FALSE
, "Should not be able to undo here.\n");
790 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
792 /* A valid flag, CHARFORMAT2 structure minimally filled */
793 memset(&cf2
, 0, sizeof(cf2
));
794 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
795 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
796 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
797 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
798 ok(rc
== FALSE
, "Should not be able to undo here.\n");
799 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
801 /* A valid flag, CHARFORMAT2 structure minimally filled */
802 memset(&cf2
, 0, sizeof(cf2
));
803 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
804 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
805 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
806 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
807 ok(rc
== FALSE
, "Should not be able to undo here.\n");
808 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
810 /* A valid flag, CHARFORMAT2 structure minimally filled */
811 memset(&cf2
, 0, sizeof(cf2
));
812 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
813 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
814 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
815 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
816 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
817 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
819 /* A valid flag, CHARFORMAT2 structure minimally filled */
820 memset(&cf2
, 0, sizeof(cf2
));
821 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
822 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
823 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
824 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
825 ok(rc
== TRUE
, "Should not be able to undo here.\n");
826 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
828 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
829 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
831 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
832 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
833 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
834 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
835 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
837 /* wParam==0 is default char format, does not set modify */
838 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
839 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
840 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
841 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
842 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
845 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
846 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
849 skip("RTL language found\n");
851 /* wParam==SCF_SELECTION sets modify if nonempty selection */
852 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
853 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
854 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
855 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
856 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
857 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
858 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
860 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
861 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
862 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
863 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
864 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
865 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
866 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
867 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
868 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
869 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
870 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
871 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
873 /* wParam==SCF_ALL sets modify regardless of whether text is present */
874 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
875 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
876 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
877 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
878 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
879 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
880 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
882 DestroyWindow(hwndRichEdit
);
884 /* EM_GETCHARFORMAT tests */
885 for (i
= 0; tested_effects
[i
]; i
++)
887 hwndRichEdit
= new_richedit(NULL
);
888 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
890 /* Need to set a TrueType font to get consistent CFM_BOLD results */
891 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
892 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
893 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
895 strcpy(cf2
.szFaceName
, "Courier New");
896 cf2
.wWeight
= FW_DONTCARE
;
897 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
899 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
900 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
901 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 4);
902 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
903 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
904 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
906 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
907 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
908 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
909 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
911 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
912 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
913 cf2
.dwMask
= tested_effects
[i
];
914 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
915 cf2
.dwMask
= CFM_SUPERSCRIPT
;
916 cf2
.dwEffects
= tested_effects
[i
];
917 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
918 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
920 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
921 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
922 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
923 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
924 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
925 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
927 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
928 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
929 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
930 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
932 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
933 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
934 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
935 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
936 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
937 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
939 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
940 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
941 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
942 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
944 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
945 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
946 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
947 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
948 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
949 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
951 (cf2
.dwMask
& tested_effects
[i
]) == 0),
952 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
954 DestroyWindow(hwndRichEdit
);
957 for (i
= 0; tested_effects
[i
]; i
++)
959 hwndRichEdit
= new_richedit(NULL
);
960 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
962 /* Need to set a TrueType font to get consistent CFM_BOLD results */
963 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
964 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
965 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
967 strcpy(cf2
.szFaceName
, "Courier New");
968 cf2
.wWeight
= FW_DONTCARE
;
969 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
971 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
972 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
973 cf2
.dwMask
= tested_effects
[i
];
974 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
975 cf2
.dwMask
= CFM_SUPERSCRIPT
;
976 cf2
.dwEffects
= tested_effects
[i
];
977 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
978 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
980 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
981 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
982 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
983 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
984 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
985 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
987 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
988 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
989 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
990 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
992 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
993 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
994 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
995 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
996 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
997 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
999 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
1000 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
1001 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
1002 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
1004 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1005 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1006 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
1007 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1008 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
1009 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
1011 (cf2
.dwMask
& tested_effects
[i
]) == 0),
1012 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
1013 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
1014 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
1016 DestroyWindow(hwndRichEdit
);
1019 /* Effects applied on an empty selection should take effect when selection is
1020 replaced with text */
1021 hwndRichEdit
= new_richedit(NULL
);
1022 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1023 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1025 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1026 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1027 cf2
.dwMask
= CFM_BOLD
;
1028 cf2
.dwEffects
= CFE_BOLD
;
1029 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1031 /* Selection is now nonempty */
1032 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1034 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1035 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1036 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1037 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1039 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1040 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1041 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1042 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1045 /* Set two effects on an empty selection */
1046 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1047 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1049 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1050 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1051 cf2
.dwMask
= CFM_BOLD
;
1052 cf2
.dwEffects
= CFE_BOLD
;
1053 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1054 cf2
.dwMask
= CFM_ITALIC
;
1055 cf2
.dwEffects
= CFE_ITALIC
;
1056 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1058 /* Selection is now nonempty */
1059 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1061 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1062 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1063 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1064 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1066 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
1067 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
1068 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
1069 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
1071 /* Setting the (empty) selection to exactly the same place as before should
1072 NOT clear the insertion style! */
1073 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1074 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1076 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1077 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1078 cf2
.dwMask
= CFM_BOLD
;
1079 cf2
.dwEffects
= CFE_BOLD
;
1080 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1082 /* Empty selection in same place, insert style should NOT be forgotten here. */
1083 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2);
1085 /* Selection is now nonempty */
1086 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1088 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1089 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1090 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1091 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1093 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1094 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1095 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1096 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1098 /* Ditto with EM_EXSETSEL */
1099 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1100 cr
.cpMin
= 2; cr
.cpMax
= 2;
1101 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1103 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1104 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1105 cf2
.dwMask
= CFM_BOLD
;
1106 cf2
.dwEffects
= CFE_BOLD
;
1107 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1109 /* Empty selection in same place, insert style should NOT be forgotten here. */
1110 cr
.cpMin
= 2; cr
.cpMax
= 2;
1111 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1113 /* Selection is now nonempty */
1114 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1116 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1117 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1118 cr
.cpMin
= 2; cr
.cpMax
= 6;
1119 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1120 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1122 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1123 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1124 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1125 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1127 DestroyWindow(hwndRichEdit
);
1130 static void test_EM_SETTEXTMODE(void)
1132 HWND hwndRichEdit
= new_richedit(NULL
);
1133 CHARFORMAT2A cf2
, cf2test
;
1137 /*Attempt to use mutually exclusive modes*/
1138 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1139 ok(rc
== E_INVALIDARG
,
1140 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1142 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1143 /*Insert text into the control*/
1145 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1147 /*Attempt to change the control to plain text mode*/
1148 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1149 ok(rc
== E_UNEXPECTED
,
1150 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1152 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1153 If rich text is pasted, it should have the same formatting as the rest
1154 of the text in the control*/
1156 /*Italicize the text
1157 *NOTE: If the default text was already italicized, the test will simply
1158 reverse; in other words, it will copy a regular "wine" into a plain
1159 text window that uses an italicized format*/
1160 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1161 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
1163 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1164 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1166 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1167 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1169 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1170 however, SCF_ALL has been implemented*/
1171 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1172 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1174 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1175 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1177 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1179 /*Select the string "wine"*/
1182 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1184 /*Copy the italicized "wine" to the clipboard*/
1185 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1187 /*Reset the formatting to default*/
1188 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1189 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1190 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1192 /*Clear the text in the control*/
1193 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1195 /*Switch to Plain Text Mode*/
1196 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1197 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1199 /*Input "wine" again in normal format*/
1200 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1202 /*Paste the italicized "wine" into the control*/
1203 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1205 /*Select a character from the first "wine" string*/
1208 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1210 /*Retrieve its formatting*/
1211 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1213 /*Select a character from the second "wine" string*/
1216 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1218 /*Retrieve its formatting*/
1219 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1220 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1222 /*Compare the two formattings*/
1223 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1224 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1225 cf2
.dwEffects
, cf2test
.dwEffects
);
1226 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1227 printing "wine" in the current format(normal)
1228 pasting "wine" from the clipboard(italicized)
1229 comparing the two formats(should differ)*/
1231 /*Attempt to switch with text in control*/
1232 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1233 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1236 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1238 /*Switch into Rich Text mode*/
1239 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1240 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1242 /*Print "wine" in normal formatting into the control*/
1243 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1245 /*Paste italicized "wine" into the control*/
1246 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1248 /*Select text from the first "wine" string*/
1251 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1253 /*Retrieve its formatting*/
1254 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1256 /*Select text from the second "wine" string*/
1259 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1261 /*Retrieve its formatting*/
1262 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1264 /*Test that the two formattings are not the same*/
1265 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1266 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1267 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1269 DestroyWindow(hwndRichEdit
);
1272 static void test_SETPARAFORMAT(void)
1274 HWND hwndRichEdit
= new_richedit(NULL
);
1277 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1278 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1279 fmt
.dwMask
= PFM_ALIGNMENT
;
1280 fmt
.wAlignment
= PFA_LEFT
;
1282 ret
= SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1283 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1285 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1287 ret
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1288 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1289 * between richedit different native builds of riched20.dll
1290 * used on different Windows versions. */
1291 ret
&= ~PFM_TABLEROWDELIMITER
;
1292 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1294 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1295 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1297 DestroyWindow(hwndRichEdit
);
1300 static void test_TM_PLAINTEXT(void)
1302 /*Tests plain text properties*/
1304 HWND hwndRichEdit
= new_richedit(NULL
);
1305 CHARFORMAT2A cf2
, cf2test
;
1309 /*Switch to plain text mode*/
1311 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1312 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1314 /*Fill control with text*/
1316 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Is Wine an emulator? No it's not");
1318 /*Select some text and bold it*/
1322 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1323 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1324 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1326 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1327 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1329 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1330 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1332 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1333 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1335 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1336 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1338 /*Get the formatting of those characters*/
1340 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1342 /*Get the formatting of some other characters*/
1343 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1346 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1347 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1349 /*Test that they are the same as plain text allows only one formatting*/
1351 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1352 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1353 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1355 /*Fill the control with a "wine" string, which when inserted will be bold*/
1357 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1359 /*Copy the bolded "wine" string*/
1363 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1364 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1366 /*Swap back to rich text*/
1368 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1369 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1371 /*Set the default formatting to bold italics*/
1373 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1374 cf2
.dwMask
|= CFM_ITALIC
;
1375 cf2
.dwEffects
^= CFE_ITALIC
;
1376 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1377 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1379 /*Set the text in the control to "wine", which will be bold and italicized*/
1381 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1383 /*Paste the plain text "wine" string, which should take the insert
1384 formatting, which at the moment is bold italics*/
1386 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1388 /*Select the first "wine" string and retrieve its formatting*/
1392 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1393 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1395 /*Select the second "wine" string and retrieve its formatting*/
1399 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1400 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1402 /*Compare the two formattings. They should be the same.*/
1404 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1405 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1406 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1407 DestroyWindow(hwndRichEdit
);
1410 static void test_WM_GETTEXT(void)
1412 HWND hwndRichEdit
= new_richedit(NULL
);
1413 static const char text
[] = "Hello. My name is RichEdit!";
1414 static const char text2
[] = "Hello. My name is RichEdit!\r";
1415 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1416 char buffer
[1024] = {0};
1419 /* Baseline test with normal-sized buffer */
1420 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1421 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1422 ok(result
== lstrlenA(buffer
),
1423 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1424 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1425 result
= strcmp(buffer
,text
);
1427 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1429 /* Test for returned value of WM_GETTEXTLENGTH */
1430 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1431 ok(result
== lstrlenA(text
),
1432 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1433 result
, lstrlenA(text
));
1435 /* Test for behavior in overflow case */
1436 memset(buffer
, 0, 1024);
1437 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1439 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1440 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1441 result
= strcmp(buffer
,text
);
1443 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1445 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1447 /* Baseline test with normal-sized buffer and carriage return */
1448 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1449 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1450 ok(result
== lstrlenA(buffer
),
1451 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1452 result
= strcmp(buffer
,text2_after
);
1454 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1456 /* Test for returned value of WM_GETTEXTLENGTH */
1457 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1458 ok(result
== lstrlenA(text2_after
),
1459 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1460 result
, lstrlenA(text2_after
));
1462 /* Test for behavior of CRLF conversion in case of overflow */
1463 memset(buffer
, 0, 1024);
1464 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1466 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1467 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1468 result
= strcmp(buffer
,text2
);
1470 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1472 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1474 DestroyWindow(hwndRichEdit
);
1477 static void test_EM_GETTEXTRANGE(void)
1479 HWND hwndRichEdit
= new_richedit(NULL
);
1480 const char * text1
= "foo bar\r\nfoo bar";
1481 const char * text2
= "foo bar\rfoo bar";
1482 const char * expect
= "bar\rfoo";
1483 char buffer
[1024] = {0};
1485 TEXTRANGEA textRange
;
1487 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1489 textRange
.lpstrText
= buffer
;
1490 textRange
.chrg
.cpMin
= 4;
1491 textRange
.chrg
.cpMax
= 11;
1492 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1493 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1494 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1496 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1498 textRange
.lpstrText
= buffer
;
1499 textRange
.chrg
.cpMin
= 4;
1500 textRange
.chrg
.cpMax
= 11;
1501 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1502 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1503 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1505 /* cpMax of text length is used instead of -1 in this case */
1506 textRange
.lpstrText
= buffer
;
1507 textRange
.chrg
.cpMin
= 0;
1508 textRange
.chrg
.cpMax
= -1;
1509 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1510 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1511 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1513 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1514 textRange
.lpstrText
= buffer
;
1515 textRange
.chrg
.cpMin
= -1;
1516 textRange
.chrg
.cpMax
= 1;
1517 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1518 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1519 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1521 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1522 textRange
.lpstrText
= buffer
;
1523 textRange
.chrg
.cpMin
= 1;
1524 textRange
.chrg
.cpMax
= -1;
1525 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1526 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1527 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1529 /* no end character is copied if cpMax - cpMin < 0 */
1530 textRange
.lpstrText
= buffer
;
1531 textRange
.chrg
.cpMin
= 5;
1532 textRange
.chrg
.cpMax
= 5;
1533 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1534 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1535 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1537 /* cpMax of text length is used if cpMax > text length*/
1538 textRange
.lpstrText
= buffer
;
1539 textRange
.chrg
.cpMin
= 0;
1540 textRange
.chrg
.cpMax
= 1000;
1541 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1542 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1543 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1545 /* Test with multibyte character */
1546 if (!is_lang_japanese
)
1547 skip("Skip multibyte character tests on non-Japanese platform\n");
1550 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1551 textRange
.chrg
.cpMin
= 4;
1552 textRange
.chrg
.cpMax
= 8;
1553 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1554 todo_wine
ok(result
== 5, "EM_GETTEXTRANGE returned %ld\n", result
);
1555 todo_wine
ok(!strcmp("ef\x8e\xf0g", buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1558 DestroyWindow(hwndRichEdit
);
1561 static void test_EM_GETSELTEXT(void)
1563 HWND hwndRichEdit
= new_richedit(NULL
);
1564 const char * text1
= "foo bar\r\nfoo bar";
1565 const char * text2
= "foo bar\rfoo bar";
1566 const char * expect
= "bar\rfoo";
1567 char buffer
[1024] = {0};
1570 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1572 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1573 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1574 ok(result
== 7, "EM_GETSELTEXT returned %ld\n", result
);
1575 ok(!strcmp(expect
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1577 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1579 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1580 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1581 ok(result
== 7, "EM_GETSELTEXT returned %ld\n", result
);
1582 ok(!strcmp(expect
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1584 /* Test with multibyte character */
1585 if (!is_lang_japanese
)
1586 skip("Skip multibyte character tests on non-Japanese platform\n");
1589 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1590 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
1591 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1592 todo_wine
ok(result
== 5, "EM_GETSELTEXT returned %ld\n", result
);
1593 todo_wine
ok(!strcmp("ef\x8e\xf0g", buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1596 DestroyWindow(hwndRichEdit
);
1599 /* FIXME: need to test unimplemented options and robustly test wparam */
1600 static void test_EM_SETOPTIONS(void)
1603 static const char text
[] = "Hello. My name is RichEdit!";
1604 char buffer
[1024] = {0};
1605 DWORD dwStyle
, options
, oldOptions
;
1606 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1607 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1608 ES_SELECTIONBAR
|ES_VERTICAL
;
1610 /* Test initial options. */
1611 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, WS_POPUP
,
1612 0, 0, 200, 60, NULL
, NULL
,
1613 hmoduleRichEdit
, NULL
);
1614 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1615 RICHEDIT_CLASS20A
, (int) GetLastError());
1616 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1617 ok(options
== 0, "Incorrect initial options %x\n", options
);
1618 DestroyWindow(hwndRichEdit
);
1620 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
1621 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1622 0, 0, 200, 60, NULL
, NULL
,
1623 hmoduleRichEdit
, NULL
);
1624 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1625 RICHEDIT_CLASS20A
, (int) GetLastError());
1626 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1627 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1628 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1629 "Incorrect initial options %x\n", options
);
1631 /* NEGATIVE TESTING - NO OPTIONS SET */
1632 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1633 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1635 /* testing no readonly by sending 'a' to the control*/
1636 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1637 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1639 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1640 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1642 /* READONLY - sending 'a' to the control */
1643 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1644 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1645 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1646 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1647 ok(buffer
[0]==text
[0],
1648 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1650 /* EM_SETOPTIONS changes the window style, but changing the
1651 * window style does not change the options. */
1652 dwStyle
= GetWindowLongA(hwndRichEdit
, GWL_STYLE
);
1653 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1654 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1655 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1656 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1657 /* Confirm that the text is still read only. */
1658 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1659 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1660 ok(buffer
[0]==text
[0],
1661 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1663 oldOptions
= options
;
1664 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1665 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1666 ok(options
== oldOptions
,
1667 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1669 DestroyWindow(hwndRichEdit
);
1672 static BOOL
check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1674 CHARFORMAT2A text_format
;
1675 text_format
.cbSize
= sizeof(text_format
);
1676 SendMessageA(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1677 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&text_format
);
1678 return (text_format
.dwEffects
& CFE_LINK
) != 0;
1681 static void check_CFE_LINK_rcvd(HWND hwnd
, BOOL is_url
, const char * url
)
1683 BOOL link_present
= FALSE
;
1685 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1687 { /* control text is url; should get CFE_LINK */
1688 ok(link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1692 ok(!link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1696 static HWND
new_static_wnd(HWND parent
) {
1697 return new_window("Static", 0, parent
);
1700 static void test_EM_AUTOURLDETECT(void)
1702 /* DO NOT change the properties of the first two elements. To shorten the
1703 tests, all tests after WM_SETTEXT test just the first two elements -
1704 one non-URL and one URL */
1709 {"winehq.org", FALSE
},
1710 {"http://www.winehq.org", TRUE
},
1711 {"http//winehq.org", FALSE
},
1712 {"ww.winehq.org", FALSE
},
1713 {"www.winehq.org", TRUE
},
1714 {"ftp://192.168.1.1", TRUE
},
1715 {"ftp//192.168.1.1", FALSE
},
1716 {"mailto:your@email.com", TRUE
},
1717 {"prospero:prosperoserver", TRUE
},
1718 {"telnet:test", TRUE
},
1719 {"news:newserver", TRUE
},
1720 {"wais:waisserver", TRUE
}
1725 HWND hwndRichEdit
, parent
;
1727 /* All of the following should cause the URL to be detected */
1728 const char * templates_delim
[] = {
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\r 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",
1736 "This is some text with :X: on it",
1738 "This text ends with X",
1740 "This is some text with X) on it",
1741 "This is some text with X--- on it",
1742 "This is some text with X\" on it",
1743 "This is some text with X' on it",
1744 "This is some text with X: on it",
1746 "This is some text with (X on it",
1747 "This is some text with \rX on it",
1748 "This is some text with ---X on it",
1749 "This is some text with \"X on it",
1750 "This is some text with 'X on it",
1751 "This is some text with :X on it",
1753 /* None of these should cause the URL to be detected */
1754 const char * templates_non_delim
[] = {
1755 "This is some text with |X| on it",
1756 "This is some text with *X* on it",
1757 "This is some text with /X/ on it",
1758 "This is some text with +X+ on it",
1759 "This is some text with %X% on it",
1760 "This is some text with #X# on it",
1761 "This is some text with @X@ on it",
1762 "This is some text with \\X\\ on it",
1763 "This is some text with |X on it",
1764 "This is some text with *X on it",
1765 "This is some text with /X on it",
1766 "This is some text with +X on it",
1767 "This is some text with %X on it",
1768 "This is some text with #X on it",
1769 "This is some text with @X on it",
1770 "This is some text with \\X on it",
1772 /* All of these cause the URL detection to be extended by one more byte,
1773 thus demonstrating that the tested character is considered as part
1775 const char * templates_xten_delim
[] = {
1776 "This is some text with X| on it",
1777 "This is some text with X* on it",
1778 "This is some text with X/ on it",
1779 "This is some text with X+ on it",
1780 "This is some text with X% on it",
1781 "This is some text with X# on it",
1782 "This is some text with X@ on it",
1783 "This is some text with X\\ on it",
1787 parent
= new_static_wnd(NULL
);
1788 hwndRichEdit
= new_richedit(parent
);
1789 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1790 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1791 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
1792 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
1793 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
1794 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1795 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
1796 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
1797 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
1798 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
1799 /* for each url, check the text to see if CFE_LINK effect is present */
1800 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1802 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1803 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1804 check_CFE_LINK_rcvd(hwndRichEdit
, FALSE
, urls
[i
].text
);
1806 /* Link detection should happen immediately upon WM_SETTEXT */
1807 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1808 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1809 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
1811 DestroyWindow(hwndRichEdit
);
1813 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1814 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1815 hwndRichEdit
= new_richedit(parent
);
1817 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
1822 at_pos
= strchr(templates_delim
[j
], 'X');
1823 at_offset
= at_pos
- templates_delim
[j
];
1824 memcpy(buffer
, templates_delim
[j
], at_offset
);
1825 buffer
[at_offset
] = '\0';
1826 strcat(buffer
, urls
[i
].text
);
1827 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
1828 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1830 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1831 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1833 /* This assumes no templates start with the URL itself, and that they
1834 have at least two characters before the URL text */
1835 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1836 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1837 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1838 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1839 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1840 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1844 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1845 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1846 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1847 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1851 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1852 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1853 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1854 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1856 if (buffer
[end_offset
] != '\0')
1858 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1859 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1860 if (buffer
[end_offset
+1] != '\0')
1862 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1863 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1868 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
1873 at_pos
= strchr(templates_non_delim
[j
], 'X');
1874 at_offset
= at_pos
- templates_non_delim
[j
];
1875 memcpy(buffer
, templates_non_delim
[j
], at_offset
);
1876 buffer
[at_offset
] = '\0';
1877 strcat(buffer
, urls
[i
].text
);
1878 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
1879 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1881 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1882 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1884 /* This assumes no templates start with the URL itself, and that they
1885 have at least two characters before the URL text */
1886 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1887 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1888 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1889 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1890 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1891 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1893 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1894 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1895 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1896 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1897 if (buffer
[end_offset
] != '\0')
1899 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1900 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1901 if (buffer
[end_offset
+1] != '\0')
1903 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1904 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1909 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
1914 at_pos
= strchr(templates_xten_delim
[j
], 'X');
1915 at_offset
= at_pos
- templates_xten_delim
[j
];
1916 memcpy(buffer
, templates_xten_delim
[j
], at_offset
);
1917 buffer
[at_offset
] = '\0';
1918 strcat(buffer
, urls
[i
].text
);
1919 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
1920 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1922 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1923 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1925 /* This assumes no templates start with the URL itself, and that they
1926 have at least two characters before the URL text */
1927 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1928 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1929 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1930 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1931 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1932 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1936 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1937 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1938 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1939 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1940 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1941 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1945 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1946 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1947 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1948 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1949 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1950 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1952 if (buffer
[end_offset
+1] != '\0')
1954 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1955 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
1956 if (buffer
[end_offset
+2] != '\0')
1958 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1959 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1964 DestroyWindow(hwndRichEdit
);
1965 hwndRichEdit
= NULL
;
1968 /* Test detection of URLs within normal text - WM_CHAR case. */
1969 /* Test only the first two URL examples for brevity */
1970 for (i
= 0; i
< 2; i
++) {
1971 hwndRichEdit
= new_richedit(parent
);
1973 /* Also for brevity, test only the first three delimiters */
1974 for (j
= 0; j
< 3; j
++) {
1980 at_pos
= strchr(templates_delim
[j
], 'X');
1981 at_offset
= at_pos
- templates_delim
[j
];
1982 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1984 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1985 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
1986 for (u
= 0; templates_delim
[j
][u
]; u
++) {
1987 if (templates_delim
[j
][u
] == '\r') {
1988 simulate_typing_characters(hwndRichEdit
, "\r");
1989 } else if (templates_delim
[j
][u
] != 'X') {
1990 SendMessageA(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
1992 for (v
= 0; urls
[i
].text
[v
]; v
++) {
1993 SendMessageA(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
1997 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1999 /* This assumes no templates start with the URL itself, and that they
2000 have at least two characters before the URL text */
2001 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2002 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2003 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2004 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2005 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2006 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2010 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2011 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2012 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2013 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2017 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2018 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2019 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2020 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2022 if (buffer
[end_offset
] != '\0')
2024 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2025 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2026 if (buffer
[end_offset
+1] != '\0')
2028 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2029 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2033 /* The following will insert a paragraph break after the first character
2034 of the URL candidate, thus breaking the URL. It is expected that the
2035 CFE_LINK attribute should break across both pieces of the URL */
2036 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
2037 simulate_typing_characters(hwndRichEdit
, "\r");
2038 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2040 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2041 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2042 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2043 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2044 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2045 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2047 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2048 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2049 /* end_offset moved because of paragraph break */
2050 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2051 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2052 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
2053 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
2055 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2056 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2057 if (buffer
[end_offset
+2] != '\0')
2059 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2060 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2064 /* The following will remove the just-inserted paragraph break, thus
2065 restoring the URL */
2066 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
2067 simulate_typing_characters(hwndRichEdit
, "\b");
2068 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2070 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2071 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2072 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2073 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2074 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2075 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2079 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2080 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2081 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2082 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2086 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2087 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2088 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2089 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2091 if (buffer
[end_offset
] != '\0')
2093 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2094 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2095 if (buffer
[end_offset
+1] != '\0')
2097 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2098 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2102 DestroyWindow(hwndRichEdit
);
2103 hwndRichEdit
= NULL
;
2106 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2107 /* Test just the first two URL examples for brevity */
2108 for (i
= 0; i
< 2; i
++) {
2111 hwndRichEdit
= new_richedit(parent
);
2113 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2115 1) Set entire text, a la WM_SETTEXT
2116 2) Set a selection of the text to the URL
2117 3) Set a portion of the text at a time, which eventually results in
2119 All of them should give equivalent results
2122 /* Set entire text in one go, like WM_SETTEXT */
2123 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2128 st
.codepage
= CP_ACP
;
2129 st
.flags
= ST_DEFAULT
;
2131 at_pos
= strchr(templates_delim
[j
], 'X');
2132 at_offset
= at_pos
- templates_delim
[j
];
2133 memcpy(buffer
, templates_delim
[j
], at_offset
);
2134 buffer
[at_offset
] = '\0';
2135 strcat(buffer
, urls
[i
].text
);
2136 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2137 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2139 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2140 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2142 /* This assumes no templates start with the URL itself, and that they
2143 have at least two characters before the URL text */
2144 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2145 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2146 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2147 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2148 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2149 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2153 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2154 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2155 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2156 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2160 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2161 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2162 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2163 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2165 if (buffer
[end_offset
] != '\0')
2167 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2168 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2169 if (buffer
[end_offset
+1] != '\0')
2171 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2172 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2177 /* Set selection with X to the URL */
2178 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2183 at_pos
= strchr(templates_delim
[j
], 'X');
2184 at_offset
= at_pos
- templates_delim
[j
];
2185 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2187 st
.codepage
= CP_ACP
;
2188 st
.flags
= ST_DEFAULT
;
2189 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2190 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2191 st
.flags
= ST_SELECTION
;
2192 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2193 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)urls
[i
].text
);
2194 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2196 /* This assumes no templates start with the URL itself, and that they
2197 have at least two characters before the URL text */
2198 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2199 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2200 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2201 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2202 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2203 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2207 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2208 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2209 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2210 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2214 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2215 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2216 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2217 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2219 if (buffer
[end_offset
] != '\0')
2221 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2222 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2223 if (buffer
[end_offset
+1] != '\0')
2225 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2226 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2231 /* Set selection with X to the first character of the URL, then the rest */
2232 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2237 at_pos
= strchr(templates_delim
[j
], 'X');
2238 at_offset
= at_pos
- templates_delim
[j
];
2239 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2241 strcpy(buffer
, "YY");
2242 buffer
[0] = urls
[i
].text
[0];
2244 st
.codepage
= CP_ACP
;
2245 st
.flags
= ST_DEFAULT
;
2246 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2247 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2248 st
.flags
= ST_SELECTION
;
2249 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2250 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2251 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2252 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2253 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2255 /* This assumes no templates start with the URL itself, and that they
2256 have at least two characters before the URL text */
2257 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2258 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2259 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2260 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2261 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2262 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2266 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2267 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2268 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2269 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2273 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2274 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2275 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2276 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2278 if (buffer
[end_offset
] != '\0')
2280 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2281 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2282 if (buffer
[end_offset
+1] != '\0')
2284 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2285 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2290 DestroyWindow(hwndRichEdit
);
2291 hwndRichEdit
= NULL
;
2294 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2295 /* Test just the first two URL examples for brevity */
2296 for (i
= 0; i
< 2; i
++) {
2297 hwndRichEdit
= new_richedit(parent
);
2299 /* Set selection with X to the URL */
2300 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2305 at_pos
= strchr(templates_delim
[j
], 'X');
2306 at_offset
= at_pos
- templates_delim
[j
];
2307 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2309 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2310 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2311 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2312 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urls
[i
].text
);
2313 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2315 /* This assumes no templates start with the URL itself, and that they
2316 have at least two characters before the URL text */
2317 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2318 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2319 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2320 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2321 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2322 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2326 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2327 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2328 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2329 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2333 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2334 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2335 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2336 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2338 if (buffer
[end_offset
] != '\0')
2340 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2341 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2342 if (buffer
[end_offset
+1] != '\0')
2344 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2345 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2350 /* Set selection with X to the first character of the URL, then the rest */
2351 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2356 at_pos
= strchr(templates_delim
[j
], 'X');
2357 at_offset
= at_pos
- templates_delim
[j
];
2358 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2360 strcpy(buffer
, "YY");
2361 buffer
[0] = urls
[i
].text
[0];
2363 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2364 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2365 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2366 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)buffer
);
2367 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2368 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2369 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2371 /* This assumes no templates start with the URL itself, and that they
2372 have at least two characters before the URL text */
2373 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2374 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2375 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2376 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2377 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2378 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2382 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2383 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2384 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2385 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2389 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2390 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2391 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2392 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2394 if (buffer
[end_offset
] != '\0')
2396 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2397 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2398 if (buffer
[end_offset
+1] != '\0')
2400 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2401 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2406 DestroyWindow(hwndRichEdit
);
2407 hwndRichEdit
= NULL
;
2410 DestroyWindow(parent
);
2413 static void test_EM_SCROLL(void)
2416 int r
; /* return value */
2417 int expr
; /* expected return value */
2418 HWND hwndRichEdit
= new_richedit(NULL
);
2419 int y_before
, y_after
; /* units of lines of text */
2421 /* test a richedit box containing a single line of text */
2422 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");/* one line of text */
2424 for (i
= 0; i
< 4; i
++) {
2425 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2427 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2428 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2429 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2430 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2431 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2432 "(i == %d)\n", y_after
, i
);
2436 * test a richedit box that will scroll. There are two general
2437 * cases: the case without any long lines and the case with a long
2440 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2442 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\nb\nc\nd\ne");
2444 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2445 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2446 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2447 "LONG LINE \nb\nc\nd\ne");
2448 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2449 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2451 /* get first visible line */
2452 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2453 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2455 /* get new current first visible line */
2456 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2458 ok(((r
& 0xffffff00) == 0x00010000) &&
2459 ((r
& 0x000000ff) != 0x00000000),
2460 "EM_SCROLL page down didn't scroll by a small positive number of "
2461 "lines (r == 0x%08x)\n", r
);
2462 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2463 "(line %d scrolled to line %d\n", y_before
, y_after
);
2467 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2468 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2469 ok(((r
& 0xffffff00) == 0x0001ff00),
2470 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2471 "(r == 0x%08x)\n", r
);
2472 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2473 "%d scrolled to line %d\n", y_before
, y_after
);
2477 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2479 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2481 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2482 "(r == 0x%08x)\n", r
);
2483 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2484 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2488 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2490 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2492 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2493 "(r == 0x%08x)\n", r
);
2494 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2495 "line (%d scrolled to %d)\n", y_before
, y_after
);
2499 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2500 SB_LINEUP
, 0); /* lineup beyond top */
2502 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2505 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2506 ok(y_before
== y_after
,
2507 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2511 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2512 SB_PAGEUP
, 0);/*page up beyond top */
2514 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2517 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2518 ok(y_before
== y_after
,
2519 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2521 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2522 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2523 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2524 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2525 SB_PAGEDOWN
, 0); /* page down beyond bot */
2526 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2529 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2530 ok(y_before
== y_after
,
2531 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2534 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2535 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2536 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2539 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2540 ok(y_before
== y_after
,
2541 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2544 DestroyWindow(hwndRichEdit
);
2547 static unsigned int recursionLevel
= 0;
2548 static unsigned int WM_SIZE_recursionLevel
= 0;
2549 static BOOL bailedOutOfRecursion
= FALSE
;
2550 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2552 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2556 if (bailedOutOfRecursion
) return 0;
2557 if (recursionLevel
>= 32) {
2558 bailedOutOfRecursion
= TRUE
;
2565 WM_SIZE_recursionLevel
++;
2566 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2567 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2568 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2569 WM_SIZE_recursionLevel
--;
2572 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2579 static void test_scrollbar_visibility(void)
2582 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2587 /* These tests show that richedit should temporarily refrain from automatically
2588 hiding or showing its scrollbars (vertical at least) when an explicit request
2589 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2590 Some applications depend on forced showing (when otherwise richedit would
2591 hide the vertical scrollbar) and are thrown on an endless recursive loop
2592 if richedit auto-hides the scrollbar again. Apparently they never heard of
2593 the ES_DISABLENOSCROLL style... */
2595 hwndRichEdit
= new_richedit(NULL
);
2597 /* Test default scrollbar visibility behavior */
2598 memset(&si
, 0, sizeof(si
));
2599 si
.cbSize
= sizeof(si
);
2600 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2601 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2602 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2603 "Vertical scrollbar is visible, should be invisible.\n");
2604 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2605 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2606 si
.nPage
, si
.nMin
, si
.nMax
);
2608 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2609 memset(&si
, 0, sizeof(si
));
2610 si
.cbSize
= sizeof(si
);
2611 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2612 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2613 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2614 "Vertical scrollbar is visible, should be invisible.\n");
2615 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2616 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2617 si
.nPage
, si
.nMin
, si
.nMax
);
2619 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2620 memset(&si
, 0, sizeof(si
));
2621 si
.cbSize
= sizeof(si
);
2622 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2623 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2624 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2625 "Vertical scrollbar is invisible, should be visible.\n");
2626 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2627 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2628 si
.nPage
, si
.nMin
, si
.nMax
);
2630 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2631 even though it hides the scrollbar */
2632 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2633 memset(&si
, 0, sizeof(si
));
2634 si
.cbSize
= sizeof(si
);
2635 si
.fMask
= SIF_PAGE
| SIF_RANGE
;