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
;
2636 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2637 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2638 "Vertical scrollbar is visible, should be invisible.\n");
2639 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2640 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2641 si
.nPage
, si
.nMin
, si
.nMax
);
2643 /* Setting non-scrolling text again does *not* reset scrollbar range */
2644 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2645 memset(&si
, 0, sizeof(si
));
2646 si
.cbSize
= sizeof(si
);
2647 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2648 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2649 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2650 "Vertical scrollbar is visible, should be invisible.\n");
2651 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2652 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2653 si
.nPage
, si
.nMin
, si
.nMax
);
2655 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2656 memset(&si
, 0, sizeof(si
));
2657 si
.cbSize
= sizeof(si
);
2658 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2659 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2660 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2661 "Vertical scrollbar is visible, should be invisible.\n");
2662 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2663 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2664 si
.nPage
, si
.nMin
, si
.nMax
);
2666 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2667 memset(&si
, 0, sizeof(si
));
2668 si
.cbSize
= sizeof(si
);
2669 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2670 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2671 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2672 "Vertical scrollbar is visible, should be invisible.\n");
2673 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2674 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2675 si
.nPage
, si
.nMin
, si
.nMax
);
2677 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2678 memset(&si
, 0, sizeof(si
));
2679 si
.cbSize
= sizeof(si
);
2680 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2681 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2682 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2683 "Vertical scrollbar is visible, should be invisible.\n");
2684 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2685 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2686 si
.nPage
, si
.nMin
, si
.nMax
);
2688 DestroyWindow(hwndRichEdit
);
2690 /* Test again, with ES_DISABLENOSCROLL style */
2691 hwndRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2693 /* Test default scrollbar visibility behavior */
2694 memset(&si
, 0, sizeof(si
));
2695 si
.cbSize
= sizeof(si
);
2696 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2697 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2698 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2699 "Vertical scrollbar is invisible, should be visible.\n");
2700 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2701 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2702 si
.nPage
, si
.nMin
, si
.nMax
);
2704 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2705 memset(&si
, 0, sizeof(si
));
2706 si
.cbSize
= sizeof(si
);
2707 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2708 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2709 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2710 "Vertical scrollbar is invisible, should be visible.\n");
2711 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2712 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2713 si
.nPage
, si
.nMin
, si
.nMax
);
2715 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2716 memset(&si
, 0, sizeof(si
));
2717 si
.cbSize
= sizeof(si
);
2718 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2719 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2720 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2721 "Vertical scrollbar is invisible, should be visible.\n");
2722 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2723 "reported page/range is %d (%d..%d)\n",
2724 si
.nPage
, si
.nMin
, si
.nMax
);
2726 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2727 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2728 memset(&si
, 0, sizeof(si
));
2729 si
.cbSize
= sizeof(si
);
2730 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2731 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2732 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2733 "Vertical scrollbar is invisible, should be visible.\n");
2734 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2735 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2736 si
.nPage
, si
.nMin
, si
.nMax
);
2738 /* Setting non-scrolling text again does *not* reset scrollbar range */
2739 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2740 memset(&si
, 0, sizeof(si
));
2741 si
.cbSize
= sizeof(si
);
2742 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2743 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2744 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2745 "Vertical scrollbar is invisible, should be visible.\n");
2746 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2747 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2748 si
.nPage
, si
.nMin
, si
.nMax
);
2750 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2751 memset(&si
, 0, sizeof(si
));
2752 si
.cbSize
= sizeof(si
);
2753 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2754 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2755 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2756 "Vertical scrollbar is invisible, should be visible.\n");
2757 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2758 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2759 si
.nPage
, si
.nMin
, si
.nMax
);
2761 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2762 memset(&si
, 0, sizeof(si
));
2763 si
.cbSize
= sizeof(si
);
2764 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2765 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2766 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2767 "Vertical scrollbar is invisible, should be visible.\n");
2768 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2769 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2770 si
.nPage
, si
.nMin
, si
.nMax
);
2772 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2773 memset(&si
, 0, sizeof(si
));
2774 si
.cbSize
= sizeof(si
);
2775 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2776 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2777 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2778 "Vertical scrollbar is invisible, should be visible.\n");
2779 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2780 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2781 si
.nPage
, si
.nMin
, si
.nMax
);
2783 DestroyWindow(hwndRichEdit
);
2785 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2786 hwndRichEdit
= new_richedit(NULL
);
2788 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2789 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
2790 memset(&si
, 0, sizeof(si
));
2791 si
.cbSize
= sizeof(si
);
2792 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2793 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2794 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2795 "Vertical scrollbar is invisible, should be visible.\n");
2797 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2798 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2799 si
.nPage
, si
.nMin
, si
.nMax
);
2802 /* Ditto, see above */
2803 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2804 memset(&si
, 0, sizeof(si
));
2805 si
.cbSize
= sizeof(si
);
2806 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2807 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2808 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2809 "Vertical scrollbar is invisible, should be visible.\n");
2811 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2812 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2813 si
.nPage
, si
.nMin
, si
.nMax
);
2816 /* Ditto, see above */
2817 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2818 memset(&si
, 0, sizeof(si
));
2819 si
.cbSize
= sizeof(si
);
2820 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2821 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2822 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2823 "Vertical scrollbar is invisible, should be visible.\n");
2825 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2826 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2827 si
.nPage
, si
.nMin
, si
.nMax
);
2830 /* Ditto, see above */
2831 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2832 memset(&si
, 0, sizeof(si
));
2833 si
.cbSize
= sizeof(si
);
2834 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2835 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2836 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2837 "Vertical scrollbar is invisible, should be visible.\n");
2839 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2840 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2841 si
.nPage
, si
.nMin
, si
.nMax
);
2844 /* Ditto, see above */
2845 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2846 memset(&si
, 0, sizeof(si
));
2847 si
.cbSize
= sizeof(si
);
2848 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2849 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2850 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2851 "Vertical scrollbar is invisible, should be visible.\n");
2853 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2854 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2855 si
.nPage
, si
.nMin
, si
.nMax
);
2858 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2859 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2860 memset(&si
, 0, sizeof(si
));
2861 si
.cbSize
= sizeof(si
);
2862 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2863 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2864 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2865 "Vertical scrollbar is visible, should be invisible.\n");
2866 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2867 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2868 si
.nPage
, si
.nMin
, si
.nMax
);
2870 DestroyWindow(hwndRichEdit
);
2872 hwndRichEdit
= new_richedit(NULL
);
2874 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2875 memset(&si
, 0, sizeof(si
));
2876 si
.cbSize
= sizeof(si
);
2877 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2878 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2879 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2880 "Vertical scrollbar is visible, should be invisible.\n");
2881 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2882 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2883 si
.nPage
, si
.nMin
, si
.nMax
);
2885 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2886 memset(&si
, 0, sizeof(si
));
2887 si
.cbSize
= sizeof(si
);
2888 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2889 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2890 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2891 "Vertical scrollbar is visible, should be invisible.\n");
2892 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2893 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2894 si
.nPage
, si
.nMin
, si
.nMax
);
2896 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2897 memset(&si
, 0, sizeof(si
));
2898 si
.cbSize
= sizeof(si
);
2899 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2900 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2901 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2902 "Vertical scrollbar is visible, should be invisible.\n");
2903 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2904 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2905 si
.nPage
, si
.nMin
, si
.nMax
);
2907 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2908 memset(&si
, 0, sizeof(si
));
2909 si
.cbSize
= sizeof(si
);
2910 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2911 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2912 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2913 "Vertical scrollbar is visible, should be invisible.\n");
2914 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2915 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2916 si
.nPage
, si
.nMin
, si
.nMax
);
2918 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2919 memset(&si
, 0, sizeof(si
));
2920 si
.cbSize
= sizeof(si
);
2921 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2922 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2923 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2924 "Vertical scrollbar is invisible, should be visible.\n");
2925 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2926 "reported page/range is %d (%d..%d)\n",
2927 si
.nPage
, si
.nMin
, si
.nMax
);
2929 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2930 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2931 memset(&si
, 0, sizeof(si
));
2932 si
.cbSize
= sizeof(si
);
2933 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2934 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2935 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2936 "Vertical scrollbar is visible, should be invisible.\n");
2937 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2938 "reported page/range is %d (%d..%d)\n",
2939 si
.nPage
, si
.nMin
, si
.nMax
);
2941 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2942 memset(&si
, 0, sizeof(si
));
2943 si
.cbSize
= sizeof(si
);
2944 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2945 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2946 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2947 "Vertical scrollbar is visible, should be invisible.\n");
2948 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2949 "reported page/range is %d (%d..%d)\n",
2950 si
.nPage
, si
.nMin
, si
.nMax
);
2952 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2953 EM_SCROLL will make visible any forcefully invisible scrollbar */
2954 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
2955 memset(&si
, 0, sizeof(si
));
2956 si
.cbSize
= sizeof(si
);
2957 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2958 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2959 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2960 "Vertical scrollbar is invisible, should be visible.\n");
2961 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2962 "reported page/range is %d (%d..%d)\n",
2963 si
.nPage
, si
.nMin
, si
.nMax
);
2965 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2966 memset(&si
, 0, sizeof(si
));
2967 si
.cbSize
= sizeof(si
);
2968 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2969 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2970 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2971 "Vertical scrollbar is visible, should be invisible.\n");
2972 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2973 "reported page/range is %d (%d..%d)\n",
2974 si
.nPage
, si
.nMin
, si
.nMax
);
2976 /* Again, EM_SCROLL, with SB_LINEUP */
2977 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
2978 memset(&si
, 0, sizeof(si
));
2979 si
.cbSize
= sizeof(si
);
2980 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2981 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2982 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2983 "Vertical scrollbar is invisible, should be visible.\n");
2984 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2985 "reported page/range is %d (%d..%d)\n",
2986 si
.nPage
, si
.nMin
, si
.nMax
);
2988 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2989 memset(&si
, 0, sizeof(si
));
2990 si
.cbSize
= sizeof(si
);
2991 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2992 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2993 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2994 "Vertical scrollbar is visible, should be invisible.\n");
2995 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2996 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2997 si
.nPage
, si
.nMin
, si
.nMax
);
2999 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3000 memset(&si
, 0, sizeof(si
));
3001 si
.cbSize
= sizeof(si
);
3002 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3003 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3004 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3005 "Vertical scrollbar is invisible, should be visible.\n");
3006 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3007 "reported page/range is %d (%d..%d)\n",
3008 si
.nPage
, si
.nMin
, si
.nMax
);
3010 DestroyWindow(hwndRichEdit
);
3013 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
3014 hwndRichEdit
= new_richedit(NULL
);
3016 #define ENABLE_WS_VSCROLL(hwnd) \
3017 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
3018 #define DISABLE_WS_VSCROLL(hwnd) \
3019 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
3021 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3022 ENABLE_WS_VSCROLL(hwndRichEdit
);
3023 memset(&si
, 0, sizeof(si
));
3024 si
.cbSize
= sizeof(si
);
3025 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3026 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3027 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3028 "Vertical scrollbar is invisible, should be visible.\n");
3029 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3030 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3031 si
.nPage
, si
.nMin
, si
.nMax
);
3033 /* Ditto, see above */
3034 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3035 memset(&si
, 0, sizeof(si
));
3036 si
.cbSize
= sizeof(si
);
3037 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3038 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3039 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3040 "Vertical scrollbar is invisible, should be visible.\n");
3041 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3042 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3043 si
.nPage
, si
.nMin
, si
.nMax
);
3045 /* Ditto, see above */
3046 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3047 memset(&si
, 0, sizeof(si
));
3048 si
.cbSize
= sizeof(si
);
3049 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3050 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3051 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3052 "Vertical scrollbar is invisible, should be visible.\n");
3053 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3054 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3055 si
.nPage
, si
.nMin
, si
.nMax
);
3057 /* Ditto, see above */
3058 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
3059 memset(&si
, 0, sizeof(si
));
3060 si
.cbSize
= sizeof(si
);
3061 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3062 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3063 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3064 "Vertical scrollbar is invisible, should be visible.\n");
3065 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3066 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3067 si
.nPage
, si
.nMin
, si
.nMax
);
3069 /* Ditto, see above */
3070 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3071 memset(&si
, 0, sizeof(si
));
3072 si
.cbSize
= sizeof(si
);
3073 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3074 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3075 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3076 "Vertical scrollbar is invisible, should be visible.\n");
3077 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3078 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3079 si
.nPage
, si
.nMin
, si
.nMax
);
3081 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3082 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3083 memset(&si
, 0, sizeof(si
));
3084 si
.cbSize
= sizeof(si
);
3085 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3086 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3087 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3088 "Vertical scrollbar is visible, should be invisible.\n");
3089 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3090 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3091 si
.nPage
, si
.nMin
, si
.nMax
);
3093 DestroyWindow(hwndRichEdit
);
3095 hwndRichEdit
= new_richedit(NULL
);
3097 DISABLE_WS_VSCROLL(hwndRichEdit
);
3098 memset(&si
, 0, sizeof(si
));
3099 si
.cbSize
= sizeof(si
);
3100 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3101 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3102 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3103 "Vertical scrollbar is visible, should be invisible.\n");
3104 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3105 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3106 si
.nPage
, si
.nMin
, si
.nMax
);
3108 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3109 memset(&si
, 0, sizeof(si
));
3110 si
.cbSize
= sizeof(si
);
3111 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3112 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3113 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3114 "Vertical scrollbar is visible, should be invisible.\n");
3115 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3116 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3117 si
.nPage
, si
.nMin
, si
.nMax
);
3119 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3120 memset(&si
, 0, sizeof(si
));
3121 si
.cbSize
= sizeof(si
);
3122 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3123 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3124 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3125 "Vertical scrollbar is visible, should be invisible.\n");
3126 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3127 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3128 si
.nPage
, si
.nMin
, si
.nMax
);
3130 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3131 memset(&si
, 0, sizeof(si
));
3132 si
.cbSize
= sizeof(si
);
3133 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3134 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3135 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3136 "Vertical scrollbar is visible, should be invisible.\n");
3137 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3138 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3139 si
.nPage
, si
.nMin
, si
.nMax
);
3141 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3142 memset(&si
, 0, sizeof(si
));
3143 si
.cbSize
= sizeof(si
);
3144 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3145 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3146 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3147 "Vertical scrollbar is invisible, should be visible.\n");
3148 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3149 "reported page/range is %d (%d..%d)\n",
3150 si
.nPage
, si
.nMin
, si
.nMax
);
3152 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3153 DISABLE_WS_VSCROLL(hwndRichEdit
);
3154 memset(&si
, 0, sizeof(si
));
3155 si
.cbSize
= sizeof(si
);
3156 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3157 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3158 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3159 "Vertical scrollbar is visible, should be invisible.\n");
3160 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3161 "reported page/range is %d (%d..%d)\n",
3162 si
.nPage
, si
.nMin
, si
.nMax
);
3164 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3165 memset(&si
, 0, sizeof(si
));
3166 si
.cbSize
= sizeof(si
);
3167 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3168 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3169 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3170 "Vertical scrollbar is visible, should be invisible.\n");
3171 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3172 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3173 si
.nPage
, si
.nMin
, si
.nMax
);
3175 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3176 memset(&si
, 0, sizeof(si
));
3177 si
.cbSize
= sizeof(si
);
3178 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3179 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3180 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3181 "Vertical scrollbar is invisible, should be visible.\n");
3182 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3183 "reported page/range is %d (%d..%d)\n",
3184 si
.nPage
, si
.nMin
, si
.nMax
);
3186 DISABLE_WS_VSCROLL(hwndRichEdit
);
3187 memset(&si
, 0, sizeof(si
));
3188 si
.cbSize
= sizeof(si
);
3189 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3190 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3191 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3192 "Vertical scrollbar is visible, should be invisible.\n");
3193 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3194 "reported page/range is %d (%d..%d)\n",
3195 si
.nPage
, si
.nMin
, si
.nMax
);
3197 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3198 EM_SCROLL will make visible any forcefully invisible scrollbar */
3199 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3200 memset(&si
, 0, sizeof(si
));
3201 si
.cbSize
= sizeof(si
);
3202 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3203 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3204 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3205 "Vertical scrollbar is invisible, should be visible.\n");
3206 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3207 "reported page/range is %d (%d..%d)\n",
3208 si
.nPage
, si
.nMin
, si
.nMax
);
3210 DISABLE_WS_VSCROLL(hwndRichEdit
);
3211 memset(&si
, 0, sizeof(si
));
3212 si
.cbSize
= sizeof(si
);
3213 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3214 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3215 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3216 "Vertical scrollbar is visible, should be invisible.\n");
3217 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3218 "reported page/range is %d (%d..%d)\n",
3219 si
.nPage
, si
.nMin
, si
.nMax
);
3221 /* Again, EM_SCROLL, with SB_LINEUP */
3222 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3223 memset(&si
, 0, sizeof(si
));
3224 si
.cbSize
= sizeof(si
);
3225 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3226 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3227 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3228 "Vertical scrollbar is invisible, should be visible.\n");
3229 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3230 "reported page/range is %d (%d..%d)\n",
3231 si
.nPage
, si
.nMin
, si
.nMax
);
3233 DestroyWindow(hwndRichEdit
);
3235 /* This window proc models what is going on with Corman Lisp 3.0.
3236 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3237 force the scrollbar into visibility. Recursion should NOT happen
3238 as a result of this action.
3240 r
= GetClassInfoA(NULL
, RICHEDIT_CLASS20A
, &cls
);
3242 richeditProc
= cls
.lpfnWndProc
;
3243 cls
.lpfnWndProc
= RicheditStupidOverrideProcA
;
3244 cls
.lpszClassName
= "RicheditStupidOverride";
3245 if(!RegisterClassA(&cls
)) assert(0);
3248 WM_SIZE_recursionLevel
= 0;
3249 bailedOutOfRecursion
= FALSE
;
3250 hwndRichEdit
= new_window(cls
.lpszClassName
, ES_MULTILINE
, NULL
);
3251 ok(!bailedOutOfRecursion
,
3252 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3255 WM_SIZE_recursionLevel
= 0;
3256 bailedOutOfRecursion
= FALSE
;
3257 MoveWindow(hwndRichEdit
, 0, 0, 250, 100, TRUE
);
3258 ok(!bailedOutOfRecursion
,
3259 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3261 /* Unblock window in order to process WM_DESTROY */
3263 bailedOutOfRecursion
= FALSE
;
3264 WM_SIZE_recursionLevel
= 0;
3265 DestroyWindow(hwndRichEdit
);
3269 static void test_EM_SETUNDOLIMIT(void)
3271 /* cases we test for:
3272 * default behaviour - limiting at 100 undo's
3273 * undo disabled - setting a limit of 0
3274 * undo limited - undo limit set to some to some number, like 2
3275 * bad input - sending a negative number should default to 100 undo's */
3277 HWND hwndRichEdit
= new_richedit(NULL
);
3282 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
3285 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
3286 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3287 also, multiple pastes don't combine like WM_CHAR would */
3288 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3290 /* first case - check the default */
3291 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3292 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
3293 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3294 for (i
=0; i
<100; i
++) /* Undo 100 of them */
3295 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3296 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3297 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3299 /* second case - cannot undo */
3300 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3301 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
3302 SendMessageA(hwndRichEdit
,
3303 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
3304 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3305 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3307 /* third case - set it to an arbitrary number */
3308 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3309 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
3310 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3311 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3312 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3313 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3314 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0,0),
3315 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3316 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3317 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3318 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3319 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3320 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3321 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3323 /* fourth case - setting negative numbers should default to 100 undos */
3324 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3325 result
= SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
3327 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
3329 DestroyWindow(hwndRichEdit
);
3332 static void test_ES_PASSWORD(void)
3334 /* This isn't hugely testable, so we're just going to run it through its paces */
3336 HWND hwndRichEdit
= new_richedit(NULL
);
3339 /* First, check the default of a regular control */
3340 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3342 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
3344 /* Now, set it to something normal */
3345 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
3346 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3348 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3350 /* Now, set it to something odd */
3351 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
3352 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3354 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3355 DestroyWindow(hwndRichEdit
);
3358 LONG streamout_written
= 0;
3360 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
3365 char** str
= (char**)dwCookie
;
3368 memcpy(*str
, pbBuff
, *pcb
);
3371 streamout_written
= *pcb
;
3375 static void test_WM_SETTEXT(void)
3377 HWND hwndRichEdit
= new_richedit(NULL
);
3378 const char * TestItem1
= "TestSomeText";
3379 const char * TestItem2
= "TestSomeText\r";
3380 const char * TestItem2_after
= "TestSomeText\r\n";
3381 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
3382 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
3383 const char * TestItem4
= "TestSomeText\n\nTestSomeText";
3384 const char * TestItem4_after
= "TestSomeText\r\n\r\nTestSomeText";
3385 const char * TestItem5
= "TestSomeText\r\r\nTestSomeText";
3386 const char * TestItem5_after
= "TestSomeText TestSomeText";
3387 const char * TestItem6
= "TestSomeText\r\r\n\rTestSomeText";
3388 const char * TestItem6_after
= "TestSomeText \r\nTestSomeText";
3389 const char * TestItem7
= "TestSomeText\r\n\r\r\n\rTestSomeText";
3390 const char * TestItem7_after
= "TestSomeText\r\n \r\nTestSomeText";
3392 const char rtftextA
[] = "{\\rtf sometext}";
3393 const char urtftextA
[] = "{\\urtf sometext}";
3394 const WCHAR rtftextW
[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3395 const WCHAR urtftextW
[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3396 const WCHAR sometextW
[] = {'s','o','m','e','t','e','x','t',0};
3398 char buf
[1024] = {0};
3399 WCHAR bufW
[1024] = {0};
3402 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3403 any solitary \r to be converted to \r\n on return. Properly paired
3404 \r\n are not affected. It also shows that the special sequence \r\r\n
3405 gets converted to a single space.
3408 #define TEST_SETTEXT(a, b) \
3409 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3410 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3411 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3412 ok (result == lstrlenA(buf), \
3413 "WM_GETTEXT returned %ld instead of expected %u\n", \
3414 result, lstrlenA(buf)); \
3415 result = strcmp(b, buf); \
3417 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3419 TEST_SETTEXT(TestItem1
, TestItem1
)
3420 TEST_SETTEXT(TestItem2
, TestItem2_after
)
3421 TEST_SETTEXT(TestItem3
, TestItem3_after
)
3422 TEST_SETTEXT(TestItem3_after
, TestItem3_after
)
3423 TEST_SETTEXT(TestItem4
, TestItem4_after
)
3424 TEST_SETTEXT(TestItem5
, TestItem5_after
)
3425 TEST_SETTEXT(TestItem6
, TestItem6_after
)
3426 TEST_SETTEXT(TestItem7
, TestItem7_after
)
3428 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3429 TEST_SETTEXT(rtftextA
, "sometext") /* interpreted as ascii rtf */
3430 TEST_SETTEXT(urtftextA
, "sometext") /* interpreted as ascii rtf */
3431 TEST_SETTEXT(rtftextW
, "{") /* interpreted as ascii text */
3432 TEST_SETTEXT(urtftextW
, "{") /* interpreted as ascii text */
3433 DestroyWindow(hwndRichEdit
);
3436 #define TEST_SETTEXTW(a, b) \
3437 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3438 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3439 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3440 ok (result == lstrlenW(bufW), \
3441 "WM_GETTEXT returned %ld instead of expected %u\n", \
3442 result, lstrlenW(bufW)); \
3443 result = lstrcmpW(b, bufW); \
3444 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3446 hwndRichEdit
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
3447 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
3448 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
3449 ok(hwndRichEdit
!= NULL
, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3450 TEST_SETTEXTW(rtftextA
, sometextW
) /* interpreted as ascii rtf */
3451 TEST_SETTEXTW(urtftextA
, sometextW
) /* interpreted as ascii rtf */
3452 TEST_SETTEXTW(rtftextW
, rtftextW
) /* interpreted as ascii text */
3453 TEST_SETTEXTW(urtftextW
, urtftextW
) /* interpreted as ascii text */
3454 DestroyWindow(hwndRichEdit
);
3455 #undef TEST_SETTEXTW
3458 /* Set *pcb to one to show that the remaining cb-1 bytes are not
3459 resent to the callkack. */
3460 static DWORD CALLBACK
test_esCallback_written_1(DWORD_PTR dwCookie
,
3465 char** str
= (char**)dwCookie
;
3466 ok(*pcb
== cb
|| *pcb
== 0, "cb %d, *pcb %d\n", cb
, *pcb
);
3469 memcpy(*str
, pbBuff
, cb
);
3476 static int count_pars(const char *buf
)
3478 const char *p
= buf
;
3480 while ((p
= strstr( p
, "\\par" )) != NULL
)
3482 if (!isalpha( p
[4] ))
3489 static void test_EM_STREAMOUT(void)
3491 HWND hwndRichEdit
= new_richedit(NULL
);
3494 char buf
[1024] = {0};
3498 const char * TestItem1
= "TestSomeText";
3499 const char * TestItem2
= "TestSomeText\r";
3500 const char * TestItem3
= "TestSomeText\r\n";
3502 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem1
);
3504 es
.dwCookie
= (DWORD_PTR
)&p
;
3506 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3507 memset(buf
, 0, sizeof(buf
));
3508 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3510 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
3511 ok(strcmp(buf
, TestItem1
) == 0,
3512 "streamed text different, got %s\n", buf
);
3513 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3515 /* RTF mode writes the final end of para \r if it's part of the selection */
3517 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3518 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3519 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3521 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 12);
3522 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3523 ok (count_pars(buf
) == 0, "got %s\n", buf
);
3524 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3526 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3527 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3528 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3529 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3531 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
3533 es
.dwCookie
= (DWORD_PTR
)&p
;
3535 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3536 memset(buf
, 0, sizeof(buf
));
3537 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3538 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3540 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3541 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3542 ok(strcmp(buf
, TestItem3
) == 0,
3543 "streamed text different from, got %s\n", buf
);
3545 /* And again RTF mode writes the final end of para \r if it's part of the selection */
3547 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3548 ok (count_pars(buf
) == 2, "got %s\n", buf
);
3549 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3551 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 13);
3552 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3553 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3554 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3556 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3557 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3558 ok (count_pars(buf
) == 2, "got %s\n", buf
);
3559 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3561 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem3
);
3563 es
.dwCookie
= (DWORD_PTR
)&p
;
3565 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3566 memset(buf
, 0, sizeof(buf
));
3567 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3568 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3570 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3571 ok(strcmp(buf
, TestItem3
) == 0,
3572 "streamed text different, got %s\n", buf
);
3574 /* Use a callback that sets *pcb to one */
3576 es
.dwCookie
= (DWORD_PTR
)&p
;
3578 es
.pfnCallback
= test_esCallback_written_1
;
3579 memset(buf
, 0, sizeof(buf
));
3580 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3582 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3583 ok(strcmp(buf
, TestItem3
) == 0,
3584 "streamed text different, got %s\n", buf
);
3585 ok(result
== 0, "got %ld expected 0\n", result
);
3588 DestroyWindow(hwndRichEdit
);
3591 static void test_EM_STREAMOUT_FONTTBL(void)
3593 HWND hwndRichEdit
= new_richedit(NULL
);
3595 char buf
[1024] = {0};
3600 const char * TestItem
= "TestSomeText";
3602 /* fills in the richedit control with some text */
3603 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem
);
3605 /* streams out the text in rtf format */
3607 es
.dwCookie
= (DWORD_PTR
)&p
;
3609 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3610 memset(buf
, 0, sizeof(buf
));
3611 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3613 /* scans for \fonttbl, error if not found */
3614 fontTbl
= strstr(buf
, "\\fonttbl");
3615 ok(fontTbl
!= NULL
, "missing \\fonttbl section\n");
3618 /* scans for terminating closing bracket */
3620 while(*fontTbl
&& brackCount
)
3624 else if(*fontTbl
== '}')
3628 /* checks whether closing bracket is ok */
3629 ok(brackCount
== 0, "missing closing bracket in \\fonttbl block\n");
3632 /* char before closing fonttbl block should be a closed bracket */
3634 ok(*fontTbl
== '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl
);
3636 /* char after fonttbl block should be a crlf */
3638 ok(*fontTbl
== 0x0d && *(fontTbl
+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3641 DestroyWindow(hwndRichEdit
);
3645 static void test_EM_SETTEXTEX(void)
3647 HWND hwndRichEdit
, parent
;
3649 int sel_start
, sel_end
;
3652 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
3654 'T', 'e', 'x', 't', 0};
3655 WCHAR TestItem1alt
[] = {'T', 'T', 'e', 's',
3661 WCHAR TestItem1altn
[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
3662 '\r','t','S','o','m','e','T','e','x','t',0};
3663 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
3667 const char * TestItem2_after
= "TestSomeText\r\n";
3668 WCHAR TestItem3
[] = {'T', 'e', 's', 't',
3671 '\r','\n','\r','\n', 0};
3672 WCHAR TestItem3alt
[] = {'T', 'e', 's', 't',
3676 WCHAR TestItem3_after
[] = {'T', 'e', 's', 't',
3680 WCHAR TestItem4
[] = {'T', 'e', 's', 't',
3683 '\r','\r','\n','\r',
3685 WCHAR TestItem4_after
[] = {'T', 'e', 's', 't',
3689 #define MAX_BUF_LEN 1024
3690 WCHAR buf
[MAX_BUF_LEN
];
3691 char bufACP
[MAX_BUF_LEN
];
3698 /* Test the scroll position with and without a parent window.
3700 * For some reason the scroll position is 0 after EM_SETTEXTEX
3701 * with the ST_SELECTION flag only when the control has a parent
3702 * window, even though the selection is at the end. */
3704 cls
.lpfnWndProc
= DefWindowProcA
;
3707 cls
.hInstance
= GetModuleHandleA(0);
3709 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
3710 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
3711 cls
.lpszMenuName
= NULL
;
3712 cls
.lpszClassName
= "ParentTestClass";
3713 if(!RegisterClassA(&cls
)) assert(0);
3715 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
3716 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
3717 ok (parent
!= 0, "Failed to create parent window\n");
3719 hwndRichEdit
= CreateWindowExA(0,
3720 RICHEDIT_CLASS20A
, NULL
,
3721 ES_MULTILINE
|WS_VSCROLL
|WS_VISIBLE
|WS_CHILD
,
3722 0, 0, 200, 60, parent
, NULL
,
3723 hmoduleRichEdit
, NULL
);
3725 setText
.codepage
= CP_ACP
;
3726 setText
.flags
= ST_SELECTION
;
3727 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3728 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3729 todo_wine
ok(result
== 18, "EM_SETTEXTEX returned %d, expected 18\n", result
);
3730 si
.cbSize
= sizeof(si
);
3732 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3733 todo_wine
ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3734 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3735 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3736 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3738 DestroyWindow(parent
);
3740 /* Test without a parent window */
3741 hwndRichEdit
= new_richedit(NULL
);
3742 setText
.codepage
= CP_ACP
;
3743 setText
.flags
= ST_SELECTION
;
3744 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3745 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3746 todo_wine
ok(result
== 18, "EM_SETTEXTEX returned %d, expected 18\n", result
);
3747 si
.cbSize
= sizeof(si
);
3749 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3750 ok(si
.nPos
!= 0, "Position is incorrectly at %d\n", si
.nPos
);
3751 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3752 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3753 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3755 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
3756 * but this time it is because the selection is at the beginning. */
3757 setText
.codepage
= CP_ACP
;
3758 setText
.flags
= ST_DEFAULT
;
3759 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3760 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3761 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3762 si
.cbSize
= sizeof(si
);
3764 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3765 ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3766 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3767 ok(sel_start
== 0, "Selection start incorrectly at %d\n", sel_start
);
3768 ok(sel_end
== 0, "Selection end incorrectly at %d\n", sel_end
);
3770 setText
.codepage
= 1200; /* no constant for unicode */
3771 getText
.codepage
= 1200; /* no constant for unicode */
3772 getText
.cb
= MAX_BUF_LEN
;
3773 getText
.flags
= GT_DEFAULT
;
3774 getText
.lpDefaultChar
= NULL
;
3775 getText
.lpUsedDefChar
= NULL
;
3778 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3779 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3780 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3781 ok(lstrcmpW(buf
, TestItem1
) == 0,
3782 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3784 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
3785 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
3787 setText
.codepage
= 1200; /* no constant for unicode */
3788 getText
.codepage
= 1200; /* no constant for unicode */
3789 getText
.cb
= MAX_BUF_LEN
;
3790 getText
.flags
= GT_DEFAULT
;
3791 getText
.lpDefaultChar
= NULL
;
3792 getText
.lpUsedDefChar
= NULL
;
3794 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem2
);
3795 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3796 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3797 ok(lstrcmpW(buf
, TestItem2
) == 0,
3798 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3800 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
3801 SendMessageA(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
3802 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
3803 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
3805 /* Baseline test for just-enough buffer space for string */
3806 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3807 getText
.codepage
= 1200; /* no constant for unicode */
3808 getText
.flags
= GT_DEFAULT
;
3809 getText
.lpDefaultChar
= NULL
;
3810 getText
.lpUsedDefChar
= NULL
;
3811 memset(buf
, 0, MAX_BUF_LEN
);
3812 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3813 ok(lstrcmpW(buf
, TestItem2
) == 0,
3814 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3816 /* When there is enough space for one character, but not both, of the CRLF
3817 pair at the end of the string, the CR is not copied at all. That is,
3818 the caller must not see CRLF pairs truncated to CR at the end of the
3821 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3822 getText
.codepage
= 1200; /* no constant for unicode */
3823 getText
.flags
= GT_USECRLF
; /* <-- asking for CR -> CRLF conversion */
3824 getText
.lpDefaultChar
= NULL
;
3825 getText
.lpUsedDefChar
= NULL
;
3826 memset(buf
, 0, MAX_BUF_LEN
);
3827 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3828 ok(lstrcmpW(buf
, TestItem1
) == 0,
3829 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3832 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
3833 setText
.codepage
= 1200; /* no constant for unicode */
3834 getText
.codepage
= 1200; /* no constant for unicode */
3835 getText
.cb
= MAX_BUF_LEN
;
3836 getText
.flags
= GT_DEFAULT
;
3837 getText
.lpDefaultChar
= NULL
;
3838 getText
.lpUsedDefChar
= NULL
;
3840 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3
);
3841 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3842 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3843 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3844 "EM_SETTEXTEX did not convert properly\n");
3846 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
3847 setText
.codepage
= 1200; /* no constant for unicode */
3848 getText
.codepage
= 1200; /* no constant for unicode */
3849 getText
.cb
= MAX_BUF_LEN
;
3850 getText
.flags
= GT_DEFAULT
;
3851 getText
.lpDefaultChar
= NULL
;
3852 getText
.lpUsedDefChar
= NULL
;
3854 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3alt
);
3855 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3856 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3857 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3858 "EM_SETTEXTEX did not convert properly\n");
3860 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
3861 setText
.codepage
= 1200; /* no constant for unicode */
3862 getText
.codepage
= 1200; /* no constant for unicode */
3863 getText
.cb
= MAX_BUF_LEN
;
3864 getText
.flags
= GT_DEFAULT
;
3865 getText
.lpDefaultChar
= NULL
;
3866 getText
.lpUsedDefChar
= NULL
;
3868 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem4
);
3869 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3870 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3871 ok(lstrcmpW(buf
, TestItem4_after
) == 0,
3872 "EM_SETTEXTEX did not convert properly\n");
3874 /* !ST_SELECTION && Unicode && !\rtf */
3875 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3876 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3879 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
3880 ok(!buf
[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
3882 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3884 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3885 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3886 /* select some text */
3889 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3890 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3891 setText
.flags
= ST_SELECTION
;
3892 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3894 "EM_SETTEXTEX with NULL lParam to replace selection"
3895 " with no text should return 0. Got %i\n",
3898 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3900 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3901 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3902 /* select some text */
3905 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3906 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3907 setText
.flags
= ST_SELECTION
;
3908 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3910 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3911 ok(result
== lstrlenW(TestItem1
),
3912 "EM_SETTEXTEX with NULL lParam to replace selection"
3913 " with no text should return 0. Got %i\n",
3915 ok(lstrlenW(buf
) == 22,
3916 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
3919 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
3920 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3922 es
.dwCookie
= (DWORD_PTR
)&p
;
3924 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3925 memset(buf
, 0, sizeof(buf
));
3926 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3927 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3928 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3930 /* !ST_SELECTION && !Unicode && \rtf */
3931 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3932 getText
.codepage
= 1200; /* no constant for unicode */
3933 getText
.cb
= MAX_BUF_LEN
;
3934 getText
.flags
= GT_DEFAULT
;
3935 getText
.lpDefaultChar
= NULL
;
3936 getText
.lpUsedDefChar
= NULL
;
3939 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3940 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
3941 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3942 ok(lstrcmpW(buf
, TestItem1
) == 0,
3943 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3945 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
3946 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
3947 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
3948 getText
.codepage
= CP_ACP
;
3949 getText
.cb
= MAX_BUF_LEN
;
3950 getText
.flags
= GT_DEFAULT
;
3951 getText
.lpDefaultChar
= NULL
;
3952 getText
.lpUsedDefChar
= NULL
;
3954 setText
.flags
= ST_SELECTION
;
3955 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3956 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf not unicode}");
3957 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
3958 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3959 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
3961 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
3962 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3964 es
.dwCookie
= (DWORD_PTR
)&p
;
3966 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3967 memset(buf
, 0, sizeof(buf
));
3968 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3969 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3970 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3972 /* select some text */
3975 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3977 /* ST_SELECTION && !Unicode && \rtf */
3978 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3979 getText
.codepage
= 1200; /* no constant for unicode */
3980 getText
.cb
= MAX_BUF_LEN
;
3981 getText
.flags
= GT_DEFAULT
;
3982 getText
.lpDefaultChar
= NULL
;
3983 getText
.lpUsedDefChar
= NULL
;
3985 setText
.flags
= ST_SELECTION
;
3986 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3987 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3988 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
3990 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
3991 setText
.codepage
= 1200; /* no constant for unicode */
3992 getText
.codepage
= CP_ACP
;
3993 getText
.cb
= MAX_BUF_LEN
;
3996 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
); /* TestItem1 */
3997 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3999 /* select some text */
4002 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4004 /* ST_SELECTION && !Unicode && !\rtf */
4005 setText
.codepage
= CP_ACP
;
4006 getText
.codepage
= 1200; /* no constant for unicode */
4007 getText
.cb
= MAX_BUF_LEN
;
4008 getText
.flags
= GT_DEFAULT
;
4009 getText
.lpDefaultChar
= NULL
;
4010 getText
.lpUsedDefChar
= NULL
;
4012 setText
.flags
= ST_SELECTION
;
4013 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)bufACP
);
4014 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4015 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
4016 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
4017 " using ST_SELECTION and non-Unicode\n");
4019 /* Test setting text using rich text format */
4021 setText
.codepage
= CP_ACP
;
4022 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
4023 getText
.codepage
= CP_ACP
;
4024 getText
.cb
= MAX_BUF_LEN
;
4025 getText
.flags
= GT_DEFAULT
;
4026 getText
.lpDefaultChar
= NULL
;
4027 getText
.lpUsedDefChar
= NULL
;
4028 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4029 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
4032 setText
.codepage
= CP_ACP
;
4033 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
4034 getText
.codepage
= CP_ACP
;
4035 getText
.cb
= MAX_BUF_LEN
;
4036 getText
.flags
= GT_DEFAULT
;
4037 getText
.lpDefaultChar
= NULL
;
4038 getText
.lpUsedDefChar
= NULL
;
4039 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4040 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
4042 /* test for utf8 text with BOM */
4044 setText
.codepage
= CP_ACP
;
4045 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
4046 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4047 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
4048 result
= strcmp(bufACP
, "TestUTF8WithBOM");
4049 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
4052 setText
.codepage
= CP_UTF8
;
4053 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
4054 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4055 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
4056 result
= strcmp(bufACP
, "TestUTF8WithBOM");
4057 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
4059 /* Test multibyte character */
4060 if (!is_lang_japanese
)
4061 skip("Skip multibyte character tests on non-Japanese platform\n");
4064 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4065 setText
.flags
= ST_SELECTION
;
4066 setText
.codepage
= CP_ACP
;
4067 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"abc\x8e\xf0");
4068 todo_wine
ok(result
== 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result
);
4069 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4070 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4071 ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4072 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4074 setText
.flags
= ST_DEFAULT
;
4075 setText
.codepage
= CP_ACP
;
4076 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"abc\x8e\xf0");
4077 ok(result
== 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result
);
4078 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4079 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4080 ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4081 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4083 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4084 setText
.flags
= ST_SELECTION
;
4085 setText
.codepage
= CP_ACP
;
4086 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf abc\x8e\xf0}");
4087 todo_wine
ok(result
== 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result
);
4088 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4089 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4090 todo_wine
ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4091 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4094 DestroyWindow(hwndRichEdit
);
4097 static void test_EM_LIMITTEXT(void)
4101 HWND hwndRichEdit
= new_richedit(NULL
);
4103 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
4104 * about setting the length to -1 for multiline edit controls doesn't happen.
4107 /* Don't check default gettextlimit case. That's done in other tests */
4109 /* Set textlimit to 100 */
4110 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
4111 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4113 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
4115 /* Set textlimit to 0 */
4116 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
4117 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4119 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
4121 /* Set textlimit to -1 */
4122 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
4123 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4125 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
4127 /* Set textlimit to -2 */
4128 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
4129 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4131 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
4133 DestroyWindow (hwndRichEdit
);
4137 static void test_EM_EXLIMITTEXT(void)
4139 int i
, selBegin
, selEnd
, len1
, len2
;
4141 char text
[1024 + 1];
4142 char buffer
[1024 + 1];
4143 int textlimit
= 0; /* multiple of 100 */
4144 HWND hwndRichEdit
= new_richedit(NULL
);
4146 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4147 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
4150 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4151 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4153 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
4156 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4157 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4159 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
4161 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
4162 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4163 /* default for WParam = 0 */
4164 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
4166 textlimit
= sizeof(text
)-1;
4167 memset(text
, 'W', textlimit
);
4168 text
[sizeof(text
)-1] = 0;
4169 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4170 /* maxed out text */
4171 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4173 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4174 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4175 len1
= selEnd
- selBegin
;
4177 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
4178 SendMessageA(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
4179 SendMessageA(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
4180 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4181 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4182 len2
= selEnd
- selBegin
;
4185 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4188 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4189 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4190 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1);
4191 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4192 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4193 len1
= selEnd
- selBegin
;
4196 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4199 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4200 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4201 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
4202 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4203 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4204 len2
= selEnd
- selBegin
;
4207 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4210 /* set text up to the limit, select all the text, then add a char */
4212 memset(text
, 'W', textlimit
);
4213 text
[textlimit
] = 0;
4214 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4215 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4216 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4217 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4218 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4219 result
= strcmp(buffer
, "A");
4220 ok(0 == result
, "got string = \"%s\"\n", buffer
);
4222 /* WM_SETTEXT not limited */
4224 memset(text
, 'W', textlimit
);
4225 text
[textlimit
] = 0;
4226 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
4227 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4228 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4230 ok(10 == i
, "expected 10 chars\n");
4231 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4232 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4234 /* try inserting more text at end */
4235 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4236 ok(0 == i
, "WM_CHAR wasn't processed\n");
4237 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4239 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4240 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4241 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4243 /* try inserting text at beginning */
4244 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
4245 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4246 ok(0 == i
, "WM_CHAR wasn't processed\n");
4247 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4249 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4250 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4251 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4253 /* WM_CHAR is limited */
4255 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4256 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4257 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4258 ok(0 == i
, "WM_CHAR wasn't processed\n");
4259 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4260 ok(0 == i
, "WM_CHAR wasn't processed\n");
4261 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4263 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4265 DestroyWindow(hwndRichEdit
);
4268 static void test_EM_GETLIMITTEXT(void)
4271 HWND hwndRichEdit
= new_richedit(NULL
);
4273 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4274 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4276 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4277 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4278 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4280 DestroyWindow(hwndRichEdit
);
4283 static void test_WM_SETFONT(void)
4285 /* There is no invalid input or error conditions for this function.
4286 * NULL wParam and lParam just fall back to their default values
4287 * It should be noted that even if you use a gibberish name for your fonts
4288 * here, it will still work because the name is stored. They will display as
4289 * System, but will report their name to be whatever they were created as */
4291 HWND hwndRichEdit
= new_richedit(NULL
);
4292 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4293 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4294 FF_DONTCARE
, "Marlett");
4295 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4296 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4297 FF_DONTCARE
, "MS Sans Serif");
4298 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4299 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4300 FF_DONTCARE
, "Courier");
4301 LOGFONTA sentLogFont
;
4302 CHARFORMAT2A returnedCF2A
;
4304 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4306 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
4307 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4308 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4310 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4311 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4312 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4313 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4315 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4316 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4317 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4318 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4319 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4320 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4322 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4323 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4324 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4325 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4326 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4327 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4329 /* This last test is special since we send in NULL. We clear the variables
4330 * and just compare to "System" instead of the sent in font name. */
4331 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4332 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4333 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4335 SendMessageA(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4336 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4337 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4338 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4339 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4341 DestroyWindow(hwndRichEdit
);
4345 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4350 const char** str
= (const char**)dwCookie
;
4351 int size
= strlen(*str
);
4352 if(size
> 3) /* let's make it piecemeal for fun */
4359 memcpy(pbBuff
, *str
, *pcb
);
4365 static void test_EM_GETMODIFY(void)
4367 HWND hwndRichEdit
= new_richedit(NULL
);
4370 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4372 'T', 'e', 'x', 't', 0};
4373 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4375 'O', 't', 'h', 'e', 'r',
4376 'T', 'e', 'x', 't', 0};
4377 const char* streamText
= "hello world";
4382 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4383 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4384 FF_DONTCARE
, "Courier");
4386 setText
.codepage
= 1200; /* no constant for unicode */
4387 setText
.flags
= ST_KEEPUNDO
;
4390 /* modify flag shouldn't be set when richedit is first created */
4391 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4393 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4395 /* setting modify flag should actually set it */
4396 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4397 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4399 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4401 /* clearing modify flag should actually clear it */
4402 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4403 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4405 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4407 /* setting font doesn't change modify flag */
4408 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4409 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4410 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4412 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4414 /* setting text should set modify flag */
4415 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4416 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4417 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4419 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4421 /* undo previous text doesn't reset modify flag */
4422 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
4423 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4425 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4427 /* set text with no flag to keep undo stack should not set modify flag */
4428 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4430 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4431 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4433 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4435 /* WM_SETTEXT doesn't modify */
4436 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4437 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4438 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4440 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4442 /* clear the text */
4443 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4444 SendMessageA(hwndRichEdit
, WM_CLEAR
, 0, 0);
4445 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4447 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4450 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4451 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4452 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4453 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4454 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4456 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4458 /* copy/paste text 1 */
4459 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4460 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4461 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4462 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4463 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4465 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4467 /* copy/paste text 2 */
4468 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4469 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4470 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4471 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 3);
4472 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4473 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4475 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4478 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4479 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 1);
4480 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4481 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4483 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4486 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4487 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4488 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4489 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4491 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4493 /* set char format */
4494 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4495 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
4496 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4497 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4498 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4499 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4500 result
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4501 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4502 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4504 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4506 /* set para format */
4507 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4508 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4509 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4510 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4511 pf2
.wAlignment
= PFA_RIGHT
;
4512 SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4513 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4515 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4518 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4519 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4521 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4522 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4523 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4525 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4527 DestroyWindow(hwndRichEdit
);
4533 LRESULT expected_retval
;
4534 int expected_getsel_start
;
4535 int expected_getsel_end
;
4539 static const struct exsetsel_s exsetsel_tests
[] = {
4541 {5, 10, 10, 5, 10 },
4542 {15, 17, 17, 15, 17 },
4543 /* test cpMax > strlen() */
4544 {0, 100, 18, 0, 18 },
4545 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
4546 {-1, 1, 17, 17, 17 },
4547 /* test cpMin == cpMax */
4549 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4553 /* test cpMin < 0 && cpMax < 0 */
4554 {-1, -1, 17, 17, 17 },
4555 {-4, -5, 17, 17, 17 },
4556 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
4557 {0, -1, 18, 0, 18 },
4558 {17, -5, 18, 17, 18 },
4559 {18, -3, 17, 17, 17 },
4560 /* test if cpMin > cpMax */
4561 {15, 19, 18, 15, 18 },
4562 {19, 15, 18, 15, 18 },
4563 /* cpMin == strlen() && cpMax > cpMin */
4564 {17, 18, 18, 17, 18 },
4565 {17, 50, 18, 17, 18 },
4568 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4573 cr
.cpMin
= setsel
->min
;
4574 cr
.cpMax
= setsel
->max
;
4575 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4577 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4579 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4581 todo_wine_if (setsel
->todo
)
4582 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4583 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4586 static void test_EM_EXSETSEL(void)
4588 HWND hwndRichEdit
= new_richedit(NULL
);
4590 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4592 /* sending some text to the window */
4593 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4594 /* 01234567890123456*/
4597 for (i
= 0; i
< num_tests
; i
++) {
4598 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4601 if (!is_lang_japanese
)
4602 skip("Skip multibyte character tests on non-Japanese platform\n");
4606 char bufA
[MAX_BUF_LEN
] = {0};
4609 /* Test with multibyte character */
4610 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
4611 /* 012345 6 78901 */
4612 cr
.cpMin
= 4, cr
.cpMax
= 8;
4613 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4614 ok(result
== 8, "EM_EXSETSEL return %ld expected 8\n", result
);
4615 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(bufA
), (LPARAM
)bufA
);
4616 ok(!strcmp(bufA
, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4617 SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4618 ok(cr
.cpMin
== 4, "Selection start incorrectly: %d expected 4\n", cr
.cpMin
);
4619 ok(cr
.cpMax
== 8, "Selection end incorrectly: %d expected 8\n", cr
.cpMax
);
4622 DestroyWindow(hwndRichEdit
);
4625 static void check_EM_SETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4629 result
= SendMessageA(hwnd
, EM_SETSEL
, setsel
->min
, setsel
->max
);
4631 ok(result
== setsel
->expected_retval
, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4633 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4635 todo_wine_if (setsel
->todo
)
4636 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4637 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4640 static void test_EM_SETSEL(void)
4642 char buffA
[32] = {0};
4643 HWND hwndRichEdit
= new_richedit(NULL
);
4645 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4647 /* sending some text to the window */
4648 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4649 /* 01234567890123456*/
4652 for (i
= 0; i
< num_tests
; i
++) {
4653 check_EM_SETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4656 SendMessageA(hwndRichEdit
, EM_SETSEL
, 17, 18);
4658 SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffA
);
4659 ok(buffA
[0] == 0, "selection text %s\n", buffA
);
4661 if (!is_lang_japanese
)
4662 skip("Skip multibyte character tests on non-Japanese platform\n");
4665 int sel_start
, sel_end
;
4668 /* Test with multibyte character */
4669 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
4670 /* 012345 6 78901 */
4671 result
= SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
4672 ok(result
== 8, "EM_SETSEL return %ld expected 8\n", result
);
4673 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(buffA
), (LPARAM
)buffA
);
4674 ok(!strcmp(buffA
, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4675 result
= SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
4676 ok(sel_start
== 4, "Selection start incorrectly: %d expected 4\n", sel_start
);
4677 ok(sel_end
== 8, "Selection end incorrectly: %d expected 8\n", sel_end
);
4680 DestroyWindow(hwndRichEdit
);
4683 static void test_EM_REPLACESEL(int redraw
)
4685 HWND hwndRichEdit
= new_richedit(NULL
);
4686 char buffer
[1024] = {0};
4690 CHAR rtfstream
[] = "{\\rtf1 TestSomeText}";
4691 CHAR urtfstream
[] = "{\\urtf1 TestSomeText}";
4693 /* sending some text to the window */
4694 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4695 /* 01234567890123456*/
4698 /* FIXME add more tests */
4699 SendMessageA(hwndRichEdit
, EM_SETSEL
, 7, 17);
4700 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4701 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4702 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4703 r
= strcmp(buffer
, "testing");
4704 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4706 DestroyWindow(hwndRichEdit
);
4708 hwndRichEdit
= new_richedit(NULL
);
4710 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
4711 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
4713 /* Test behavior with carriage returns and newlines */
4714 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4715 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1");
4716 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
4717 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4718 r
= strcmp(buffer
, "RichEdit1");
4719 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4721 getText
.codepage
= CP_ACP
;
4722 getText
.flags
= GT_DEFAULT
;
4723 getText
.lpDefaultChar
= NULL
;
4724 getText
.lpUsedDefChar
= NULL
;
4725 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4726 ok(strcmp(buffer
, "RichEdit1") == 0,
4727 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
4729 /* Test number of lines reported after EM_REPLACESEL */
4730 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4731 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4733 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4734 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r");
4735 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
4736 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4737 r
= strcmp(buffer
, "RichEdit1\r\n");
4738 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4740 getText
.codepage
= CP_ACP
;
4741 getText
.flags
= GT_DEFAULT
;
4742 getText
.lpDefaultChar
= NULL
;
4743 getText
.lpUsedDefChar
= NULL
;
4744 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4745 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4746 "EM_GETTEXTEX returned incorrect string\n");
4748 /* Test number of lines reported after EM_REPLACESEL */
4749 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4750 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4752 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4753 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r\n");
4754 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
4756 /* Test number of lines reported after EM_REPLACESEL */
4757 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4758 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4760 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4761 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4762 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4763 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4765 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4766 r
= strcmp(buffer
, "RichEdit1\r\n");
4767 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4769 getText
.codepage
= CP_ACP
;
4770 getText
.flags
= GT_DEFAULT
;
4771 getText
.lpDefaultChar
= NULL
;
4772 getText
.lpUsedDefChar
= NULL
;
4773 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4774 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4775 "EM_GETTEXTEX returned incorrect string\n");
4777 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4778 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4779 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4780 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4782 /* The following tests show that richedit should handle the special \r\r\n
4783 sequence by turning it into a single space on insertion. However,
4784 EM_REPLACESEL on WinXP returns the number of characters in the original
4788 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4789 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r");
4790 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
4791 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4792 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4793 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4794 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4796 /* Test the actual string */
4798 getText
.codepage
= CP_ACP
;
4799 getText
.flags
= GT_DEFAULT
;
4800 getText
.lpDefaultChar
= NULL
;
4801 getText
.lpUsedDefChar
= NULL
;
4802 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4803 ok(strcmp(buffer
, "\r\r") == 0,
4804 "EM_GETTEXTEX returned incorrect string\n");
4806 /* Test number of lines reported after EM_REPLACESEL */
4807 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4808 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4810 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4811 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n");
4812 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
4813 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4814 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4815 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
4816 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
4818 /* Test the actual string */
4820 getText
.codepage
= CP_ACP
;
4821 getText
.flags
= GT_DEFAULT
;
4822 getText
.lpDefaultChar
= NULL
;
4823 getText
.lpUsedDefChar
= NULL
;
4824 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4825 ok(strcmp(buffer
, " ") == 0,
4826 "EM_GETTEXTEX returned incorrect string\n");
4828 /* Test number of lines reported after EM_REPLACESEL */
4829 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4830 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4832 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4833 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\r\r\r\n\r\r\r");
4834 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4835 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4836 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4837 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4838 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4840 /* Test the actual string */
4842 getText
.codepage
= CP_ACP
;
4843 getText
.flags
= GT_DEFAULT
;
4844 getText
.lpDefaultChar
= NULL
;
4845 getText
.lpUsedDefChar
= NULL
;
4846 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4847 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
4848 "EM_GETTEXTEX returned incorrect string\n");
4850 /* Test number of lines reported after EM_REPLACESEL */
4851 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4852 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4854 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4855 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\n");
4856 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4857 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4858 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4859 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4860 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4862 /* Test the actual string */
4864 getText
.codepage
= CP_ACP
;
4865 getText
.flags
= GT_DEFAULT
;
4866 getText
.lpDefaultChar
= NULL
;
4867 getText
.lpUsedDefChar
= NULL
;
4868 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4869 ok(strcmp(buffer
, " \r") == 0,
4870 "EM_GETTEXTEX returned incorrect string\n");
4872 /* Test number of lines reported after EM_REPLACESEL */
4873 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4874 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4876 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4877 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\r");
4878 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4879 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4880 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4881 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
4882 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
4884 /* Test the actual string */
4886 getText
.codepage
= CP_ACP
;
4887 getText
.flags
= GT_DEFAULT
;
4888 getText
.lpDefaultChar
= NULL
;
4889 getText
.lpUsedDefChar
= NULL
;
4890 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4891 ok(strcmp(buffer
, " \r\r") == 0,
4892 "EM_GETTEXTEX returned incorrect string\n");
4894 /* Test number of lines reported after EM_REPLACESEL */
4895 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4896 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4898 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4899 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\rX\r\n\r\r");
4900 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
4901 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4902 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4903 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
4904 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
4906 /* Test the actual string */
4908 getText
.codepage
= CP_ACP
;
4909 getText
.flags
= GT_DEFAULT
;
4910 getText
.lpDefaultChar
= NULL
;
4911 getText
.lpUsedDefChar
= NULL
;
4912 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4913 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
4914 "EM_GETTEXTEX returned incorrect string\n");
4916 /* Test number of lines reported after EM_REPLACESEL */
4917 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4918 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
4920 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4921 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n");
4922 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
4923 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4924 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4925 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4926 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4928 /* Test the actual string */
4930 getText
.codepage
= CP_ACP
;
4931 getText
.flags
= GT_DEFAULT
;
4932 getText
.lpDefaultChar
= NULL
;
4933 getText
.lpUsedDefChar
= NULL
;
4934 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4935 ok(strcmp(buffer
, "\r\r") == 0,
4936 "EM_GETTEXTEX returned incorrect string\n");
4938 /* Test number of lines reported after EM_REPLACESEL */
4939 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4940 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4942 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4943 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n\n\n\r\r\r\r\n");
4944 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4945 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4946 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4947 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4948 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4950 /* Test the actual string */
4952 getText
.codepage
= CP_ACP
;
4953 getText
.flags
= GT_DEFAULT
;
4954 getText
.lpDefaultChar
= NULL
;
4955 getText
.lpUsedDefChar
= NULL
;
4956 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4957 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
4958 "EM_GETTEXTEX returned incorrect string\n");
4960 /* Test number of lines reported after EM_REPLACESEL */
4961 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4962 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4964 /* Test with multibyte character */
4965 if (!is_lang_japanese
)
4966 skip("Skip multibyte character tests on non-Japanese platform\n");
4969 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4970 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"abc\x8e\xf0");
4971 todo_wine
ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4972 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4973 ok(r
== 0, "EM_EXGETSEL returned %d, expected 0\n", r
);
4974 ok(cr
.cpMin
== 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr
.cpMin
);
4975 ok(cr
.cpMax
== 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr
.cpMax
);
4976 r
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4977 ok(!strcmp(buffer
, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
4978 ok(r
== 5, "WM_GETTEXT returned %d, expected 5\n", r
);
4980 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4981 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"{\\rtf abc\x8e\xf0}");
4982 todo_wine
ok(r
== 4, "EM_REPLACESEL returned %d, expected 4\n", r
);
4983 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4984 ok(r
== 0, "EM_EXGETSEL returned %d, expected 0\n", r
);
4985 todo_wine
ok(cr
.cpMin
== 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr
.cpMin
);
4986 todo_wine
ok(cr
.cpMax
== 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr
.cpMax
);
4987 r
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4988 todo_wine
ok(!strcmp(buffer
, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
4989 todo_wine
ok(r
== 5, "WM_GETTEXT returned %d, expected 5\n", r
);
4992 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4993 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
4994 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
4995 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4996 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4997 todo_wine
ok(cr
.cpMin
== 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr
.cpMin
);
4998 todo_wine
ok(cr
.cpMax
== 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr
.cpMax
);
4999 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5000 todo_wine
ok(!strcmp(buffer
, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5002 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5003 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urtfstream
);
5004 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5005 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5006 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5007 todo_wine
ok(cr
.cpMin
== 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr
.cpMin
);
5008 todo_wine
ok(cr
.cpMax
== 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr
.cpMax
);
5009 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5010 todo_wine
ok(!strcmp(buffer
, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5012 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Wine");
5013 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 2);
5014 todo_wine r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
5015 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5016 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5017 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5018 todo_wine
ok(cr
.cpMin
== 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr
.cpMin
);
5019 todo_wine
ok(cr
.cpMax
== 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr
.cpMax
);
5020 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5021 todo_wine
ok(!strcmp(buffer
, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5023 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"{\\rtf1 Wine}");
5024 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 2);
5025 todo_wine r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
5026 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5027 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5028 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5029 todo_wine
ok(cr
.cpMin
== 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr
.cpMin
);
5030 todo_wine
ok(cr
.cpMax
== 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr
.cpMax
);
5031 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5032 todo_wine
ok(!strcmp(buffer
, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5035 /* This is needed to avoid interferring with keybd_event calls
5036 * on other tests that simulate keyboard events. */
5037 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
5039 DestroyWindow(hwndRichEdit
);
5042 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
5043 * to test the state of the modifiers (Ctrl/Alt/Shift).
5045 * Therefore Ctrl-<key> keystrokes need to be simulated with
5046 * keybd_event or by using SetKeyboardState to set the modifiers
5047 * and SendMessage to simulate the keystrokes.
5049 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
5052 hold_key(VK_CONTROL
);
5053 result
= SendMessageA(hwnd
, WM_KEYDOWN
, key
, 1);
5054 release_key(VK_CONTROL
);
5058 static void test_WM_PASTE(void)
5061 char buffer
[1024] = {0};
5062 const char* text1
= "testing paste\r";
5063 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
5064 const char* text1_after
= "testing paste\r\n";
5065 const char* text2
= "testing paste\r\rtesting paste";
5066 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
5067 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
5068 HWND hwndRichEdit
= new_richedit(NULL
);
5070 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
5071 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 14);
5073 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
5074 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
5075 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
5076 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5077 /* Pasted text should be visible at this step */
5078 result
= strcmp(text1_step1
, buffer
);
5080 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
5082 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
5083 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5084 /* Text should be the same as before (except for \r -> \r\n conversion) */
5085 result
= strcmp(text1_after
, buffer
);
5087 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
5089 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
5090 SendMessageA(hwndRichEdit
, EM_SETSEL
, 8, 13);
5091 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
5092 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
5093 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
5094 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5095 /* Pasted text should be visible at this step */
5096 result
= strcmp(text3
, buffer
);
5098 "test paste: strcmp = %i\n", result
);
5099 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
5100 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5101 /* Text should be the same as before (except for \r -> \r\n conversion) */
5102 result
= strcmp(text2_after
, buffer
);
5104 "test paste: strcmp = %i\n", result
);
5105 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
5106 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5107 /* Text should revert to post-paste state */
5108 result
= strcmp(buffer
,text3
);
5110 "test paste: strcmp = %i\n", result
);
5112 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5113 /* Send WM_CHAR to simulate Ctrl-V */
5114 SendMessageA(hwndRichEdit
, WM_CHAR
, 22,
5115 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
5116 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5117 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
5118 result
= strcmp(buffer
,"");
5120 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5122 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
5123 * with SetKeyboard state. */
5125 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5126 /* Simulates paste (Ctrl-V) */
5127 hold_key(VK_CONTROL
);
5128 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'V',
5129 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
5130 release_key(VK_CONTROL
);
5131 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5132 result
= strcmp(buffer
,"paste");
5134 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5136 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
5137 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 7);
5138 /* Simulates copy (Ctrl-C) */
5139 hold_key(VK_CONTROL
);
5140 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'C',
5141 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC
) << 16) | 1);
5142 release_key(VK_CONTROL
);
5143 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5144 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
5145 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5146 result
= strcmp(buffer
,"testing");
5148 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5150 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
5151 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"cut");
5152 /* Simulates select all (Ctrl-A) */
5153 hold_key(VK_CONTROL
);
5154 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A',
5155 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC
) << 16) | 1);
5156 /* Simulates select cut (Ctrl-X) */
5157 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'X',
5158 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC
) << 16) | 1);
5159 release_key(VK_CONTROL
);
5160 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5161 result
= strcmp(buffer
,"");
5163 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5164 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5165 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
5166 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5167 result
= strcmp(buffer
,"cut\r\n");
5169 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5170 /* Simulates undo (Ctrl-Z) */
5171 hold_key(VK_CONTROL
);
5172 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Z',
5173 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
5174 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5175 result
= strcmp(buffer
,"");
5177 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5178 /* Simulates redo (Ctrl-Y) */
5179 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Y',
5180 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
5181 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5182 result
= strcmp(buffer
,"cut\r\n");
5184 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5185 release_key(VK_CONTROL
);
5187 DestroyWindow(hwndRichEdit
);
5190 static void test_EM_FORMATRANGE(void)
5192 int r
, i
, tpp_x
, tpp_y
;
5194 HWND hwndRichEdit
= new_richedit(NULL
);
5196 BOOL skip_non_english
;
5197 static const struct {
5198 const char *string
; /* The string */
5199 int first
; /* First 'pagebreak', 0 for don't care */
5200 int second
; /* Second 'pagebreak', 0 for don't care */
5202 {"WINE wine", 0, 0},
5203 {"WINE wineWine", 0, 0},
5204 {"WINE\r\nwine\r\nwine", 5, 10},
5205 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
5206 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
5209 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
5210 if (skip_non_english
)
5211 skip("Skipping some tests on non-English platform\n");
5213 hdc
= GetDC(hwndRichEdit
);
5214 ok(hdc
!= NULL
, "Could not get HDC\n");
5216 /* Calculate the twips per pixel */
5217 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
5218 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
5220 /* Test the simple case where all the text fits in the page rect. */
5221 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
5222 fr
.hdc
= fr
.hdcTarget
= hdc
;
5223 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
5224 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
5225 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
5228 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
5229 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
5231 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
5232 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
5233 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
5234 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
5236 SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
5238 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
5240 GETTEXTLENGTHEX gtl
;
5244 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)fmtstrings
[i
].string
);
5246 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5247 gtl
.codepage
= CP_ACP
;
5248 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5250 /* Get some size information for the string */
5251 GetTextExtentPoint32A(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
5253 /* Define the box to be half the width needed and a bit larger than the height.
5254 * Changes to the width means we have at least 2 pages. Changes to the height
5255 * is done so we can check the changing of fr.rc.bottom.
5257 fr
.hdc
= fr
.hdcTarget
= hdc
;
5258 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
5259 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
5260 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
5262 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
5264 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
5267 /* We know that the page can't hold the full string. See how many characters
5268 * are on the first one
5272 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
5274 if (! skip_non_english
)
5275 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
5277 if (fmtstrings
[i
].first
)
5279 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
5282 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
5284 /* Do another page */
5286 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
5287 if (fmtstrings
[i
].second
)
5289 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
5291 else if (! skip_non_english
)
5292 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
5294 /* There is at least on more page, but we don't care */
5296 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
5298 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
5302 ReleaseDC(NULL
, hdc
);
5303 DestroyWindow(hwndRichEdit
);
5306 static int nCallbackCount
= 0;
5308 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
5311 const char text
[] = {'t','e','s','t'};
5313 if (sizeof(text
) <= cb
)
5315 if ((int)dwCookie
!= nCallbackCount
)
5321 memcpy (pbBuff
, text
, sizeof(text
));
5322 *pcb
= sizeof(text
);
5329 return 1; /* indicates callback failed */
5332 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
5337 const char** str
= (const char**)dwCookie
;
5338 int size
= strlen(*str
);
5344 memcpy(pbBuff
, *str
, *pcb
);
5350 static DWORD CALLBACK
test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie
,
5355 DWORD
*phase
= (DWORD
*)dwCookie
;
5358 static const char first
[] = "\xef\xbb\xbf\xc3\x96\xc3";
5359 *pcb
= sizeof(first
) - 1;
5360 memcpy(pbBuff
, first
, *pcb
);
5361 }else if(*phase
== 1){
5362 static const char second
[] = "\x8f\xc3\x8b";
5363 *pcb
= sizeof(second
) - 1;
5364 memcpy(pbBuff
, second
, *pcb
);
5373 struct StringWithLength
{
5378 /* This callback is used to handled the null characters in a string. */
5379 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
5384 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
5385 int size
= str
->length
;
5391 memcpy(pbBuff
, str
->buffer
, *pcb
);
5392 str
->buffer
+= *pcb
;
5393 str
->length
-= *pcb
;
5398 static void test_EM_STREAMIN(void)
5400 HWND hwndRichEdit
= new_richedit(NULL
);
5404 char buffer
[1024] = {0}, tmp
[16];
5407 const char * streamText0
= "{\\rtf1 TestSomeText}";
5408 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
5409 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
5412 const char * streamText1
=
5413 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5414 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5417 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5418 const char * streamText2
=
5419 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5420 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5421 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5422 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5423 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5424 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5425 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5427 const char * streamText3
= "RichEdit1";
5429 const char * streamTextUTF8BOM
= "\xef\xbb\xbfTestUTF8WithBOM";
5431 const char * streamText4
=
5432 "This text just needs to be long enough to cause run to be split onto "
5433 "two separate lines and make sure the null terminating character is "
5434 "handled properly.\0";
5436 const WCHAR UTF8Split_exp
[4] = {0xd6, 0xcf, 0xcb, 0};
5438 int length4
= strlen(streamText4
) + 1;
5439 struct StringWithLength cookieForStream4
= {
5441 (char *)streamText4
,
5444 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5445 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5446 struct StringWithLength cookieForStream5
= {
5447 sizeof(streamText5
),
5448 (char *)streamText5
,
5451 /* Minimal test without \par at the end */
5452 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5454 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5455 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5456 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5458 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5460 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5461 result
= strcmp (buffer
,"TestSomeText");
5463 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5464 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5466 /* Native richedit 2.0 ignores last \par */
5468 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5470 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5471 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5472 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5474 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5476 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5477 result
= strcmp (buffer
,"TestSomeText");
5479 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5480 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5482 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5483 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5485 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5486 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5487 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5489 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5491 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5492 result
= strcmp (buffer
,"TestSomeText\r\n");
5494 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5495 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5497 /* Show that when using SFF_SELECTION the last \par is not ignored. */
5499 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5501 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5502 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5503 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5505 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5507 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5508 result
= strcmp (buffer
,"TestSomeText");
5510 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5511 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5515 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&range
);
5516 ok (result
== 13, "got %ld\n", result
);
5519 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5521 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5523 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SFF_SELECTION
| SF_RTF
, (LPARAM
)&es
);
5524 ok(result
== 13, "got %ld, expected 13\n", result
);
5526 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5528 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result
);
5529 result
= strcmp (buffer
,"TestSomeText\r\n");
5531 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer
);
5532 ok(es
.dwError
== 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es
.dwError
, 0);
5534 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5536 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5537 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5538 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5540 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5542 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5543 result
= strcmp (buffer
,"TestSomeText");
5545 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5546 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5548 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5550 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5551 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5553 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5555 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5556 ok(!buffer
[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5557 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5559 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5561 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5562 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5564 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5566 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5567 ok(!buffer
[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5568 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5570 es
.dwCookie
= (DWORD_PTR
)&streamTextUTF8BOM
;
5572 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5573 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5574 ok(result
== 18, "got %ld, expected %d\n", result
, 18);
5576 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5578 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result
);
5579 result
= strcmp (buffer
,"TestUTF8WithBOM");
5581 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer
);
5582 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es
.dwError
, 0);
5585 es
.dwCookie
= (DWORD_PTR
)&phase
;
5587 es
.pfnCallback
= test_EM_STREAMIN_esCallback_UTF8Split
;
5588 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5589 ok(result
== 8, "got %ld\n", result
);
5591 WideCharToMultiByte(CP_ACP
, 0, UTF8Split_exp
, -1, tmp
, sizeof(tmp
), NULL
, NULL
);
5593 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5595 "EM_STREAMIN: Test UTF8Split returned %ld\n", result
);
5596 result
= memcmp (buffer
, tmp
, 3);
5598 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer
);
5599 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es
.dwError
, 0);
5601 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5603 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5604 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5605 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5607 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5608 ok (result
== length4
,
5609 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5610 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5612 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5614 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5615 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5616 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5618 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5619 ok (result
== length5
,
5620 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result
, length5
);
5621 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5623 DestroyWindow(hwndRichEdit
);
5626 static void test_EM_StreamIn_Undo(void)
5628 /* The purpose of this test is to determine when a EM_StreamIn should be
5629 * undoable. This is important because WM_PASTE currently uses StreamIn and
5630 * pasting should always be undoable but streaming isn't always.
5633 * StreamIn plain text without SFF_SELECTION.
5634 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5635 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5636 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5637 * Feel free to add tests for other text modes or StreamIn things.
5641 HWND hwndRichEdit
= new_richedit(NULL
);
5644 char buffer
[1024] = {0};
5645 const char randomtext
[] = "Some text";
5647 es
.pfnCallback
= EditStreamCallback
;
5649 /* StreamIn, no SFF_SELECTION */
5650 es
.dwCookie
= nCallbackCount
;
5651 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5652 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5653 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5654 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5655 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5656 result
= strcmp (buffer
,"test");
5658 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5660 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5661 ok (result
== FALSE
,
5662 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5664 /* StreamIn, SFF_SELECTION, but nothing selected */
5665 es
.dwCookie
= nCallbackCount
;
5666 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5667 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5668 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5669 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5670 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5671 result
= strcmp (buffer
,"testSome text");
5673 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5675 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5677 "EM_STREAMIN with SFF_SELECTION but no selection set "
5678 "should create an undo\n");
5680 /* StreamIn, SFF_SELECTION, with a selection */
5681 es
.dwCookie
= nCallbackCount
;
5682 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5683 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5684 SendMessageA(hwndRichEdit
, EM_SETSEL
,4,5);
5685 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5686 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5687 result
= strcmp (buffer
,"Sometesttext");
5689 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5691 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5693 "EM_STREAMIN with SFF_SELECTION and selection set "
5694 "should create an undo\n");
5696 DestroyWindow(hwndRichEdit
);
5699 static BOOL
is_em_settextex_supported(HWND hwnd
)
5701 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
5702 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
5705 static void test_unicode_conversions(void)
5707 static const WCHAR tW
[] = {'t',0};
5708 static const WCHAR teW
[] = {'t','e',0};
5709 static const WCHAR textW
[] = {'t','e','s','t',0};
5710 static const char textA
[] = "test";
5714 int em_settextex_supported
, ret
;
5716 #define set_textA(hwnd, wm_set_text, txt) \
5718 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
5719 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5720 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5721 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5722 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
5724 #define expect_textA(hwnd, wm_get_text, txt) \
5726 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5727 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5728 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5729 memset(bufA, 0xAA, sizeof(bufA)); \
5730 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5731 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
5732 ret = lstrcmpA(bufA, txt); \
5733 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
5736 #define set_textW(hwnd, wm_set_text, txt) \
5738 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
5739 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5740 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5741 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5742 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
5744 #define expect_textW(hwnd, wm_get_text, txt) \
5746 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
5747 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5748 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5749 memset(bufW, 0xAA, sizeof(bufW)); \
5750 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
5751 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
5752 ret = lstrcmpW(bufW, txt); \
5753 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
5755 #define expect_empty(hwnd, wm_get_text) \
5757 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5758 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5759 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5760 memset(bufA, 0xAA, sizeof(bufA)); \
5761 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5762 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
5763 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
5766 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5767 0, 0, 200, 60, 0, 0, 0, 0);
5768 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5770 ret
= IsWindowUnicode(hwnd
);
5771 ok(ret
, "RichEdit20W should be unicode under NT\n");
5773 /* EM_SETTEXTEX is supported starting from version 3.0 */
5774 em_settextex_supported
= is_em_settextex_supported(hwnd
);
5775 trace("EM_SETTEXTEX is %ssupported on this platform\n",
5776 em_settextex_supported
? "" : "NOT ");
5778 expect_empty(hwnd
, WM_GETTEXT
);
5779 expect_empty(hwnd
, EM_GETTEXTEX
);
5781 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
5782 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5783 expect_textA(hwnd
, WM_GETTEXT
, "t");
5784 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
5785 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
5787 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
5788 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5789 expect_textA(hwnd
, WM_GETTEXT
, "te");
5790 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
5791 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
5793 set_textA(hwnd
, WM_SETTEXT
, NULL
);
5794 expect_empty(hwnd
, WM_GETTEXT
);
5795 expect_empty(hwnd
, EM_GETTEXTEX
);
5797 set_textA(hwnd
, WM_SETTEXT
, textA
);
5798 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5799 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5800 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5802 if (em_settextex_supported
)
5804 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5805 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5806 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5807 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5810 set_textW(hwnd
, WM_SETTEXT
, textW
);
5811 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5812 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5813 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5814 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5816 if (em_settextex_supported
)
5818 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5819 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5820 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5821 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5822 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5824 DestroyWindow(hwnd
);
5826 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
5827 0, 0, 200, 60, 0, 0, 0, 0);
5828 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5830 ret
= IsWindowUnicode(hwnd
);
5831 ok(!ret
, "RichEdit20A should NOT be unicode\n");
5833 set_textA(hwnd
, WM_SETTEXT
, textA
);
5834 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5835 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5836 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5838 if (em_settextex_supported
)
5840 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5841 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5842 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5843 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5846 set_textW(hwnd
, WM_SETTEXT
, textW
);
5847 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5848 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5849 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5850 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5852 if (em_settextex_supported
)
5854 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5855 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5856 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5857 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5858 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5860 DestroyWindow(hwnd
);
5863 static void test_WM_CHAR(void)
5867 const char * char_list
= "abc\rabc\r";
5868 const char * expected_content_single
= "abcabc";
5869 const char * expected_content_multi
= "abc\r\nabc\r\n";
5870 char buffer
[64] = {0};
5873 /* single-line control must IGNORE carriage returns */
5874 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5875 0, 0, 200, 60, 0, 0, 0, 0);
5876 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5879 while (*p
!= '\0') {
5880 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5881 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5882 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5883 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5887 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5888 ret
= strcmp(buffer
, expected_content_single
);
5889 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5891 DestroyWindow(hwnd
);
5893 /* multi-line control inserts CR normally */
5894 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5895 0, 0, 200, 60, 0, 0, 0, 0);
5896 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5899 while (*p
!= '\0') {
5900 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5901 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5902 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5903 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5907 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5908 ret
= strcmp(buffer
, expected_content_multi
);
5909 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5911 DestroyWindow(hwnd
);
5914 static void test_EM_GETTEXTLENGTHEX(void)
5917 GETTEXTLENGTHEX gtl
;
5919 const char * base_string
= "base string";
5920 const char * test_string
= "a\nb\n\n\r\n";
5921 const char * test_string_after
= "a";
5922 const char * test_string_2
= "a\rtest\rstring";
5923 char buffer
[64] = {0};
5926 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5927 0, 0, 200, 60, 0, 0, 0, 0);
5928 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5930 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5931 gtl
.codepage
= CP_ACP
;
5932 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5933 ok(ret
== 0, "ret %d\n",ret
);
5935 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5936 gtl
.codepage
= CP_ACP
;
5937 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5938 ok(ret
== 0, "ret %d\n",ret
);
5940 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5942 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5943 gtl
.codepage
= CP_ACP
;
5944 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5945 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5947 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5948 gtl
.codepage
= CP_ACP
;
5949 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5950 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5952 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5954 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5955 gtl
.codepage
= CP_ACP
;
5956 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5957 ok(ret
== 1, "ret %d\n",ret
);
5959 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5960 gtl
.codepage
= CP_ACP
;
5961 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5962 ok(ret
== 1, "ret %d\n",ret
);
5964 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5965 ret
= strcmp(buffer
, test_string_after
);
5966 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5968 DestroyWindow(hwnd
);
5971 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
5972 0, 0, 200, 60, 0, 0, 0, 0);
5973 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5975 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5976 gtl
.codepage
= CP_ACP
;
5977 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5978 ok(ret
== 0, "ret %d\n",ret
);
5980 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5981 gtl
.codepage
= CP_ACP
;
5982 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5983 ok(ret
== 0, "ret %d\n",ret
);
5985 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5987 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5988 gtl
.codepage
= CP_ACP
;
5989 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5990 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5992 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5993 gtl
.codepage
= CP_ACP
;
5994 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5995 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5997 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5999 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6000 gtl
.codepage
= CP_ACP
;
6001 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6002 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
6004 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6005 gtl
.codepage
= CP_ACP
;
6006 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6007 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
6009 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
6011 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6012 gtl
.codepage
= CP_ACP
;
6013 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6014 ok(ret
== 10, "ret %d\n",ret
);
6016 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6017 gtl
.codepage
= CP_ACP
;
6018 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6019 ok(ret
== 6, "ret %d\n",ret
);
6021 /* Unicode/NUMCHARS/NUMBYTES */
6022 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
6024 gtl
.flags
= GTL_DEFAULT
;
6025 gtl
.codepage
= 1200;
6026 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6027 ok(ret
== lstrlenA(test_string_2
),
6028 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6030 gtl
.flags
= GTL_NUMCHARS
;
6031 gtl
.codepage
= 1200;
6032 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6033 ok(ret
== lstrlenA(test_string_2
),
6034 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6036 gtl
.flags
= GTL_NUMBYTES
;
6037 gtl
.codepage
= 1200;
6038 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6039 ok(ret
== lstrlenA(test_string_2
)*2,
6040 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
6042 gtl
.flags
= GTL_PRECISE
;
6043 gtl
.codepage
= 1200;
6044 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6045 ok(ret
== lstrlenA(test_string_2
)*2,
6046 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
6048 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6049 gtl
.codepage
= 1200;
6050 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6051 ok(ret
== lstrlenA(test_string_2
),
6052 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6054 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
6055 gtl
.codepage
= 1200;
6056 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6057 ok(ret
== E_INVALIDARG
,
6058 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
6060 DestroyWindow(hwnd
);
6064 /* globals that parent and child access when checking event masks & notifications */
6065 static HWND eventMaskEditHwnd
= 0;
6066 static int queriedEventMask
;
6067 static int watchForEventMask
= 0;
6069 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
6070 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6072 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
6074 queriedEventMask
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
6076 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6079 /* test event masks in combination with WM_COMMAND */
6080 static void test_eventMask(void)
6085 const char text
[] = "foo bar\n";
6088 /* register class to capture WM_COMMAND */
6090 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
6093 cls
.hInstance
= GetModuleHandleA(0);
6095 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6096 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6097 cls
.lpszMenuName
= NULL
;
6098 cls
.lpszClassName
= "EventMaskParentClass";
6099 if(!RegisterClassA(&cls
)) assert(0);
6101 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6102 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6103 ok (parent
!= 0, "Failed to create parent window\n");
6105 eventMaskEditHwnd
= new_richedit(parent
);
6106 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
6108 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
6109 ret
= SendMessageA(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
6110 ok(ret
== ENM_NONE
, "wrong event mask\n");
6111 ret
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
6112 ok(ret
== eventMask
, "failed to set event mask\n");
6114 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
6115 queriedEventMask
= 0; /* initialize to something other than we expect */
6116 watchForEventMask
= EN_CHANGE
;
6117 ret
= SendMessageA(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6118 ok(ret
== TRUE
, "failed to set text\n");
6119 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
6120 notification in response to WM_SETTEXT */
6121 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
6122 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6124 /* check to see if EN_CHANGE is sent when redraw is turned off */
6125 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
6126 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6127 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
6128 /* redraw is disabled by making the window invisible. */
6129 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
6130 queriedEventMask
= 0; /* initialize to something other than we expect */
6131 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6132 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
6133 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6134 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
6135 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6137 /* check to see if EN_UPDATE is sent when the editor isn't visible */
6138 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
6139 style
= GetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
);
6140 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
6141 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
6142 watchForEventMask
= EN_UPDATE
;
6143 queriedEventMask
= 0; /* initialize to something other than we expect */
6144 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6145 ok(queriedEventMask
== 0,
6146 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6147 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
);
6148 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6149 queriedEventMask
= 0; /* initialize to something other than we expect */
6150 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6151 ok(queriedEventMask
== eventMask
,
6152 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6155 DestroyWindow(parent
);
6158 static int received_WM_NOTIFY
= 0;
6159 static int modify_at_WM_NOTIFY
= 0;
6160 static BOOL filter_on_WM_NOTIFY
= FALSE
;
6161 static HWND hwndRichedit_WM_NOTIFY
;
6163 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6165 if(message
== WM_NOTIFY
)
6167 received_WM_NOTIFY
= 1;
6168 modify_at_WM_NOTIFY
= SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
6169 if (filter_on_WM_NOTIFY
) return TRUE
;
6171 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6174 static void test_WM_NOTIFY(void)
6179 int sel_start
, sel_end
;
6181 /* register class to capture WM_NOTIFY */
6183 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
6186 cls
.hInstance
= GetModuleHandleA(0);
6188 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6189 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6190 cls
.lpszMenuName
= NULL
;
6191 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
6192 if(!RegisterClassA(&cls
)) assert(0);
6194 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6195 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6196 ok (parent
!= 0, "Failed to create parent window\n");
6198 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
6199 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
6201 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
6203 /* Notifications for selection change should only be sent when selection
6204 actually changes. EM_SETCHARFORMAT is one message that calls
6205 ME_CommitUndo, which should check whether message should be sent */
6206 received_WM_NOTIFY
= 0;
6207 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
6208 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
6209 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
6210 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
6211 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
6212 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
6214 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
6216 received_WM_NOTIFY
= 0;
6217 modify_at_WM_NOTIFY
= 0;
6218 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
6219 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
6220 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6222 received_WM_NOTIFY
= 0;
6223 modify_at_WM_NOTIFY
= 0;
6224 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
6225 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6227 received_WM_NOTIFY
= 0;
6228 modify_at_WM_NOTIFY
= 0;
6229 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
6230 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6231 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6233 /* Test for WM_NOTIFY messages with redraw disabled. */
6234 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
6235 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
6236 received_WM_NOTIFY
= 0;
6237 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
6238 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6239 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
6241 /* Test filtering key events. */
6242 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
6243 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
6244 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6245 received_WM_NOTIFY
= 0;
6246 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6247 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6248 ok(sel_start
== 1 && sel_end
== 1,
6249 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6250 filter_on_WM_NOTIFY
= TRUE
;
6251 received_WM_NOTIFY
= 0;
6252 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6253 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6254 ok(sel_start
== 1 && sel_end
== 1,
6255 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6257 /* test with owner set to NULL */
6258 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
6259 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6260 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6261 ok(sel_start
== 1 && sel_end
== 1,
6262 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6264 DestroyWindow(hwndRichedit_WM_NOTIFY
);
6265 DestroyWindow(parent
);
6268 static ENLINK enlink
;
6269 #define CURSOR_CLIENT_X 5
6270 #define CURSOR_CLIENT_Y 5
6274 static LRESULT WINAPI
EN_LINK_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6276 if(message
== WM_NOTIFY
&& ((NMHDR
*)lParam
)->code
== EN_LINK
)
6278 enlink
= *(ENLINK
*)lParam
;
6280 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6283 static void link_notify_test(const char *desc
, int i
, HWND hwnd
, HWND parent
,
6284 UINT msg
, WPARAM wParam
, LPARAM lParam
, BOOL notifies
)
6290 case WM_LBUTTONDBLCLK
:
6291 case WM_LBUTTONDOWN
:
6296 case WM_RBUTTONDBLCLK
:
6297 case WM_RBUTTONDOWN
:
6299 lParam
= MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
);
6302 if (wParam
== WP_PARENT
)
6303 wParam
= (WPARAM
)parent
;
6304 else if (wParam
== WP_CHILD
)
6305 wParam
= (WPARAM
)hwnd
;
6309 memset(&junk_enlink
, 0x23, sizeof(junk_enlink
));
6310 enlink
= junk_enlink
;
6312 SendMessageA(hwnd
, msg
, wParam
, lParam
);
6316 ok(enlink
.nmhdr
.hwndFrom
== hwnd
,
6317 "%s test %i: Expected hwnd %p got %p\n", desc
, i
, hwnd
, enlink
.nmhdr
.hwndFrom
);
6318 ok(enlink
.nmhdr
.idFrom
== 0,
6319 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc
, i
, enlink
.nmhdr
.idFrom
);
6320 ok(enlink
.msg
== msg
,
6321 "%s test %i: Expected msg 0x%x got 0x%x\n", desc
, i
, msg
, enlink
.msg
);
6322 if (msg
== WM_SETCURSOR
)
6324 ok(enlink
.wParam
== 0,
6325 "%s test %i: Expected wParam 0 got 0x%lx\n", desc
, i
, enlink
.wParam
);
6329 ok(enlink
.wParam
== wParam
,
6330 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc
, i
, wParam
, enlink
.wParam
);
6332 ok(enlink
.lParam
== MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
),
6333 "%s test %i: Expected lParam 0x%lx got 0x%lx\n",
6334 desc
, i
, MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
), enlink
.lParam
);
6335 ok(enlink
.chrg
.cpMin
== 0 && enlink
.chrg
.cpMax
== 31,
6336 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc
, i
, enlink
.chrg
.cpMin
, enlink
.chrg
.cpMax
);
6340 ok(memcmp(&enlink
, &junk_enlink
, sizeof(enlink
)) == 0,
6341 "%s test %i: Expected enlink to remain unmodified\n", desc
, i
);
6345 static void test_EN_LINK(void)
6350 POINT orig_cursor_pos
;
6351 POINT cursor_screen_pos
= {CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
};
6361 link_notify_tests
[] =
6363 /* hold down the left button and try some messages */
6364 { WM_LBUTTONDOWN
, 0, 0, TRUE
}, /* 0 */
6365 { EM_LINESCROLL
, 0, 1, FALSE
},
6366 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6367 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6368 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6369 { WM_MOUSEMOVE
, 0, 0, FALSE
},
6370 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6371 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6372 { WM_RBUTTONDOWN
, 0, 0, TRUE
},
6373 { WM_RBUTTONUP
, 0, 0, TRUE
},
6374 { WM_SETCURSOR
, 0, 0, FALSE
},
6375 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6376 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6377 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6378 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
},
6379 { WM_LBUTTONUP
, 0, 0, TRUE
},
6380 /* hold down the right button and try some messages */
6381 { WM_RBUTTONDOWN
, 0, 0, TRUE
}, /* 16 */
6382 { EM_LINESCROLL
, 0, 1, FALSE
},
6383 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6384 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6385 { WM_LBUTTONDOWN
, 0, 0, TRUE
},
6386 { WM_LBUTTONUP
, 0, 0, TRUE
},
6387 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6388 { WM_MOUSEMOVE
, 0, 0, TRUE
},
6389 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6390 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6391 { WM_SETCURSOR
, 0, 0, FALSE
},
6392 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6393 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6394 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6395 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
},
6396 { WM_RBUTTONUP
, 0, 0, TRUE
},
6397 /* try the messages with both buttons released */
6398 { EM_LINESCROLL
, 0, 1, FALSE
}, /* 32 */
6399 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6400 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6401 { WM_LBUTTONDOWN
, 0, 0, TRUE
},
6402 { WM_LBUTTONUP
, 0, 0, TRUE
},
6403 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6404 { WM_MOUSEMOVE
, 0, 0, TRUE
},
6405 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6406 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6407 { WM_RBUTTONDOWN
, 0, 0, TRUE
},
6408 { WM_RBUTTONUP
, 0, 0, TRUE
},
6409 { WM_SETCURSOR
, 0, 0, FALSE
},
6410 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6411 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6412 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6413 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
}
6416 /* register class to capture WM_NOTIFY */
6418 cls
.lpfnWndProc
= EN_LINK_ParentMsgCheckProcA
;
6421 cls
.hInstance
= GetModuleHandleA(0);
6423 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6424 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6425 cls
.lpszMenuName
= NULL
;
6426 cls
.lpszClassName
= "EN_LINK_ParentClass";
6427 if(!RegisterClassA(&cls
)) assert(0);
6429 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6430 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6431 ok(parent
!= 0, "Failed to create parent window\n");
6433 hwnd
= new_richedit(parent
);
6434 ok(hwnd
!= 0, "Failed to create edit window\n");
6436 SendMessageA(hwnd
, EM_SETEVENTMASK
, 0, ENM_LINK
);
6438 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
6439 cf2
.dwMask
= CFM_LINK
;
6440 cf2
.dwEffects
= CFE_LINK
;
6441 SendMessageA(hwnd
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
6442 /* mixing letters and numbers causes runs to be split */
6443 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"link text with at least 2 runs");
6445 GetCursorPos(&orig_cursor_pos
);
6448 for (i
= 0; i
< sizeof(link_notify_tests
)/sizeof(link_notify_tests
[0]); i
++)
6450 link_notify_test("cursor position simulated", i
, hwnd
, parent
,
6451 link_notify_tests
[i
].msg
, link_notify_tests
[i
].wParam
, link_notify_tests
[i
].lParam
,
6452 link_notify_tests
[i
].msg
== WM_SETCURSOR
? FALSE
: link_notify_tests
[i
].notifies
);
6455 ClientToScreen(hwnd
, &cursor_screen_pos
);
6456 SetCursorPos(cursor_screen_pos
.x
, cursor_screen_pos
.y
);
6458 for (i
= 0; i
< sizeof(link_notify_tests
)/sizeof(link_notify_tests
[0]); i
++)
6460 link_notify_test("cursor position set", i
, hwnd
, parent
,
6461 link_notify_tests
[i
].msg
, link_notify_tests
[i
].wParam
, link_notify_tests
[i
].lParam
,
6462 link_notify_tests
[i
].notifies
);
6465 SetCursorPos(orig_cursor_pos
.x
, orig_cursor_pos
.y
);
6466 DestroyWindow(hwnd
);
6467 DestroyWindow(parent
);
6470 static void test_undo_coalescing(void)
6474 char buffer
[64] = {0};
6476 /* multi-line control inserts CR normally */
6477 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
6478 0, 0, 200, 60, 0, 0, 0, 0);
6479 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6481 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6482 ok (result
== FALSE
, "Can undo after window creation.\n");
6483 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6484 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
6485 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6486 ok (result
== FALSE
, "Can redo after window creation.\n");
6487 result
= SendMessageA(hwnd
, EM_REDO
, 0, 0);
6488 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
6490 /* Test the effect of arrows keys during typing on undo transactions*/
6491 simulate_typing_characters(hwnd
, "one two three");
6492 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
6493 SendMessageA(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
6494 simulate_typing_characters(hwnd
, " four five six");
6496 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6497 ok (result
== FALSE
, "Can redo before anything is undone.\n");
6498 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6499 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6500 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6501 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
6502 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6503 ok (result
== TRUE
, "Cannot redo after undo.\n");
6504 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6505 result
= strcmp(buffer
, "one two three");
6506 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6508 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6509 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6510 result
= SendMessageA(hwnd
, WM_UNDO
, 0, 0);
6511 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6512 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6513 result
= strcmp(buffer
, "");
6514 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6516 /* Test the effect of focus changes during typing on undo transactions*/
6517 simulate_typing_characters(hwnd
, "one two three");
6518 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6519 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6520 SendMessageA(hwnd
, WM_KILLFOCUS
, 0, 0);
6521 SendMessageA(hwnd
, WM_SETFOCUS
, 0, 0);
6522 simulate_typing_characters(hwnd
, " four five six");
6523 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6524 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6525 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6526 result
= strcmp(buffer
, "one two three");
6527 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6529 /* Test the effect of the back key during typing on undo transactions */
6530 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6531 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6532 ok (result
== TRUE
, "Failed to clear the text.\n");
6533 simulate_typing_characters(hwnd
, "one two threa");
6534 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6535 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6536 SendMessageA(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
6537 SendMessageA(hwnd
, WM_KEYUP
, VK_BACK
, 1);
6538 simulate_typing_characters(hwnd
, "e four five six");
6539 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6540 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6541 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6542 result
= strcmp(buffer
, "");
6543 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6545 /* Test the effect of the delete key during typing on undo transactions */
6546 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6547 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
6548 ok(result
== TRUE
, "Failed to set the text.\n");
6549 SendMessageA(hwnd
, EM_SETSEL
, 1, 1);
6550 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6551 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6552 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6553 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6554 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6555 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6556 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6557 result
= strcmp(buffer
, "acd");
6558 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
6559 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6560 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6561 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6562 result
= strcmp(buffer
, "abcd");
6563 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
6565 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
6566 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6567 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6568 ok (result
== TRUE
, "Failed to clear the text.\n");
6569 simulate_typing_characters(hwnd
, "one two three");
6570 result
= SendMessageA(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
6571 ok (result
== 0, "expected %d but got %d\n", 0, result
);
6572 simulate_typing_characters(hwnd
, " four five six");
6573 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6574 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6575 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6576 result
= strcmp(buffer
, "one two three");
6577 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6578 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6579 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6580 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6581 result
= strcmp(buffer
, "");
6582 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6584 DestroyWindow(hwnd
);
6587 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
6591 /* MSDN lied, length is actually the number of bytes. */
6592 length
= bytes
/ sizeof(WCHAR
);
6595 case WB_ISDELIMITER
:
6596 return text
[pos
] == 'X';
6598 case WB_MOVEWORDLEFT
:
6599 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6601 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
6604 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6608 case WB_MOVEWORDRIGHT
:
6609 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6611 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
6614 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6618 ok(FALSE
, "Unexpected code %d\n", code
);
6624 static void test_word_movement(void)
6628 int sel_start
, sel_end
;
6629 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
6631 /* multi-line control inserts CR normally */
6632 hwnd
= new_richedit(NULL
);
6634 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
6635 ok (result
== TRUE
, "Failed to clear the text.\n");
6636 SendMessageA(hwnd
, EM_SETSEL
, 0, 0);
6637 /* |one two three */
6639 send_ctrl_key(hwnd
, VK_RIGHT
);
6640 /* one |two three */
6641 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6642 ok(sel_start
== sel_end
, "Selection should be empty\n");
6643 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6645 send_ctrl_key(hwnd
, VK_RIGHT
);
6646 /* one two |three */
6647 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6648 ok(sel_start
== sel_end
, "Selection should be empty\n");
6649 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6651 send_ctrl_key(hwnd
, VK_LEFT
);
6652 /* one |two three */
6653 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6654 ok(sel_start
== sel_end
, "Selection should be empty\n");
6655 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6657 send_ctrl_key(hwnd
, VK_LEFT
);
6658 /* |one two three */
6659 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6660 ok(sel_start
== sel_end
, "Selection should be empty\n");
6661 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
6663 SendMessageA(hwnd
, EM_SETSEL
, 8, 8);
6664 /* one two | three */
6665 send_ctrl_key(hwnd
, VK_RIGHT
);
6666 /* one two |three */
6667 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6668 ok(sel_start
== sel_end
, "Selection should be empty\n");
6669 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6671 SendMessageA(hwnd
, EM_SETSEL
, 11, 11);
6672 /* one two th|ree */
6673 send_ctrl_key(hwnd
, VK_LEFT
);
6674 /* one two |three */
6675 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6676 ok(sel_start
== sel_end
, "Selection should be empty\n");
6677 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6679 /* Test with a custom word break procedure that uses X as the delimiter. */
6680 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
6681 ok (result
== TRUE
, "Failed to clear the text.\n");
6682 SendMessageA(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6683 /* |one twoXthree */
6684 send_ctrl_key(hwnd
, VK_RIGHT
);
6685 /* one twoX|three */
6686 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6687 ok(sel_start
== sel_end
, "Selection should be empty\n");
6688 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6690 DestroyWindow(hwnd
);
6692 /* Make sure the behaviour is the same with a unicode richedit window,
6693 * and using unicode functions. */
6695 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
6696 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6697 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6699 /* Test with a custom word break procedure that uses X as the delimiter. */
6700 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
6701 ok (result
== TRUE
, "Failed to clear the text.\n");
6702 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6703 /* |one twoXthree */
6704 send_ctrl_key(hwnd
, VK_RIGHT
);
6705 /* one twoX|three */
6706 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6707 ok(sel_start
== sel_end
, "Selection should be empty\n");
6708 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6710 DestroyWindow(hwnd
);
6713 static void test_EM_CHARFROMPOS(void)
6722 /* multi-line control inserts CR normally */
6723 hwnd
= new_richedit(NULL
);
6724 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
6725 (LPARAM
)"one two three four five six seven\reight");
6726 ok(result
== 1, "Expected 1, got %d\n", result
);
6727 GetClientRect(hwnd
, &rcClient
);
6729 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6730 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6732 /* Test with points outside the bounds of the richedit control. */
6735 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6736 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6740 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6741 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
6745 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6746 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6750 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6751 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
6754 point
.y
= rcClient
.bottom
+ 1;
6755 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6756 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6759 point
.y
= rcClient
.bottom
;
6760 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6761 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6763 DestroyWindow(hwnd
);
6766 static void test_word_wrap(void)
6769 POINTL point
= {0, 60}; /* This point must be below the first line */
6770 const char *text
= "Must be long enough to test line wrapping";
6771 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
6772 int res
, pos
, lines
;
6774 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
6775 * when specified on window creation and set later. */
6776 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6777 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6778 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6779 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6780 ok(res
, "WM_SETTEXT failed.\n");
6781 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6782 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6783 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6784 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6786 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
6787 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6788 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6789 DestroyWindow(hwnd
);
6791 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
6792 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6793 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6795 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6796 ok(res
, "WM_SETTEXT failed.\n");
6797 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6798 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6799 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6800 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6802 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6803 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6804 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6805 DestroyWindow(hwnd
);
6807 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
6808 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6809 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6810 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6811 ok(res
, "WM_SETTEXT failed.\n");
6812 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6813 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6815 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6816 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6817 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6818 DestroyWindow(hwnd
);
6820 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
6821 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
6822 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6823 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6824 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6825 ok(res
, "WM_SETTEXT failed.\n");
6826 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6827 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6829 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6830 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6831 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6833 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
6834 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
6835 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6836 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6837 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6839 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
6840 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6841 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6842 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6843 DestroyWindow(hwnd
);
6845 /* Test to see if wrapping happens with redraw disabled. */
6846 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6847 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6848 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6849 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
6850 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
6851 ok(res
, "EM_REPLACESEL failed.\n");
6852 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6853 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6854 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
6855 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6856 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6858 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6859 DestroyWindow(hwnd
);
6862 static void test_autoscroll(void)
6864 HWND hwnd
= new_richedit(NULL
);
6865 int lines
, ret
, redraw
;
6868 for (redraw
= 0; redraw
<= 1; redraw
++) {
6869 trace("testing with WM_SETREDRAW=%d\n", redraw
);
6870 SendMessageA(hwnd
, WM_SETREDRAW
, redraw
, 0);
6871 SendMessageA(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
6872 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6873 ok(lines
== 8, "%d lines instead of 8\n", lines
);
6874 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6875 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6876 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
6877 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6878 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
6880 SendMessageA(hwnd
, WM_SETTEXT
, 0, 0);
6881 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6882 ok(lines
== 1, "%d lines instead of 1\n", lines
);
6883 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6884 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6885 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
6886 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6887 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
6890 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6891 DestroyWindow(hwnd
);
6893 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
6894 * auto vertical/horizontal scrolling options. */
6895 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6896 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
6897 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6898 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6899 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6900 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
6901 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
6902 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6903 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6904 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6905 DestroyWindow(hwnd
);
6907 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6908 WS_POPUP
|ES_MULTILINE
,
6909 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6910 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6911 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6912 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
6913 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
6914 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6915 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6916 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6917 DestroyWindow(hwnd
);
6921 static void test_format_rect(void)
6924 RECT rc
, expected
, clientRect
;
6928 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6929 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6930 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6931 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6933 GetClientRect(hwnd
, &clientRect
);
6935 expected
= clientRect
;
6937 expected
.right
-= 1;
6938 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6939 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6940 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6941 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6942 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6943 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6945 for (n
= -3; n
<= 3; n
++)
6952 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6955 expected
.top
= max(0, rc
.top
);
6956 expected
.left
= max(0, rc
.left
);
6957 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
6958 expected
.right
= min(clientRect
.right
, rc
.right
);
6959 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6960 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6961 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6962 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6963 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6964 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6968 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6969 expected
= clientRect
;
6970 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6971 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6972 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6973 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6974 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6975 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6977 /* Adding the selectionbar adds the selectionbar width to the left side. */
6978 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
6979 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6980 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
6981 expected
.left
+= 8; /* selection bar width */
6982 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6983 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6984 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6985 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6986 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6987 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6990 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6991 expected
= clientRect
;
6992 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6993 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6994 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6995 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6996 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6997 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6999 /* Removing the selectionbar subtracts the selectionbar width from the left side,
7000 * even if the left side is already 0. */
7001 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
7002 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
7003 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
7004 expected
.left
-= 8; /* selection bar width */
7005 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7006 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7007 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7008 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7009 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7010 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7012 /* Set the absolute value of the formatting rectangle. */
7014 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7015 expected
= clientRect
;
7016 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7017 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7018 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7019 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7020 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7021 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7023 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
7024 * LPARAM as being a relative offset when the WPARAM value is 1, but these
7025 * tests show that this isn't true. */
7028 rc
.bottom
= clientRect
.bottom
- 15;
7029 rc
.right
= clientRect
.right
- 15;
7031 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
7032 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7033 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7034 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7035 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7036 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7037 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7039 /* For some reason it does not limit the values to the client rect with
7040 * a WPARAM value of 1. */
7043 rc
.bottom
= clientRect
.bottom
+ 15;
7044 rc
.right
= clientRect
.right
+ 15;
7046 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
7047 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7048 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7049 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7050 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7051 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7052 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7054 /* Reset to default rect and check how the format rect adjusts to window
7055 * resize and how it copes with very small windows */
7056 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
7058 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
7059 GetClientRect(hwnd
, &clientRect
);
7061 expected
= clientRect
;
7063 expected
.right
-= 1;
7064 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7065 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7066 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7067 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7068 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7069 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7071 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
7072 GetClientRect(hwnd
, &clientRect
);
7074 expected
= clientRect
;
7076 expected
.right
-= 1;
7077 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7078 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7079 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7080 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7081 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7082 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7084 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
7085 GetClientRect(hwnd
, &clientRect
);
7087 expected
= clientRect
;
7089 expected
.right
-= 1;
7090 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7091 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7092 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7093 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7094 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7095 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7097 DestroyWindow(hwnd
);
7099 /* The extended window style affects the formatting rectangle. */
7100 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS20A
, NULL
,
7101 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
7102 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7103 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7105 GetClientRect(hwnd
, &clientRect
);
7107 expected
= clientRect
;
7110 expected
.right
-= 1;
7111 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7112 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7113 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7114 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7115 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7116 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7126 expected
.right
+= 1;
7127 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7128 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7129 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
7130 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
7131 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
7132 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
7133 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
7135 DestroyWindow(hwnd
);
7138 static void test_WM_GETDLGCODE(void)
7144 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7146 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7147 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
7148 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7149 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7151 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
7152 expected
= expected
| DLGC_WANTMESSAGE
;
7153 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7155 DestroyWindow(hwnd
);
7157 msg
.message
= WM_KEYDOWN
;
7158 msg
.wParam
= VK_RETURN
;
7159 msg
.lParam
= (MapVirtualKeyA(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7162 msg
.time
= GetTickCount();
7164 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7165 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
7166 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7167 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7169 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7170 expected
= expected
| DLGC_WANTMESSAGE
;
7171 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7173 DestroyWindow(hwnd
);
7175 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7176 ES_MULTILINE
|WS_POPUP
,
7177 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7178 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7180 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7181 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7182 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7184 DestroyWindow(hwnd
);
7186 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7187 ES_WANTRETURN
|WS_POPUP
,
7188 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7189 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7191 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7192 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7193 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7195 DestroyWindow(hwnd
);
7197 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7199 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7200 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7202 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7203 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7204 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7206 DestroyWindow(hwnd
);
7208 msg
.wParam
= VK_TAB
;
7209 msg
.lParam
= (MapVirtualKeyA(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7211 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7212 ES_MULTILINE
|WS_POPUP
,
7213 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7214 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7216 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7217 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7218 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7220 DestroyWindow(hwnd
);
7222 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7224 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7225 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7227 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7228 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7229 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7231 DestroyWindow(hwnd
);
7233 hold_key(VK_CONTROL
);
7235 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7236 ES_MULTILINE
|WS_POPUP
,
7237 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7238 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7240 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7241 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7242 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7244 DestroyWindow(hwnd
);
7246 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7248 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7249 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7251 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7252 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7253 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7255 DestroyWindow(hwnd
);
7257 release_key(VK_CONTROL
);
7260 msg
.lParam
= (MapVirtualKeyA('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7262 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7263 ES_MULTILINE
|WS_POPUP
,
7264 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7265 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7267 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7268 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7269 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7271 DestroyWindow(hwnd
);
7273 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7275 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7276 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7278 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7279 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7280 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7282 DestroyWindow(hwnd
);
7284 msg
.message
= WM_CHAR
;
7286 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7287 ES_MULTILINE
|WS_POPUP
,
7288 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7289 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7291 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7292 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7293 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7295 DestroyWindow(hwnd
);
7297 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7299 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7300 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7302 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7303 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7304 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7306 DestroyWindow(hwnd
);
7308 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7309 WS_POPUP
|ES_SAVESEL
,
7310 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7311 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7312 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
7313 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
;
7314 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7316 DestroyWindow(hwnd
);
7319 static void test_zoom(void)
7325 int numerator
, denominator
;
7327 hwnd
= new_richedit(NULL
);
7328 GetClientRect(hwnd
, &rc
);
7329 pt
.x
= (rc
.right
- rc
.left
) / 2;
7330 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
7331 ClientToScreen(hwnd
, &pt
);
7333 /* Test initial zoom value */
7334 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7335 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
7336 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
7337 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7339 /* test scroll wheel */
7340 hold_key(VK_CONTROL
);
7341 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7342 MAKELPARAM(pt
.x
, pt
.y
));
7343 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7344 release_key(VK_CONTROL
);
7346 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7347 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
7348 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7349 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7351 /* Test how much the mouse wheel can zoom in and out. */
7352 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 490, 100);
7353 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7355 hold_key(VK_CONTROL
);
7356 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7357 MAKELPARAM(pt
.x
, pt
.y
));
7358 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7359 release_key(VK_CONTROL
);
7361 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7362 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
7363 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7364 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7366 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 491, 100);
7367 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7369 hold_key(VK_CONTROL
);
7370 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7371 MAKELPARAM(pt
.x
, pt
.y
));
7372 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7373 release_key(VK_CONTROL
);
7375 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7376 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
7377 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7378 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7380 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 20, 100);
7381 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7383 hold_key(VK_CONTROL
);
7384 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
7385 MAKELPARAM(pt
.x
, pt
.y
));
7386 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7387 release_key(VK_CONTROL
);
7389 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7390 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
7391 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7392 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7394 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 19, 100);
7395 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7397 hold_key(VK_CONTROL
);
7398 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
7399 MAKELPARAM(pt
.x
, pt
.y
));
7400 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7401 release_key(VK_CONTROL
);
7403 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7404 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
7405 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7406 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7408 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
7409 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 50, 13);
7410 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7412 hold_key(VK_CONTROL
);
7413 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7414 MAKELPARAM(pt
.x
, pt
.y
));
7415 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7416 release_key(VK_CONTROL
);
7418 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7419 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
7420 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7421 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7423 /* Test bounds checking on EM_SETZOOM */
7424 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 127);
7425 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
7427 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 127, 2);
7428 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
7430 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 128);
7431 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7433 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7434 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7435 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7436 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7438 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 128, 2);
7439 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7441 /* See if negative numbers are accepted. */
7442 ret
= SendMessageA(hwnd
, EM_SETZOOM
, -100, -100);
7443 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7445 /* See if negative numbers are accepted. */
7446 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 100);
7447 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
7449 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7450 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7451 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7452 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7454 /* Reset the zoom value */
7455 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 0);
7456 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7458 DestroyWindow(hwnd
);
7461 struct dialog_mode_messages
7463 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
7466 static struct dialog_mode_messages dm_messages
;
7468 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
7469 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
7470 "got %d\n", wmclose, dm_messages.wm_close); \
7471 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
7472 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
7473 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
7474 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
7476 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
7481 dm_messages
.wm_getdefid
++;
7482 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
7484 dm_messages
.wm_nextdlgctl
++;
7487 dm_messages
.wm_close
++;
7491 return DefWindowProcA(hwnd
, iMsg
, wParam
, lParam
);
7494 static void test_dialogmode(void)
7496 HWND hwRichEdit
, hwParent
, hwButton
;
7502 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
7505 cls
.hInstance
= GetModuleHandleA(0);
7507 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
7508 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
7509 cls
.lpszMenuName
= NULL
;
7510 cls
.lpszClassName
= "DialogModeParentClass";
7511 if(!RegisterClassA(&cls
)) assert(0);
7513 hwParent
= CreateWindowA("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
7514 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
7516 /* Test richedit(ES_MULTILINE) */
7518 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7520 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7521 ok(0 == r
, "expected 0, got %d\n", r
);
7522 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7523 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7525 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
7526 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7528 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7529 ok(0 == r
, "expected 0, got %d\n", r
);
7530 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7531 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7533 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7534 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7535 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7536 ok(0 == r
, "expected 0, got %d\n", r
);
7537 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7538 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7540 DestroyWindow(hwRichEdit
);
7542 /* Test standalone richedit(ES_MULTILINE) */
7544 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, NULL
);
7546 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7547 ok(0 == r
, "expected 0, got %d\n", r
);
7548 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7549 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7551 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7552 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7554 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7555 ok(0 == r
, "expected 0, got %d\n", r
);
7556 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7557 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7559 DestroyWindow(hwRichEdit
);
7561 /* Check a destination for messages */
7563 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7565 SetWindowLongA(hwRichEdit
, GWL_STYLE
, GetWindowLongA(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
7566 SetParent( hwRichEdit
, NULL
);
7568 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7569 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7571 memset(&dm_messages
, 0, sizeof(dm_messages
));
7572 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7573 ok(0 == r
, "expected 0, got %d\n", r
);
7574 test_dm_messages(0, 1, 0);
7576 memset(&dm_messages
, 0, sizeof(dm_messages
));
7577 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7578 ok(0 == r
, "expected 0, got %d\n", r
);
7579 test_dm_messages(0, 0, 1);
7581 DestroyWindow(hwRichEdit
);
7583 /* Check messages from richedit(ES_MULTILINE) */
7585 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7587 memset(&dm_messages
, 0, sizeof(dm_messages
));
7588 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7589 ok(0 == r
, "expected 0, got %d\n", r
);
7590 test_dm_messages(0, 0, 0);
7592 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7593 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7595 memset(&dm_messages
, 0, sizeof(dm_messages
));
7596 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7597 ok(0 == r
, "expected 0, got %d\n", r
);
7598 test_dm_messages(0, 0, 0);
7600 memset(&dm_messages
, 0, sizeof(dm_messages
));
7601 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7602 ok(0 == r
, "expected 0, got %d\n", r
);
7603 test_dm_messages(0, 0, 0);
7605 memset(&dm_messages
, 0, sizeof(dm_messages
));
7606 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7607 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7608 test_dm_messages(0, 0, 0);
7610 memset(&dm_messages
, 0, sizeof(dm_messages
));
7611 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7612 ok(0 == r
, "expected 0, got %d\n", r
);
7613 test_dm_messages(0, 1, 0);
7615 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7616 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7618 memset(&dm_messages
, 0, sizeof(dm_messages
));
7619 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7620 ok(0 == r
, "expected 0, got %d\n", r
);
7621 test_dm_messages(0, 0, 0);
7623 memset(&dm_messages
, 0, sizeof(dm_messages
));
7624 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7625 ok(0 == r
, "expected 0, got %d\n", r
);
7626 test_dm_messages(0, 0, 1);
7628 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7629 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7630 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7632 memset(&dm_messages
, 0, sizeof(dm_messages
));
7633 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7634 ok(0 == r
, "expected 0, got %d\n", r
);
7635 test_dm_messages(0, 1, 1);
7637 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7638 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7640 DestroyWindow(hwButton
);
7641 DestroyWindow(hwRichEdit
);
7643 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
7645 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
7647 memset(&dm_messages
, 0, sizeof(dm_messages
));
7648 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7649 ok(0 == r
, "expected 0, got %d\n", r
);
7650 test_dm_messages(0, 0, 0);
7652 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7653 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7655 memset(&dm_messages
, 0, sizeof(dm_messages
));
7656 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7657 ok(0 == r
, "expected 0, got %d\n", r
);
7658 test_dm_messages(0, 0, 0);
7660 memset(&dm_messages
, 0, sizeof(dm_messages
));
7661 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7662 ok(0 == r
, "expected 0, got %d\n", r
);
7663 test_dm_messages(0, 0, 0);
7665 memset(&dm_messages
, 0, sizeof(dm_messages
));
7666 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7667 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7668 test_dm_messages(0, 0, 0);
7670 memset(&dm_messages
, 0, sizeof(dm_messages
));
7671 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7672 ok(0 == r
, "expected 0, got %d\n", r
);
7673 test_dm_messages(0, 0, 0);
7675 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7676 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7678 memset(&dm_messages
, 0, sizeof(dm_messages
));
7679 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7680 ok(0 == r
, "expected 0, got %d\n", r
);
7681 test_dm_messages(0, 0, 0);
7683 memset(&dm_messages
, 0, sizeof(dm_messages
));
7684 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7685 ok(0 == r
, "expected 0, got %d\n", r
);
7686 test_dm_messages(0, 0, 1);
7688 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7689 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7690 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7692 memset(&dm_messages
, 0, sizeof(dm_messages
));
7693 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7694 ok(0 == r
, "expected 0, got %d\n", r
);
7695 test_dm_messages(0, 0, 0);
7697 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7698 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7700 DestroyWindow(hwButton
);
7701 DestroyWindow(hwRichEdit
);
7703 /* Check messages from richedit(0) */
7705 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, 0, hwParent
);
7707 memset(&dm_messages
, 0, sizeof(dm_messages
));
7708 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7709 ok(0 == r
, "expected 0, got %d\n", r
);
7710 test_dm_messages(0, 0, 0);
7712 memset(&dm_messages
, 0, sizeof(dm_messages
));
7713 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7714 ok(0 == r
, "expected 0, got %d\n", r
);
7715 test_dm_messages(0, 0, 0);
7717 memset(&dm_messages
, 0, sizeof(dm_messages
));
7718 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7719 ok(0 == r
, "expected 0, got %d\n", r
);
7720 test_dm_messages(0, 0, 0);
7722 memset(&dm_messages
, 0, sizeof(dm_messages
));
7723 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7724 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7725 test_dm_messages(0, 0, 0);
7727 memset(&dm_messages
, 0, sizeof(dm_messages
));
7728 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7729 ok(0 == r
, "expected 0, got %d\n", r
);
7730 test_dm_messages(0, 1, 0);
7732 memset(&dm_messages
, 0, sizeof(dm_messages
));
7733 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7734 ok(0 == r
, "expected 0, got %d\n", r
);
7735 test_dm_messages(0, 0, 0);
7737 memset(&dm_messages
, 0, sizeof(dm_messages
));
7738 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7739 ok(0 == r
, "expected 0, got %d\n", r
);
7740 test_dm_messages(0, 0, 1);
7742 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7743 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7744 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7746 memset(&dm_messages
, 0, sizeof(dm_messages
));
7747 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7748 ok(0 == r
, "expected 0, got %d\n", r
);
7749 test_dm_messages(0, 1, 1);
7751 DestroyWindow(hwRichEdit
);
7753 /* Check messages from richedit(ES_WANTRETURN) */
7755 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_WANTRETURN
, hwParent
);
7757 memset(&dm_messages
, 0, sizeof(dm_messages
));
7758 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7759 ok(0 == r
, "expected 0, got %d\n", r
);
7760 test_dm_messages(0, 0, 0);
7762 memset(&dm_messages
, 0, sizeof(dm_messages
));
7763 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7764 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7765 test_dm_messages(0, 0, 0);
7767 memset(&dm_messages
, 0, sizeof(dm_messages
));
7768 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7769 ok(0 == r
, "expected 0, got %d\n", r
);
7770 test_dm_messages(0, 0, 0);
7772 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7773 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7774 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7776 memset(&dm_messages
, 0, sizeof(dm_messages
));
7777 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7778 ok(0 == r
, "expected 0, got %d\n", r
);
7779 test_dm_messages(0, 0, 0);
7781 DestroyWindow(hwRichEdit
);
7782 DestroyWindow(hwParent
);
7785 static void test_EM_FINDWORDBREAK_W(void)
7787 static const struct {
7789 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7790 } delimiter_tests
[] = {
7791 {0x0a, FALSE
}, /* newline */
7792 {0x0b, FALSE
}, /* vertical tab */
7793 {0x0c, FALSE
}, /* form feed */
7794 {0x0d, FALSE
}, /* carriage return */
7795 {0x20, TRUE
}, /* space */
7796 {0x61, FALSE
}, /* capital letter a */
7797 {0xa0, FALSE
}, /* no-break space */
7798 {0x2000, FALSE
}, /* en quad */
7799 {0x3000, FALSE
}, /* Ideographic space */
7800 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
7801 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
7802 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
7803 {0xac00, FALSE
}, /* Hangul character GA*/
7804 {0xd7af, FALSE
}, /* End of Hangul character chart */
7805 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
7806 {0xff20, FALSE
}, /* fullwidth commercial @ */
7807 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
7810 HWND hwndRichEdit
= new_richeditW(NULL
);
7811 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
7812 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7817 wbuf
[0] = delimiter_tests
[i
].c
;
7819 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
7820 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
7821 todo_wine_if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
7822 ok(result
== delimiter_tests
[i
].isdelimiter
,
7823 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7824 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7826 DestroyWindow(hwndRichEdit
);
7829 static void test_EM_FINDWORDBREAK_A(void)
7831 static const struct {
7833 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7834 } delimiter_tests
[] = {
7835 {0x0a, FALSE
}, /* newline */
7836 {0x0b, FALSE
}, /* vertical tab */
7837 {0x0c, FALSE
}, /* form feed */
7838 {0x0d, FALSE
}, /* carriage return */
7839 {0x20, TRUE
}, /* space */
7840 {0x61, FALSE
}, /* capital letter a */
7843 HWND hwndRichEdit
= new_richedit(NULL
);
7845 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
7846 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7850 buf
[0] = delimiter_tests
[i
].c
;
7852 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
7853 result
= SendMessageA(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
7854 todo_wine_if (buf
[0] == 0x20)
7855 ok(result
== delimiter_tests
[i
].isdelimiter
,
7856 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7857 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7859 DestroyWindow(hwndRichEdit
);
7863 * This test attempts to show the effect of enter on a richedit
7864 * control v1.0 inserts CRLF whereas for higher versions it only
7865 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
7866 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
7867 * does for higher. The same test is cloned in riched32 and riched20.
7869 static void test_enter(void)
7871 static const struct {
7872 const char *initialtext
;
7874 const char *expectedwmtext
;
7875 const char *expectedemtext
;
7876 const char *expectedemtextcrlf
;
7877 } testenteritems
[] = {
7878 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
7879 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
7880 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
7881 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
7882 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
7885 char expectedbuf
[1024];
7886 char resultbuf
[1024];
7887 HWND hwndRichEdit
= new_richedit(NULL
);
7890 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
7892 char buf
[1024] = {0};
7895 const char *expected
;
7897 /* Set the text to the initial text */
7898 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
7899 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
7902 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
7903 simulate_typing_characters(hwndRichEdit
, "\r");
7905 /* 1. Retrieve with WM_GETTEXT */
7907 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
7908 expected
= testenteritems
[i
].expectedwmtext
;
7911 for (j
= 0; j
< (UINT
)result
; j
++)
7912 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7913 expectedbuf
[0] = '\0';
7914 for (j
= 0; j
< strlen(expected
); j
++)
7915 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7917 result
= strcmp(expected
, buf
);
7919 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
7920 i
, resultbuf
, expectedbuf
);
7922 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
7923 getText
.cb
= sizeof(buf
);
7924 getText
.flags
= GT_DEFAULT
;
7925 getText
.codepage
= CP_ACP
;
7926 getText
.lpDefaultChar
= NULL
;
7927 getText
.lpUsedDefChar
= NULL
;
7929 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7930 expected
= testenteritems
[i
].expectedemtext
;
7933 for (j
= 0; j
< (UINT
)result
; j
++)
7934 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7935 expectedbuf
[0] = '\0';
7936 for (j
= 0; j
< strlen(expected
); j
++)
7937 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7939 result
= strcmp(expected
, buf
);
7941 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
7942 i
, resultbuf
, expectedbuf
);
7944 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
7945 getText
.cb
= sizeof(buf
);
7946 getText
.flags
= GT_USECRLF
;
7947 getText
.codepage
= CP_ACP
;
7948 getText
.lpDefaultChar
= NULL
;
7949 getText
.lpUsedDefChar
= NULL
;
7951 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7952 expected
= testenteritems
[i
].expectedemtextcrlf
;
7955 for (j
= 0; j
< (UINT
)result
; j
++)
7956 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7957 expectedbuf
[0] = '\0';
7958 for (j
= 0; j
< strlen(expected
); j
++)
7959 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7961 result
= strcmp(expected
, buf
);
7963 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
7964 i
, resultbuf
, expectedbuf
);
7967 DestroyWindow(hwndRichEdit
);
7970 static void test_WM_CREATE(void)
7972 static const WCHAR titleW
[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
7973 static const char title
[] = "line1\nline2";
7980 rich_edit
= CreateWindowA(RICHEDIT_CLASS20A
, title
, WS_POPUP
|WS_VISIBLE
,
7981 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7982 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7984 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7985 ok(len
== 5, "GetWindowText returned %d\n", len
);
7986 ok(!strcmp(buf
, "line1"), "buf = %s\n", buf
);
7988 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7989 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7991 DestroyWindow(rich_edit
);
7993 rich_edit
= CreateWindowW(RICHEDIT_CLASS20W
, titleW
, WS_POPUP
|WS_VISIBLE
|ES_MULTILINE
,
7994 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7995 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W
), (int) GetLastError());
7997 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7998 ok(len
== 12, "GetWindowText returned %d\n", len
);
7999 ok(!strcmp(buf
, "line1\r\nline2"), "buf = %s\n", buf
);
8001 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
8002 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
8004 DestroyWindow(rich_edit
);
8007 /*******************************************************************
8008 * Test that after deleting all of the text, the first paragraph
8009 * format reverts to the default.
8011 static void test_reset_default_para_fmt( void )
8013 HWND richedit
= new_richeditW( NULL
);
8015 WORD def_align
, new_align
;
8017 memset( &fmt
, 0, sizeof(fmt
) );
8018 fmt
.cbSize
= sizeof(PARAFORMAT2
);
8020 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8021 def_align
= fmt
.wAlignment
;
8022 new_align
= (def_align
== PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
8024 simulate_typing_characters( richedit
, "123" );
8026 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
8027 fmt
.dwMask
= PFM_ALIGNMENT
;
8028 fmt
.wAlignment
= new_align
;
8029 SendMessageA( richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8031 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8032 ok( fmt
.wAlignment
== new_align
, "got %d expect %d\n", fmt
.wAlignment
, new_align
);
8034 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
8035 SendMessageA( richedit
, WM_CUT
, 0, 0 );
8037 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8038 ok( fmt
.wAlignment
== def_align
, "got %d exppect %d\n", fmt
.wAlignment
, def_align
);
8040 DestroyWindow( richedit
);
8043 static void test_EM_SETREADONLY(void)
8045 HWND richedit
= new_richeditW(NULL
);
8049 res
= SendMessageA(richedit
, EM_SETREADONLY
, TRUE
, 0);
8050 ok(res
== 1, "EM_SETREADONLY\n");
8051 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
8052 ok(dwStyle
& ES_READONLY
, "got wrong value: 0x%x\n", dwStyle
);
8054 res
= SendMessageA(richedit
, EM_SETREADONLY
, FALSE
, 0);
8055 ok(res
== 1, "EM_SETREADONLY\n");
8056 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
8057 ok(!(dwStyle
& ES_READONLY
), "got wrong value: 0x%x\n", dwStyle
);
8059 DestroyWindow(richedit
);
8062 static inline LONG
twips2points(LONG value
)
8067 #define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \
8068 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo)
8069 static void _test_font_size(unsigned line
, HWND hwnd
, LONG size
, LONG expected_size
,
8070 LRESULT expected_res
, BOOL expected_undo
)
8076 cf
.cbSize
= sizeof(cf
);
8077 cf
.dwMask
= CFM_SIZE
;
8079 res
= SendMessageA(hwnd
, EM_SETFONTSIZE
, size
, 0);
8080 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf
);
8081 isundo
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
8082 ok_(__FILE__
,line
)(res
== expected_res
, "EM_SETFONTSIZE unexpected return value: %lx.\n", res
);
8083 ok_(__FILE__
,line
)(twips2points(cf
.yHeight
) == expected_size
, "got wrong font size: %d, expected: %d\n",
8084 twips2points(cf
.yHeight
), expected_size
);
8085 ok_(__FILE__
,line
)(isundo
== expected_undo
, "get wrong undo mark: %d, expected: %d.\n",
8086 isundo
, expected_undo
);
8089 static void test_EM_SETFONTSIZE(void)
8091 HWND richedit
= new_richedit(NULL
);
8092 CHAR text
[] = "wine";
8093 CHARFORMAT2A tmp_cf
;
8096 tmp_cf
.cbSize
= sizeof(tmp_cf
);
8097 tmp_cf
.dwMask
= CFM_SIZE
;
8098 tmp_cf
.yHeight
= 9 * 20.0;
8099 SendMessageA(richedit
, EM_SETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&tmp_cf
);
8101 SendMessageA(richedit
, WM_SETTEXT
, 0, (LPARAM
)text
);
8103 SendMessageA(richedit
, EM_SETMODIFY
, FALSE
, 0);
8104 /* without selection */
8105 TEST_EM_SETFONTSIZE(richedit
, 1, 10, TRUE
, FALSE
); /* 9 + 1 -> 10 */
8106 SendMessageA(richedit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&tmp_cf
);
8107 default_size
= twips2points(tmp_cf
.yHeight
);
8108 ok(default_size
== 9, "Default font size should not be changed.\n");
8109 ok(SendMessageA(richedit
, EM_SETMODIFY
, 0, 0) == FALSE
, "Modify flag should not be changed.\n");
8111 SendMessageA(richedit
, EM_SETSEL
, 0, 2);
8113 TEST_EM_SETFONTSIZE(richedit
, 0, 9, TRUE
, TRUE
); /* 9 + 0 -> 9 */
8115 SendMessageA(richedit
, EM_SETMODIFY
, FALSE
, 0);
8116 TEST_EM_SETFONTSIZE(richedit
, 3, 12, TRUE
, TRUE
); /* 9 + 3 -> 12 */
8117 ok(SendMessageA(richedit
, EM_SETMODIFY
, 0, 0) == FALSE
, "Modify flag should not be changed.\n");
8119 TEST_EM_SETFONTSIZE(richedit
, 1, 14, TRUE
, TRUE
); /* 12 + 1 + 1 -> 14 */
8120 TEST_EM_SETFONTSIZE(richedit
, -1, 12, TRUE
, TRUE
); /* 14 - 1 - 1 -> 12 */
8121 TEST_EM_SETFONTSIZE(richedit
, 4, 16, TRUE
, TRUE
); /* 12 + 4 -> 16 */
8122 TEST_EM_SETFONTSIZE(richedit
, 3, 20, TRUE
, TRUE
); /* 16 + 3 + 1 -> 20 */
8123 TEST_EM_SETFONTSIZE(richedit
, 0, 20, TRUE
, TRUE
); /* 20 + 0 -> 20 */
8124 TEST_EM_SETFONTSIZE(richedit
, 8, 28, TRUE
, TRUE
); /* 20 + 8 -> 28 */
8125 TEST_EM_SETFONTSIZE(richedit
, 0, 28, TRUE
, TRUE
); /* 28 + 0 -> 28 */
8126 TEST_EM_SETFONTSIZE(richedit
, 1, 36, TRUE
, TRUE
); /* 28 + 1 -> 36 */
8127 TEST_EM_SETFONTSIZE(richedit
, 0, 36, TRUE
, TRUE
); /* 36 + 0 -> 36 */
8128 TEST_EM_SETFONTSIZE(richedit
, 1, 48, TRUE
, TRUE
); /* 36 + 1 -> 48 */
8129 TEST_EM_SETFONTSIZE(richedit
, 0, 48, TRUE
, TRUE
); /* 48 + 0 -> 48 */
8130 TEST_EM_SETFONTSIZE(richedit
, 1, 72, TRUE
, TRUE
); /* 48 + 1 -> 72 */
8131 TEST_EM_SETFONTSIZE(richedit
, 0, 72, TRUE
, TRUE
); /* 72 + 0 -> 72 */
8132 TEST_EM_SETFONTSIZE(richedit
, 1, 80, TRUE
, TRUE
); /* 72 + 1 -> 80 */
8133 TEST_EM_SETFONTSIZE(richedit
, 0, 80, TRUE
, TRUE
); /* 80 + 0 -> 80 */
8134 TEST_EM_SETFONTSIZE(richedit
, 1, 90, TRUE
, TRUE
); /* 80 + 1 -> 90 */
8135 TEST_EM_SETFONTSIZE(richedit
, 0, 90, TRUE
, TRUE
); /* 90 + 0 -> 90 */
8136 TEST_EM_SETFONTSIZE(richedit
, 1, 100, TRUE
, TRUE
); /* 90 + 1 -> 100 */
8137 TEST_EM_SETFONTSIZE(richedit
, 25, 130, TRUE
, TRUE
); /* 100 + 25 -> 130 */
8138 TEST_EM_SETFONTSIZE(richedit
, -1, 120, TRUE
, TRUE
); /* 130 - 1 -> 120 */
8139 TEST_EM_SETFONTSIZE(richedit
, -35, 80, TRUE
, TRUE
); /* 120 - 35 -> 80 */
8140 TEST_EM_SETFONTSIZE(richedit
, -7, 72, TRUE
, TRUE
); /* 80 - 7 -> 72 */
8141 TEST_EM_SETFONTSIZE(richedit
, -42, 28, TRUE
, TRUE
); /* 72 - 42 -> 28 */
8142 TEST_EM_SETFONTSIZE(richedit
, -16, 12, TRUE
, TRUE
); /* 28 - 16 -> 12 */
8143 TEST_EM_SETFONTSIZE(richedit
, -3, 9, TRUE
, TRUE
); /* 12 - 3 -> 9 */
8144 TEST_EM_SETFONTSIZE(richedit
, -8, 1, TRUE
, TRUE
); /* 9 - 8 -> 1 */
8145 TEST_EM_SETFONTSIZE(richedit
, -111, 1, TRUE
, TRUE
); /* 1 - 111 -> 1 */
8146 TEST_EM_SETFONTSIZE(richedit
, 10086, 1638, TRUE
, TRUE
); /* 1 + 10086 -> 1638 */
8148 /* return FALSE when richedit is TM_PLAINTEXT mode */
8149 SendMessageA(richedit
, WM_SETTEXT
, 0, (LPARAM
)"");
8150 SendMessageA(richedit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
8151 TEST_EM_SETFONTSIZE(richedit
, 0, 9, FALSE
, FALSE
);
8153 DestroyWindow(richedit
);
8156 static void test_alignment_style(void)
8158 HWND richedit
= NULL
;
8160 DWORD align_style
[] = {ES_LEFT
, ES_CENTER
, ES_RIGHT
, ES_RIGHT
| ES_CENTER
,
8161 ES_LEFT
| ES_CENTER
, ES_LEFT
| ES_RIGHT
,
8162 ES_LEFT
| ES_RIGHT
| ES_CENTER
};
8163 DWORD align_mask
[] = {PFA_LEFT
, PFA_CENTER
, PFA_RIGHT
, PFA_CENTER
, PFA_CENTER
,
8164 PFA_RIGHT
, PFA_CENTER
};
8165 const char * streamtext
=
8166 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
8167 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
8172 for (i
= 0; i
< sizeof(align_style
) / sizeof(align_style
[0]); i
++)
8174 DWORD dwStyle
, new_align
;
8176 richedit
= new_windowW(RICHEDIT_CLASS20W
, align_style
[i
], NULL
);
8177 memset(&pf
, 0, sizeof(pf
));
8178 pf
.cbSize
= sizeof(PARAFORMAT2
);
8181 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8182 ok(pf
.wAlignment
== align_mask
[i
], "(i = %d) got %d expected %d\n",
8183 i
, pf
.wAlignment
, align_mask
[i
]);
8184 dwStyle
= GetWindowLongW(richedit
, GWL_STYLE
);
8185 ok((i
? (dwStyle
& align_style
[i
]) : (!(dwStyle
& 0x0000000f))) ,
8186 "(i = %d) didn't set right align style: 0x%x\n", i
, dwStyle
);
8189 /* Based on test_reset_default_para_fmt() */
8190 new_align
= (align_mask
[i
] == PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
8191 simulate_typing_characters(richedit
, "123");
8193 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8194 pf
.dwMask
= PFM_ALIGNMENT
;
8195 pf
.wAlignment
= new_align
;
8196 SendMessageW(richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf
);
8198 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8199 ok(pf
.wAlignment
== new_align
, "got %d expect %d\n", pf
.wAlignment
, new_align
);
8201 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8202 SendMessageW(richedit
, WM_CUT
, 0, 0);
8204 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8205 ok(pf
.wAlignment
== align_mask
[i
], "got %d exppect %d\n", pf
.wAlignment
, align_mask
[i
]);
8207 DestroyWindow(richedit
);
8210 /* test with EM_STREAMIN */
8211 richedit
= new_windowW(RICHEDIT_CLASS20W
, ES_CENTER
, NULL
);
8212 simulate_typing_characters(richedit
, "abc");
8213 es
.dwCookie
= (DWORD_PTR
)&streamtext
;
8215 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
8216 SendMessageW(richedit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8217 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8218 memset(&pf
, 0, sizeof(pf
));
8219 pf
.cbSize
= sizeof(PARAFORMAT2
);
8221 SendMessageW(richedit
, EM_GETPARAFORMAT
, SCF_SELECTION
, (LPARAM
)&pf
);
8222 ok(pf
.wAlignment
== ES_CENTER
, "got %d expected ES_CENTER\n", pf
.wAlignment
);
8223 DestroyWindow(richedit
);
8226 static void test_WM_GETTEXTLENGTH(void)
8228 HWND hwndRichEdit
= new_richedit(NULL
);
8229 static const char text1
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
8230 static const char text2
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
8231 static const char text3
[] = "abcdef\x8e\xf0";
8234 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
8235 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8236 ok(result
== lstrlenA(text1
), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8237 result
, lstrlenA(text1
));
8239 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
8240 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8241 ok(result
== lstrlenA(text2
), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8242 result
, lstrlenA(text2
));
8244 /* Test with multibyte character */
8245 if (!is_lang_japanese
)
8246 skip("Skip multibyte character tests on non-Japanese platform\n");
8249 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text3
);
8250 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8251 todo_wine
ok(result
== 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result
);
8254 DestroyWindow(hwndRichEdit
);
8257 START_TEST( editor
)
8260 /* Must explicitly LoadLibrary(). The test has no references to functions in
8261 * RICHED20.DLL, so the linker doesn't actually link to it. */
8262 hmoduleRichEdit
= LoadLibraryA("riched20.dll");
8263 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
8264 is_lang_japanese
= (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE
);
8267 test_EM_FINDTEXT(FALSE
);
8268 test_EM_FINDTEXT(TRUE
);
8270 test_EM_POSFROMCHAR();
8271 test_EM_SCROLLCARET();
8273 test_scrollbar_visibility();
8275 test_EM_LINELENGTH();
8276 test_EM_SETCHARFORMAT();
8277 test_EM_SETTEXTMODE();
8278 test_TM_PLAINTEXT();
8279 test_EM_SETOPTIONS();
8281 test_EM_GETTEXTRANGE();
8282 test_EM_GETSELTEXT();
8283 test_EM_SETUNDOLIMIT();
8285 test_EM_SETTEXTEX();
8286 test_EM_LIMITTEXT();
8287 test_EM_EXLIMITTEXT();
8288 test_EM_GETLIMITTEXT();
8290 test_EM_GETMODIFY();
8295 test_EM_STREAMOUT();
8296 test_EM_STREAMOUT_FONTTBL();
8297 test_EM_StreamIn_Undo();
8298 test_EM_FORMATRANGE();
8299 test_unicode_conversions();
8300 test_EM_GETTEXTLENGTHEX();
8301 test_WM_GETTEXTLENGTH();
8302 test_EM_REPLACESEL(1);
8303 test_EM_REPLACESEL(0);
8306 test_EM_AUTOURLDETECT();
8308 test_undo_coalescing();
8309 test_word_movement();
8310 test_EM_CHARFROMPOS();
8311 test_SETPARAFORMAT();
8315 test_WM_GETDLGCODE();
8318 test_EM_FINDWORDBREAK_W();
8319 test_EM_FINDWORDBREAK_A();
8322 test_reset_default_para_fmt();
8323 test_EM_SETREADONLY();
8324 test_EM_SETFONTSIZE();
8325 test_alignment_style();
8327 /* Set the environment variable WINETEST_RICHED20 to keep windows
8328 * responsive and open for 30 seconds. This is useful for debugging.
8330 if (getenv( "WINETEST_RICHED20" )) {
8331 keep_responsive(30);
8334 OleFlushClipboard();
8335 ret
= FreeLibrary(hmoduleRichEdit
);
8336 ok(ret
, "error: %d\n", (int) GetLastError());