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;
605 static const char text
[] = "aa\n"
606 "this is a long line of text that should be longer than the "
615 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
616 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
617 (sig
.lsUsb
[3] & 0x08000000) != 0);
619 /* Fill the control to lines to ensure that most of them are offscreen */
620 for (i
= 0; i
< 50; i
++)
622 /* Do not modify the string; it is exactly 16 characters long. */
623 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
624 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
628 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
629 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
630 Richedit 3.0 accepts either of the above API conventions.
633 /* Testing Richedit 2.0 API format */
635 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
636 Since all lines are identical and drawn with the same font,
637 they should have the same height... right?
639 for (i
= 0; i
< 50; i
++)
641 /* All the lines are 16 characters long */
642 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
645 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
646 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
647 xpos
= LOWORD(result
);
651 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
652 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
653 height
= HIWORD(result
);
657 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
658 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
662 /* Testing position at end of text */
663 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
664 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
665 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
667 /* Testing position way past end of text */
668 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
669 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
670 expected
= (rtl
? 8 : 1);
671 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
673 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
674 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
675 for (i
= 0; i
< 50; i
++)
677 /* All the lines are 16 characters long */
678 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
679 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
680 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
681 (signed short)(HIWORD(result
)), (i
- 1) * height
);
682 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
685 /* Testing position at end of text */
686 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
687 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
688 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
690 /* Testing position way past end of text */
691 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
692 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
693 expected
= (rtl
? 8 : 1);
694 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
696 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
697 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
698 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
700 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
701 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
702 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
703 xpos
= LOWORD(result
);
705 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
706 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
707 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
708 ok((signed short)(LOWORD(result
)) < xpos
,
709 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
710 (signed short)(LOWORD(result
)), xpos
);
711 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
713 /* Test around end of text that doesn't end in a newline. */
714 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"12345678901234");
715 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
716 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
717 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
719 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
720 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
721 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
722 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
723 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
724 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
725 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
727 /* Try a negative position. */
728 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
729 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
731 /* test negative indentation */
732 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0,
733 (LPARAM
)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}");
734 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, 0);
735 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
737 fmt
.cbSize
= sizeof(fmt
);
738 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
739 ok(fmt
.dxStartIndent
== -400, "got %d\n", fmt
.dxStartIndent
);
740 ok(fmt
.dxOffset
== 200, "got %d\n", fmt
.dxOffset
);
741 ok(fmt
.wAlignment
== PFA_LEFT
, "got %d\n", fmt
.wAlignment
);
743 DestroyWindow(hwndRichEdit
);
746 static void test_EM_SETCHARFORMAT(void)
748 HWND hwndRichEdit
= new_richedit(NULL
);
752 int tested_effects
[] = {
767 DWORD expect_effects
;
769 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
770 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
771 (sig
.lsUsb
[3] & 0x08000000) != 0);
773 /* check charformat defaults */
774 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
775 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
776 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
777 ok(cf2
.dwMask
== CFM_ALL2
, "got %08x\n", cf2
.dwMask
);
778 expect_effects
= CFE_AUTOCOLOR
| CFE_AUTOBACKCOLOR
;
779 if (cf2
.wWeight
> 550) expect_effects
|= CFE_BOLD
;
780 ok(cf2
.dwEffects
== expect_effects
, "got %08x\n", cf2
.dwEffects
);
781 ok(cf2
.yOffset
== 0, "got %d\n", cf2
.yOffset
);
782 ok(cf2
.sSpacing
== 0, "got %d\n", cf2
.sSpacing
);
783 ok(cf2
.lcid
== GetSystemDefaultLCID(), "got %x\n", cf2
.lcid
);
784 ok(cf2
.sStyle
== 0, "got %d\n", cf2
.sStyle
);
785 ok(cf2
.wKerning
== 0, "got %d\n", cf2
.wKerning
);
786 ok(cf2
.bAnimation
== 0, "got %d\n", cf2
.bAnimation
);
787 ok(cf2
.bRevAuthor
== 0, "got %d\n", cf2
.bRevAuthor
);
789 /* Invalid flags, CHARFORMAT2 structure blanked out */
790 memset(&cf2
, 0, sizeof(cf2
));
791 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
792 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
794 /* A valid flag, CHARFORMAT2 structure blanked out */
795 memset(&cf2
, 0, sizeof(cf2
));
796 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
797 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
799 /* A valid flag, CHARFORMAT2 structure blanked out */
800 memset(&cf2
, 0, sizeof(cf2
));
801 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
802 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
804 /* A valid flag, CHARFORMAT2 structure blanked out */
805 memset(&cf2
, 0, sizeof(cf2
));
806 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
807 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
809 /* A valid flag, CHARFORMAT2 structure blanked out */
810 memset(&cf2
, 0, sizeof(cf2
));
811 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
812 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
814 /* Invalid flags, CHARFORMAT2 structure minimally filled */
815 memset(&cf2
, 0, sizeof(cf2
));
816 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
817 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
818 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
819 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
820 ok(rc
== FALSE
, "Should not be able to undo here.\n");
821 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
823 /* A valid flag, CHARFORMAT2 structure minimally filled */
824 memset(&cf2
, 0, sizeof(cf2
));
825 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
826 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
827 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
828 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
829 ok(rc
== FALSE
, "Should not be able to undo here.\n");
830 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
832 /* A valid flag, CHARFORMAT2 structure minimally filled */
833 memset(&cf2
, 0, sizeof(cf2
));
834 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
835 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
836 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
837 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
838 ok(rc
== FALSE
, "Should not be able to undo here.\n");
839 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
841 /* A valid flag, CHARFORMAT2 structure minimally filled */
842 memset(&cf2
, 0, sizeof(cf2
));
843 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
844 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
845 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
846 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
847 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
848 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
850 /* A valid flag, CHARFORMAT2 structure minimally filled */
851 memset(&cf2
, 0, sizeof(cf2
));
852 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
853 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
854 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
855 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
856 ok(rc
== TRUE
, "Should not be able to undo here.\n");
857 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
859 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
860 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
862 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
863 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
864 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
865 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
866 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
868 /* wParam==0 is default char format, does not set modify */
869 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
870 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
871 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
872 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
873 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
876 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
877 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
880 skip("RTL language found\n");
882 /* wParam==SCF_SELECTION sets modify if nonempty selection */
883 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
884 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
885 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
886 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
887 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
888 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
889 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
891 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
892 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
893 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
894 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
895 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
896 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
897 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
898 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
899 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
900 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
901 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
902 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
904 /* wParam==SCF_ALL sets modify regardless of whether text is present */
905 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
906 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
907 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
908 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
909 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
910 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
911 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
913 DestroyWindow(hwndRichEdit
);
915 /* EM_GETCHARFORMAT tests */
916 for (i
= 0; tested_effects
[i
]; i
++)
918 hwndRichEdit
= new_richedit(NULL
);
919 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
921 /* Need to set a TrueType font to get consistent CFM_BOLD results */
922 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
923 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
924 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
926 strcpy(cf2
.szFaceName
, "Courier New");
927 cf2
.wWeight
= FW_DONTCARE
;
928 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
930 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
931 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
932 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 4);
933 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
934 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
935 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
937 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
938 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
939 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
940 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
942 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
943 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
944 cf2
.dwMask
= tested_effects
[i
];
945 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
946 cf2
.dwMask
= CFM_SUPERSCRIPT
;
947 cf2
.dwEffects
= tested_effects
[i
];
948 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
949 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
951 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
952 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
953 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
954 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
955 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
956 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
958 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
959 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
960 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
961 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
963 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
964 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
965 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
966 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
967 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
968 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
970 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
971 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
972 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
973 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
975 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
976 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
977 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
978 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
979 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
980 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
982 (cf2
.dwMask
& tested_effects
[i
]) == 0),
983 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
985 DestroyWindow(hwndRichEdit
);
988 for (i
= 0; tested_effects
[i
]; i
++)
990 hwndRichEdit
= new_richedit(NULL
);
991 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
993 /* Need to set a TrueType font to get consistent CFM_BOLD results */
994 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
995 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
996 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
998 strcpy(cf2
.szFaceName
, "Courier New");
999 cf2
.wWeight
= FW_DONTCARE
;
1000 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1002 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1003 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1004 cf2
.dwMask
= tested_effects
[i
];
1005 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
1006 cf2
.dwMask
= CFM_SUPERSCRIPT
;
1007 cf2
.dwEffects
= tested_effects
[i
];
1008 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
1009 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1011 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1012 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1013 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
1014 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1015 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
1016 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
1018 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
1019 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
1020 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
1021 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
1023 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1024 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1025 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
1026 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1027 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
1028 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
1030 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
1031 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
1032 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
1033 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
1035 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1036 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1037 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
1038 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1039 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
1040 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
1042 (cf2
.dwMask
& tested_effects
[i
]) == 0),
1043 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
1044 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
1045 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
1047 DestroyWindow(hwndRichEdit
);
1050 /* Effects applied on an empty selection should take effect when selection is
1051 replaced with text */
1052 hwndRichEdit
= new_richedit(NULL
);
1053 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1054 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1056 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1057 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1058 cf2
.dwMask
= CFM_BOLD
;
1059 cf2
.dwEffects
= CFE_BOLD
;
1060 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1062 /* Selection is now nonempty */
1063 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1065 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1066 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1067 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1068 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1070 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1071 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1072 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1073 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1076 /* Set two effects on an empty selection */
1077 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1078 /* first clear bold, italic */
1079 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
1080 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1081 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1082 cf2
.dwMask
= CFM_BOLD
| CFM_ITALIC
;
1084 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1086 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1088 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1089 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1090 cf2
.dwMask
= CFM_BOLD
;
1091 cf2
.dwEffects
= CFE_BOLD
;
1092 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1093 cf2
.dwMask
= CFM_ITALIC
;
1094 cf2
.dwEffects
= CFE_ITALIC
;
1095 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1097 /* Selection is now nonempty */
1098 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1100 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1101 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1102 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1103 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1105 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
1106 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
1107 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
1108 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
1110 /* Setting the (empty) selection to exactly the same place as before should
1111 NOT clear the insertion style! */
1112 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1113 /* first clear bold, italic */
1114 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
1115 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1116 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1117 cf2
.dwMask
= CFM_BOLD
| CFM_ITALIC
;
1119 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1121 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1123 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1124 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1125 cf2
.dwMask
= CFM_BOLD
;
1126 cf2
.dwEffects
= CFE_BOLD
;
1127 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1129 /* Empty selection in same place, insert style should NOT be forgotten here. */
1130 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2);
1132 /* Selection is now nonempty */
1133 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1135 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1136 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1137 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1138 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1140 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1141 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1142 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1143 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1145 /* Moving the selection will clear the insertion style */
1146 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1147 /* first clear bold, italic */
1148 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
1149 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1150 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1151 cf2
.dwMask
= CFM_BOLD
| CFM_ITALIC
;
1153 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1155 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1157 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1158 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1159 cf2
.dwMask
= CFM_BOLD
;
1160 cf2
.dwEffects
= CFE_BOLD
;
1161 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1163 /* Move selection and then put it back, insert style should be forgotten here. */
1164 SendMessageA(hwndRichEdit
, EM_SETSEL
, 3, 3);
1165 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1167 /* Selection is now nonempty */
1168 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1170 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1171 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1172 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1173 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1175 ok(((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1176 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1177 ok((cf2
.dwEffects
& CFE_BOLD
) == 0,
1178 "%d, cf2.dwEffects == 0x%08x not expecting effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1180 /* Ditto with EM_EXSETSEL */
1181 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1182 /* first clear bold, italic */
1183 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
1184 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1185 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1186 cf2
.dwMask
= CFM_BOLD
| CFM_ITALIC
;
1188 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1190 cr
.cpMin
= 2; cr
.cpMax
= 2;
1191 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1193 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1194 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1195 cf2
.dwMask
= CFM_BOLD
;
1196 cf2
.dwEffects
= CFE_BOLD
;
1197 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1199 /* Empty selection in same place, insert style should NOT be forgotten here. */
1200 cr
.cpMin
= 2; cr
.cpMax
= 2;
1201 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1203 /* Selection is now nonempty */
1204 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1206 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1207 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1208 cr
.cpMin
= 2; cr
.cpMax
= 6;
1209 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1210 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1212 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1213 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1214 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1215 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1217 /* show that wWeight is at the correct offset in CHARFORMAT2A */
1218 memset(&cf2
, 0, sizeof(cf2
));
1219 cf2
.cbSize
= sizeof(cf2
);
1220 cf2
.dwMask
= CFM_WEIGHT
;
1222 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1223 memset(&cf2
, 0, sizeof(cf2
));
1224 cf2
.cbSize
= sizeof(cf2
);
1225 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1226 ok(cf2
.wWeight
== 100, "got %d\n", cf2
.wWeight
);
1228 memset(&cf2
, 0, sizeof(cf2
));
1229 cf2
.cbSize
= sizeof(cf2
);
1230 cf2
.dwMask
= CFM_SPACING
;
1232 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1233 memset(&cf2
, 0, sizeof(cf2
));
1234 cf2
.cbSize
= sizeof(cf2
);
1235 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1236 ok(cf2
.sSpacing
== 10, "got %d\n", cf2
.sSpacing
);
1238 /* show that wWeight is at the correct offset in CHARFORMAT2W */
1239 memset(&cfW
, 0, sizeof(cfW
));
1240 cfW
.cbSize
= sizeof(cfW
);
1241 cfW
.dwMask
= CFM_WEIGHT
;
1243 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cfW
);
1244 memset(&cfW
, 0, sizeof(cfW
));
1245 cfW
.cbSize
= sizeof(cfW
);
1246 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cfW
);
1247 ok(cfW
.wWeight
== 100, "got %d\n", cfW
.wWeight
);
1249 memset(&cfW
, 0, sizeof(cfW
));
1250 cfW
.cbSize
= sizeof(cfW
);
1251 cfW
.dwMask
= CFM_SPACING
;
1253 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cfW
);
1254 memset(&cfW
, 0, sizeof(cfW
));
1255 cfW
.cbSize
= sizeof(cfW
);
1256 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cfW
);
1257 ok(cfW
.sSpacing
== 10, "got %d\n", cfW
.sSpacing
);
1259 /* test CFE_UNDERLINE and bUnderlineType interaction */
1260 /* clear bold, italic */
1261 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
1262 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1263 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1264 cf2
.dwMask
= CFM_BOLD
| CFM_ITALIC
;
1266 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1268 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */
1269 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1270 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1271 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1272 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1273 "got %08x\n", cf2
.dwMask
);
1274 ok(!(cf2
.dwEffects
& CFE_UNDERLINE
), "got %08x\n", cf2
.dwEffects
);
1275 ok(cf2
.bUnderlineType
== CFU_UNDERLINE
, "got %x\n", cf2
.bUnderlineType
);
1277 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */
1278 cf2
.dwMask
= CFM_UNDERLINETYPE
;
1279 cf2
.bUnderlineType
= CFU_UNDERLINE
;
1280 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1281 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1282 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1283 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1284 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1285 "got %08x\n", cf2
.dwMask
);
1286 ok(cf2
.dwEffects
& CFE_UNDERLINE
, "got %08x\n", cf2
.dwEffects
);
1287 ok(cf2
.bUnderlineType
== CFU_UNDERLINE
, "got %x\n", cf2
.bUnderlineType
);
1289 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */
1290 cf2
.dwMask
= CFM_UNDERLINETYPE
;
1291 cf2
.bUnderlineType
= CFU_UNDERLINENONE
;
1292 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1293 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1294 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1295 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1296 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1297 "got %08x\n", cf2
.dwMask
);
1298 ok(!(cf2
.dwEffects
& CFE_UNDERLINE
), "got %08x\n", cf2
.dwEffects
);
1299 ok(cf2
.bUnderlineType
== CFU_UNDERLINENONE
, "got %x\n", cf2
.bUnderlineType
);
1301 /* another underline type also sets CFE_UNDERLINE */
1302 cf2
.dwMask
= CFM_UNDERLINETYPE
;
1303 cf2
.bUnderlineType
= CFU_UNDERLINEDOUBLE
;
1304 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1305 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1306 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1307 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1308 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1309 "got %08x\n", cf2
.dwMask
);
1310 ok(cf2
.dwEffects
& CFE_UNDERLINE
, "got %08x\n", cf2
.dwEffects
);
1311 ok(cf2
.bUnderlineType
== CFU_UNDERLINEDOUBLE
, "got %x\n", cf2
.bUnderlineType
);
1313 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */
1314 cf2
.dwMask
= CFM_UNDERLINETYPE
| CFM_UNDERLINE
;
1315 cf2
.bUnderlineType
= CFU_UNDERLINEDOUBLE
;
1317 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1318 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1319 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1320 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1321 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1322 "got %08x\n", cf2
.dwMask
);
1323 ok(!(cf2
.dwEffects
& CFE_UNDERLINE
), "got %08x\n", cf2
.dwEffects
);
1324 ok(cf2
.bUnderlineType
== CFU_UNDERLINEDOUBLE
, "got %x\n", cf2
.bUnderlineType
);
1326 /* And turing it back on again by just setting CFE_UNDERLINE */
1327 cf2
.dwMask
= CFM_UNDERLINE
;
1328 cf2
.dwEffects
= CFE_UNDERLINE
;
1329 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1330 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1331 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1332 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1333 ok((cf2
.dwMask
& (CFM_UNDERLINE
| CFM_UNDERLINETYPE
)) == (CFM_UNDERLINE
| CFM_UNDERLINETYPE
),
1334 "got %08x\n", cf2
.dwMask
);
1335 ok(cf2
.dwEffects
& CFE_UNDERLINE
, "got %08x\n", cf2
.dwEffects
);
1336 ok(cf2
.bUnderlineType
== CFU_UNDERLINEDOUBLE
, "got %x\n", cf2
.bUnderlineType
);
1338 DestroyWindow(hwndRichEdit
);
1341 static void test_EM_SETTEXTMODE(void)
1343 HWND hwndRichEdit
= new_richedit(NULL
);
1344 CHARFORMAT2A cf2
, cf2test
;
1348 /*Attempt to use mutually exclusive modes*/
1349 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1350 ok(rc
== E_INVALIDARG
,
1351 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1353 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1354 /*Insert text into the control*/
1356 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1358 /*Attempt to change the control to plain text mode*/
1359 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1360 ok(rc
== E_UNEXPECTED
,
1361 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1363 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1364 If rich text is pasted, it should have the same formatting as the rest
1365 of the text in the control*/
1367 /*Italicize the text
1368 *NOTE: If the default text was already italicized, the test will simply
1369 reverse; in other words, it will copy a regular "wine" into a plain
1370 text window that uses an italicized format*/
1371 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1372 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
1374 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1375 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1377 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1378 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1380 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1381 however, SCF_ALL has been implemented*/
1382 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1383 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1385 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1386 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1388 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1390 /*Select the string "wine"*/
1393 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1395 /*Copy the italicized "wine" to the clipboard*/
1396 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1398 /*Reset the formatting to default*/
1399 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1400 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1401 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1403 /*Clear the text in the control*/
1404 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1406 /*Switch to Plain Text Mode*/
1407 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1408 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1410 /*Input "wine" again in normal format*/
1411 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1413 /*Paste the italicized "wine" into the control*/
1414 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1416 /*Select a character from the first "wine" string*/
1419 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1421 /*Retrieve its formatting*/
1422 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1424 /*Select a character from the second "wine" string*/
1427 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1429 /*Retrieve its formatting*/
1430 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1431 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1433 /*Compare the two formattings*/
1434 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1435 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1436 cf2
.dwEffects
, cf2test
.dwEffects
);
1437 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1438 printing "wine" in the current format(normal)
1439 pasting "wine" from the clipboard(italicized)
1440 comparing the two formats(should differ)*/
1442 /*Attempt to switch with text in control*/
1443 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1444 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1447 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1449 /*Switch into Rich Text mode*/
1450 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1451 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1453 /*Print "wine" in normal formatting into the control*/
1454 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1456 /*Paste italicized "wine" into the control*/
1457 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1459 /*Select text from the first "wine" string*/
1462 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1464 /*Retrieve its formatting*/
1465 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1467 /*Select text from the second "wine" string*/
1470 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1472 /*Retrieve its formatting*/
1473 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1475 /*Test that the two formattings are not the same*/
1476 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1477 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1478 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1480 DestroyWindow(hwndRichEdit
);
1483 static void test_SETPARAFORMAT(void)
1485 HWND hwndRichEdit
= new_richedit(NULL
);
1488 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1489 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1490 fmt
.dwMask
= PFM_ALIGNMENT
;
1491 fmt
.wAlignment
= PFA_LEFT
;
1493 ret
= SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1494 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1496 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1498 ret
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1499 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1500 * between richedit different native builds of riched20.dll
1501 * used on different Windows versions. */
1502 ret
&= ~PFM_TABLEROWDELIMITER
;
1503 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1505 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1506 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1508 /* Test some other paraformat field defaults */
1509 ok( fmt
.wNumbering
== 0, "got %d\n", fmt
.wNumbering
);
1510 ok( fmt
.wNumberingStart
== 0, "got %d\n", fmt
.wNumberingStart
);
1511 ok( fmt
.wNumberingStyle
== 0, "got %04x\n", fmt
.wNumberingStyle
);
1512 ok( fmt
.wNumberingTab
== 0, "got %d\n", fmt
.wNumberingTab
);
1514 DestroyWindow(hwndRichEdit
);
1517 static void test_TM_PLAINTEXT(void)
1519 /*Tests plain text properties*/
1521 HWND hwndRichEdit
= new_richedit(NULL
);
1522 CHARFORMAT2A cf2
, cf2test
;
1526 /*Switch to plain text mode*/
1528 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1529 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1531 /*Fill control with text*/
1533 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Is Wine an emulator? No it's not");
1535 /*Select some text and bold it*/
1539 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1540 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1541 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1543 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1544 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1546 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1547 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1549 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1550 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1552 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1553 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1555 /*Get the formatting of those characters*/
1557 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1559 /*Get the formatting of some other characters*/
1560 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1563 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1564 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1566 /*Test that they are the same as plain text allows only one formatting*/
1568 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1569 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1570 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1572 /*Fill the control with a "wine" string, which when inserted will be bold*/
1574 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1576 /*Copy the bolded "wine" string*/
1580 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1581 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1583 /*Swap back to rich text*/
1585 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1586 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1588 /*Set the default formatting to bold italics*/
1590 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1591 cf2
.dwMask
|= CFM_ITALIC
;
1592 cf2
.dwEffects
^= CFE_ITALIC
;
1593 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1594 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1596 /*Set the text in the control to "wine", which will be bold and italicized*/
1598 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1600 /*Paste the plain text "wine" string, which should take the insert
1601 formatting, which at the moment is bold italics*/
1603 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1605 /*Select the first "wine" string and retrieve its formatting*/
1609 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1610 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1612 /*Select the second "wine" string and retrieve its formatting*/
1616 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1617 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1619 /*Compare the two formattings. They should be the same.*/
1621 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1622 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1623 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1624 DestroyWindow(hwndRichEdit
);
1627 static void test_WM_GETTEXT(void)
1629 HWND hwndRichEdit
= new_richedit(NULL
);
1630 static const char text
[] = "Hello. My name is RichEdit!";
1631 static const char text2
[] = "Hello. My name is RichEdit!\r";
1632 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1633 char buffer
[1024] = {0};
1636 /* Baseline test with normal-sized buffer */
1637 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1638 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1639 ok(result
== lstrlenA(buffer
),
1640 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1641 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1642 result
= strcmp(buffer
,text
);
1644 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1646 /* Test for returned value of WM_GETTEXTLENGTH */
1647 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1648 ok(result
== lstrlenA(text
),
1649 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1650 result
, lstrlenA(text
));
1652 /* Test for behavior in overflow case */
1653 memset(buffer
, 0, 1024);
1654 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1656 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1657 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1658 result
= strcmp(buffer
,text
);
1660 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1662 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1664 /* Baseline test with normal-sized buffer and carriage return */
1665 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1666 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1667 ok(result
== lstrlenA(buffer
),
1668 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1669 result
= strcmp(buffer
,text2_after
);
1671 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1673 /* Test for returned value of WM_GETTEXTLENGTH */
1674 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1675 ok(result
== lstrlenA(text2_after
),
1676 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1677 result
, lstrlenA(text2_after
));
1679 /* Test for behavior of CRLF conversion in case of overflow */
1680 memset(buffer
, 0, 1024);
1681 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1683 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1684 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1685 result
= strcmp(buffer
,text2
);
1687 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1689 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1691 DestroyWindow(hwndRichEdit
);
1694 static void test_EM_GETTEXTRANGE(void)
1696 HWND hwndRichEdit
= new_richedit(NULL
);
1697 const char * text1
= "foo bar\r\nfoo bar";
1698 const char * text2
= "foo bar\rfoo bar";
1699 const char * expect
= "bar\rfoo";
1700 char buffer
[1024] = {0};
1702 TEXTRANGEA textRange
;
1704 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1706 textRange
.lpstrText
= buffer
;
1707 textRange
.chrg
.cpMin
= 4;
1708 textRange
.chrg
.cpMax
= 11;
1709 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1710 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1711 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1713 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1715 textRange
.lpstrText
= buffer
;
1716 textRange
.chrg
.cpMin
= 4;
1717 textRange
.chrg
.cpMax
= 11;
1718 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1719 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1720 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1722 /* cpMax of text length is used instead of -1 in this case */
1723 textRange
.lpstrText
= buffer
;
1724 textRange
.chrg
.cpMin
= 0;
1725 textRange
.chrg
.cpMax
= -1;
1726 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1727 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1728 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1730 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1731 textRange
.lpstrText
= buffer
;
1732 textRange
.chrg
.cpMin
= -1;
1733 textRange
.chrg
.cpMax
= 1;
1734 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1735 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1736 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1738 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1739 textRange
.lpstrText
= buffer
;
1740 textRange
.chrg
.cpMin
= 1;
1741 textRange
.chrg
.cpMax
= -1;
1742 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1743 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1744 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1746 /* no end character is copied if cpMax - cpMin < 0 */
1747 textRange
.lpstrText
= buffer
;
1748 textRange
.chrg
.cpMin
= 5;
1749 textRange
.chrg
.cpMax
= 5;
1750 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1751 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1752 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1754 /* cpMax of text length is used if cpMax > text length*/
1755 textRange
.lpstrText
= buffer
;
1756 textRange
.chrg
.cpMin
= 0;
1757 textRange
.chrg
.cpMax
= 1000;
1758 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1759 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1760 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1762 /* Test with multibyte character */
1763 if (!is_lang_japanese
)
1764 skip("Skip multibyte character tests on non-Japanese platform\n");
1767 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1768 textRange
.chrg
.cpMin
= 4;
1769 textRange
.chrg
.cpMax
= 8;
1770 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1771 todo_wine
ok(result
== 5, "EM_GETTEXTRANGE returned %ld\n", result
);
1772 todo_wine
ok(!strcmp("ef\x8e\xf0g", buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1775 DestroyWindow(hwndRichEdit
);
1778 static void test_EM_GETSELTEXT(void)
1780 HWND hwndRichEdit
= new_richedit(NULL
);
1781 const char * text1
= "foo bar\r\nfoo bar";
1782 const char * text2
= "foo bar\rfoo bar";
1783 const char * expect
= "bar\rfoo";
1784 char buffer
[1024] = {0};
1787 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1789 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1790 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1791 ok(result
== 7, "EM_GETSELTEXT returned %ld\n", result
);
1792 ok(!strcmp(expect
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1794 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1796 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1797 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1798 ok(result
== 7, "EM_GETSELTEXT returned %ld\n", result
);
1799 ok(!strcmp(expect
, buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1801 /* Test with multibyte character */
1802 if (!is_lang_japanese
)
1803 skip("Skip multibyte character tests on non-Japanese platform\n");
1806 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
1807 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
1808 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1809 todo_wine
ok(result
== 5, "EM_GETSELTEXT returned %ld\n", result
);
1810 todo_wine
ok(!strcmp("ef\x8e\xf0g", buffer
), "EM_GETSELTEXT filled %s\n", buffer
);
1813 DestroyWindow(hwndRichEdit
);
1816 /* FIXME: need to test unimplemented options and robustly test wparam */
1817 static void test_EM_SETOPTIONS(void)
1820 static const char text
[] = "Hello. My name is RichEdit!";
1821 char buffer
[1024] = {0};
1822 DWORD dwStyle
, options
, oldOptions
;
1823 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1824 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1825 ES_SELECTIONBAR
|ES_VERTICAL
;
1827 /* Test initial options. */
1828 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, WS_POPUP
,
1829 0, 0, 200, 60, NULL
, NULL
,
1830 hmoduleRichEdit
, NULL
);
1831 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1832 RICHEDIT_CLASS20A
, (int) GetLastError());
1833 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1834 ok(options
== 0, "Incorrect initial options %x\n", options
);
1835 DestroyWindow(hwndRichEdit
);
1837 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
1838 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1839 0, 0, 200, 60, NULL
, NULL
,
1840 hmoduleRichEdit
, NULL
);
1841 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1842 RICHEDIT_CLASS20A
, (int) GetLastError());
1843 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1844 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1845 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1846 "Incorrect initial options %x\n", options
);
1848 /* NEGATIVE TESTING - NO OPTIONS SET */
1849 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1850 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1852 /* testing no readonly by sending 'a' to the control*/
1853 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1854 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1856 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1857 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1859 /* READONLY - sending 'a' to the control */
1860 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1861 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1862 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1863 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1864 ok(buffer
[0]==text
[0],
1865 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1867 /* EM_SETOPTIONS changes the window style, but changing the
1868 * window style does not change the options. */
1869 dwStyle
= GetWindowLongA(hwndRichEdit
, GWL_STYLE
);
1870 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1871 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1872 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1873 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1874 /* Confirm that the text is still read only. */
1875 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1876 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1877 ok(buffer
[0]==text
[0],
1878 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1880 oldOptions
= options
;
1881 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1882 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1883 ok(options
== oldOptions
,
1884 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1886 DestroyWindow(hwndRichEdit
);
1889 static BOOL
check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1891 CHARFORMAT2A text_format
;
1892 text_format
.cbSize
= sizeof(text_format
);
1893 SendMessageA(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1894 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&text_format
);
1895 return (text_format
.dwEffects
& CFE_LINK
) != 0;
1898 static void check_CFE_LINK_rcvd(HWND hwnd
, BOOL is_url
, const char * url
)
1900 BOOL link_present
= FALSE
;
1902 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1904 { /* control text is url; should get CFE_LINK */
1905 ok(link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1909 ok(!link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1913 static HWND
new_static_wnd(HWND parent
) {
1914 return new_window("Static", 0, parent
);
1917 static void test_EM_AUTOURLDETECT(void)
1919 /* DO NOT change the properties of the first two elements. To shorten the
1920 tests, all tests after WM_SETTEXT test just the first two elements -
1921 one non-URL and one URL */
1926 {"winehq.org", FALSE
},
1927 {"http://www.winehq.org", TRUE
},
1928 {"http//winehq.org", FALSE
},
1929 {"ww.winehq.org", FALSE
},
1930 {"www.winehq.org", TRUE
},
1931 {"ftp://192.168.1.1", TRUE
},
1932 {"ftp//192.168.1.1", FALSE
},
1933 {"mailto:your@email.com", TRUE
},
1934 {"prospero:prosperoserver", TRUE
},
1935 {"telnet:test", TRUE
},
1936 {"news:newserver", TRUE
},
1937 {"wais:waisserver", TRUE
}
1942 HWND hwndRichEdit
, parent
;
1944 /* All of the following should cause the URL to be detected */
1945 const char * templates_delim
[] = {
1946 "This is some text with X on it",
1947 "This is some text with (X) on it",
1948 "This is some text with X\r on it",
1949 "This is some text with ---X--- on it",
1950 "This is some text with \"X\" on it",
1951 "This is some text with 'X' on it",
1952 "This is some text with 'X' on it",
1953 "This is some text with :X: on it",
1955 "This text ends with X",
1957 "This is some text with X) on it",
1958 "This is some text with X--- on it",
1959 "This is some text with X\" on it",
1960 "This is some text with X' on it",
1961 "This is some text with X: on it",
1963 "This is some text with (X on it",
1964 "This is some text with \rX on it",
1965 "This is some text with ---X on it",
1966 "This is some text with \"X on it",
1967 "This is some text with 'X on it",
1968 "This is some text with :X on it",
1970 /* None of these should cause the URL to be detected */
1971 const char * templates_non_delim
[] = {
1972 "This is some text with |X| on it",
1973 "This is some text with *X* on it",
1974 "This is some text with /X/ on it",
1975 "This is some text with +X+ on it",
1976 "This is some text with %X% on it",
1977 "This is some text with #X# on it",
1978 "This is some text with @X@ on it",
1979 "This is some text with \\X\\ on it",
1980 "This is some text with |X on it",
1981 "This is some text with *X on it",
1982 "This is some text with /X on it",
1983 "This is some text with +X on it",
1984 "This is some text with %X on it",
1985 "This is some text with #X on it",
1986 "This is some text with @X on it",
1987 "This is some text with \\X on it",
1988 "This is some text with _X on it",
1990 /* All of these cause the URL detection to be extended by one more byte,
1991 thus demonstrating that the tested character is considered as part
1993 const char * templates_xten_delim
[] = {
1994 "This is some text with X| on it",
1995 "This is some text with X* on it",
1996 "This is some text with X/ on it",
1997 "This is some text with X+ on it",
1998 "This is some text with X% on it",
1999 "This is some text with X# on it",
2000 "This is some text with X@ on it",
2001 "This is some text with X\\ on it",
2002 "This is some text with X_ on it",
2004 /* These delims act as neutral breaks. Whether the url is ended
2005 or not depends on the next non-neutral character. We'll test
2006 with Y unchanged, in which case the url should include the
2007 deliminator and the Y. We'll also test with the Y changed
2008 to a space, in which case the url stops before the
2010 const char * templates_neutral_delim
[] = {
2011 "This is some text with X-Y on it",
2012 "This is some text with X--Y on it",
2013 "This is some text with X!Y on it",
2014 "This is some text with X[Y on it",
2015 "This is some text with X]Y on it",
2016 "This is some text with X{Y on it",
2017 "This is some text with X}Y on it",
2018 "This is some text with X(Y on it",
2019 "This is some text with X)Y on it",
2020 "This is some text with X\"Y on it",
2021 "This is some text with X;Y on it",
2022 "This is some text with X:Y on it",
2023 "This is some text with X'Y on it",
2024 "This is some text with X?Y on it",
2025 "This is some text with X<Y on it",
2026 "This is some text with X>Y on it",
2027 "This is some text with X.Y on it",
2028 "This is some text with X,Y on it",
2032 parent
= new_static_wnd(NULL
);
2033 hwndRichEdit
= new_richedit(parent
);
2034 /* Try and pass EM_AUTOURLDETECT some test wParam values */
2035 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
2036 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
2037 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
2038 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
2039 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
2040 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
2041 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
2042 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
2043 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
2044 /* for each url, check the text to see if CFE_LINK effect is present */
2045 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
2047 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
2048 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
2049 check_CFE_LINK_rcvd(hwndRichEdit
, FALSE
, urls
[i
].text
);
2051 /* Link detection should happen immediately upon WM_SETTEXT */
2052 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2053 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
2054 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
2056 DestroyWindow(hwndRichEdit
);
2058 /* Test detection of URLs within normal text - WM_SETTEXT case. */
2059 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
2060 hwndRichEdit
= new_richedit(parent
);
2062 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2067 at_pos
= strchr(templates_delim
[j
], 'X');
2068 at_offset
= at_pos
- templates_delim
[j
];
2069 memcpy(buffer
, templates_delim
[j
], at_offset
);
2070 buffer
[at_offset
] = '\0';
2071 strcat(buffer
, urls
[i
].text
);
2072 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2073 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2075 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2076 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
2078 /* This assumes no templates start with the URL itself, and that they
2079 have at least two characters before the URL text */
2080 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2081 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2082 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2083 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2084 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2085 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2089 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2090 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2091 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2092 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2096 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2097 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2098 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2099 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2101 if (buffer
[end_offset
] != '\0')
2103 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2104 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2105 if (buffer
[end_offset
+1] != '\0')
2107 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2108 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2113 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
2118 at_pos
= strchr(templates_non_delim
[j
], 'X');
2119 at_offset
= at_pos
- templates_non_delim
[j
];
2120 memcpy(buffer
, templates_non_delim
[j
], at_offset
);
2121 buffer
[at_offset
] = '\0';
2122 strcat(buffer
, urls
[i
].text
);
2123 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
2124 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2126 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2127 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
2129 /* This assumes no templates start with the URL itself, and that they
2130 have at least two characters before the URL text */
2131 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2132 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2133 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2134 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2135 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2136 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2138 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2139 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2140 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2141 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2142 if (buffer
[end_offset
] != '\0')
2144 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2145 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2146 if (buffer
[end_offset
+1] != '\0')
2148 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2149 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2154 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
2159 at_pos
= strchr(templates_xten_delim
[j
], 'X');
2160 at_offset
= at_pos
- templates_xten_delim
[j
];
2161 memcpy(buffer
, templates_xten_delim
[j
], at_offset
);
2162 buffer
[at_offset
] = '\0';
2163 strcat(buffer
, urls
[i
].text
);
2164 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
2165 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2167 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2168 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
2170 /* This assumes no templates start with the URL itself, and that they
2171 have at least two characters before the URL text */
2172 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2173 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2174 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2175 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2176 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2177 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2181 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2182 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2183 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2184 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2185 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2186 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2190 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2191 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2192 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2193 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2194 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2195 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2197 if (buffer
[end_offset
+1] != '\0')
2199 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2200 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
2201 if (buffer
[end_offset
+2] != '\0')
2203 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2204 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2209 for (j
= 0; j
< sizeof(templates_neutral_delim
) / sizeof(const char *); j
++) {
2210 char * at_pos
, * end_pos
;
2214 if (!urls
[i
].is_url
) continue;
2216 at_pos
= strchr(templates_neutral_delim
[j
], 'X');
2217 at_offset
= at_pos
- templates_neutral_delim
[j
];
2218 memcpy(buffer
, templates_neutral_delim
[j
], at_offset
);
2219 buffer
[at_offset
] = '\0';
2220 strcat(buffer
, urls
[i
].text
);
2221 strcat(buffer
, templates_neutral_delim
[j
] + at_offset
+ 1);
2223 end_pos
= strchr(buffer
, 'Y');
2224 end_offset
= end_pos
- buffer
;
2226 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2227 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
2229 /* This assumes no templates start with the URL itself, and that they
2230 have at least two characters before the URL text */
2231 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2232 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2233 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2234 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2235 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2236 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2238 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2239 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2240 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2241 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2242 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2243 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2247 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2248 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
2250 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2251 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2252 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2253 "CFE_LINK set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2254 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2255 "CFE_LINK set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2258 DestroyWindow(hwndRichEdit
);
2259 hwndRichEdit
= NULL
;
2262 /* Test detection of URLs within normal text - WM_CHAR case. */
2263 /* Test only the first two URL examples for brevity */
2264 for (i
= 0; i
< 2; i
++) {
2265 hwndRichEdit
= new_richedit(parent
);
2267 /* Also for brevity, test only the first three delimiters */
2268 for (j
= 0; j
< 3; j
++) {
2274 at_pos
= strchr(templates_delim
[j
], 'X');
2275 at_offset
= at_pos
- templates_delim
[j
];
2276 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2278 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2279 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2280 for (u
= 0; templates_delim
[j
][u
]; u
++) {
2281 if (templates_delim
[j
][u
] == '\r') {
2282 simulate_typing_characters(hwndRichEdit
, "\r");
2283 } else if (templates_delim
[j
][u
] != 'X') {
2284 SendMessageA(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
2286 for (v
= 0; urls
[i
].text
[v
]; v
++) {
2287 SendMessageA(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
2291 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2293 /* This assumes no templates start with the URL itself, and that they
2294 have at least two characters before the URL text */
2295 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2296 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2297 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2298 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2299 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2300 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2304 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2305 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2306 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2307 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2311 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2312 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2313 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2314 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2316 if (buffer
[end_offset
] != '\0')
2318 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2319 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2320 if (buffer
[end_offset
+1] != '\0')
2322 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2323 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2327 /* The following will insert a paragraph break after the first character
2328 of the URL candidate, thus breaking the URL. It is expected that the
2329 CFE_LINK attribute should break across both pieces of the URL */
2330 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
2331 simulate_typing_characters(hwndRichEdit
, "\r");
2332 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2334 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2335 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2336 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2337 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2338 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2339 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2341 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2342 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2343 /* end_offset moved because of paragraph break */
2344 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2345 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2346 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
2347 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
2349 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2350 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2351 if (buffer
[end_offset
+2] != '\0')
2353 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2354 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2358 /* The following will remove the just-inserted paragraph break, thus
2359 restoring the URL */
2360 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
2361 simulate_typing_characters(hwndRichEdit
, "\b");
2362 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2364 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2365 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2366 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2367 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2368 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2369 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2373 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2374 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2375 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2376 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2380 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2381 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2382 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2383 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2385 if (buffer
[end_offset
] != '\0')
2387 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2388 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2389 if (buffer
[end_offset
+1] != '\0')
2391 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2392 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2396 DestroyWindow(hwndRichEdit
);
2397 hwndRichEdit
= NULL
;
2400 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2401 /* Test just the first two URL examples for brevity */
2402 for (i
= 0; i
< 2; i
++) {
2405 hwndRichEdit
= new_richedit(parent
);
2407 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2409 1) Set entire text, a la WM_SETTEXT
2410 2) Set a selection of the text to the URL
2411 3) Set a portion of the text at a time, which eventually results in
2413 All of them should give equivalent results
2416 /* Set entire text in one go, like WM_SETTEXT */
2417 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2422 st
.codepage
= CP_ACP
;
2423 st
.flags
= ST_DEFAULT
;
2425 at_pos
= strchr(templates_delim
[j
], 'X');
2426 at_offset
= at_pos
- templates_delim
[j
];
2427 memcpy(buffer
, templates_delim
[j
], at_offset
);
2428 buffer
[at_offset
] = '\0';
2429 strcat(buffer
, urls
[i
].text
);
2430 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2431 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2433 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2434 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2436 /* This assumes no templates start with the URL itself, and that they
2437 have at least two characters before the URL text */
2438 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2439 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2440 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2441 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2442 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2443 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2447 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2448 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2449 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2450 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2454 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2455 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2456 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2457 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2459 if (buffer
[end_offset
] != '\0')
2461 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2462 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2463 if (buffer
[end_offset
+1] != '\0')
2465 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2466 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2471 /* Set selection with X to the URL */
2472 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2477 at_pos
= strchr(templates_delim
[j
], 'X');
2478 at_offset
= at_pos
- templates_delim
[j
];
2479 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2481 st
.codepage
= CP_ACP
;
2482 st
.flags
= ST_DEFAULT
;
2483 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2484 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2485 st
.flags
= ST_SELECTION
;
2486 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2487 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)urls
[i
].text
);
2488 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2490 /* This assumes no templates start with the URL itself, and that they
2491 have at least two characters before the URL text */
2492 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2493 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2494 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2495 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2496 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2497 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2501 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2502 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2503 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2504 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2508 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2509 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2510 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2511 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2513 if (buffer
[end_offset
] != '\0')
2515 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2516 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2517 if (buffer
[end_offset
+1] != '\0')
2519 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2520 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2525 /* Set selection with X to the first character of the URL, then the rest */
2526 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2531 at_pos
= strchr(templates_delim
[j
], 'X');
2532 at_offset
= at_pos
- templates_delim
[j
];
2533 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2535 strcpy(buffer
, "YY");
2536 buffer
[0] = urls
[i
].text
[0];
2538 st
.codepage
= CP_ACP
;
2539 st
.flags
= ST_DEFAULT
;
2540 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2541 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2542 st
.flags
= ST_SELECTION
;
2543 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2544 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2545 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2546 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2547 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2549 /* This assumes no templates start with the URL itself, and that they
2550 have at least two characters before the URL text */
2551 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2552 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2553 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2554 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2555 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2556 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2560 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2561 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2562 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2563 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2567 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2568 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2569 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2570 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2572 if (buffer
[end_offset
] != '\0')
2574 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2575 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2576 if (buffer
[end_offset
+1] != '\0')
2578 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2579 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2584 DestroyWindow(hwndRichEdit
);
2585 hwndRichEdit
= NULL
;
2588 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2589 /* Test just the first two URL examples for brevity */
2590 for (i
= 0; i
< 2; i
++) {
2591 hwndRichEdit
= new_richedit(parent
);
2593 /* Set selection with X to the URL */
2594 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2599 at_pos
= strchr(templates_delim
[j
], 'X');
2600 at_offset
= at_pos
- templates_delim
[j
];
2601 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2603 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2604 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2605 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2606 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urls
[i
].text
);
2607 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2609 /* This assumes no templates start with the URL itself, and that they
2610 have at least two characters before the URL text */
2611 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2612 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2613 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2614 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2615 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2616 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2620 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2621 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2622 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2623 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2627 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2628 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2629 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2630 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2632 if (buffer
[end_offset
] != '\0')
2634 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2635 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2636 if (buffer
[end_offset
+1] != '\0')
2638 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2639 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2644 /* Set selection with X to the first character of the URL, then the rest */
2645 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2650 at_pos
= strchr(templates_delim
[j
], 'X');
2651 at_offset
= at_pos
- templates_delim
[j
];
2652 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2654 strcpy(buffer
, "YY");
2655 buffer
[0] = urls
[i
].text
[0];
2657 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2658 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2659 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2660 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)buffer
);
2661 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2662 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2663 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2665 /* This assumes no templates start with the URL itself, and that they
2666 have at least two characters before the URL text */
2667 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2668 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2669 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2670 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2671 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2672 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2676 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2677 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2678 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2679 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2683 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2684 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2685 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2686 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2688 if (buffer
[end_offset
] != '\0')
2690 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2691 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2692 if (buffer
[end_offset
+1] != '\0')
2694 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2695 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2700 DestroyWindow(hwndRichEdit
);
2701 hwndRichEdit
= NULL
;
2704 DestroyWindow(parent
);
2707 static void test_EM_SCROLL(void)
2710 int r
; /* return value */
2711 int expr
; /* expected return value */
2712 HWND hwndRichEdit
= new_richedit(NULL
);
2713 int y_before
, y_after
; /* units of lines of text */
2715 /* test a richedit box containing a single line of text */
2716 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");/* one line of text */
2718 for (i
= 0; i
< 4; i
++) {
2719 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2721 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2722 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2723 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2724 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2725 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2726 "(i == %d)\n", y_after
, i
);
2730 * test a richedit box that will scroll. There are two general
2731 * cases: the case without any long lines and the case with a long
2734 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2736 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\nb\nc\nd\ne");
2738 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2739 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2740 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2741 "LONG LINE \nb\nc\nd\ne");
2742 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2743 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2745 /* get first visible line */
2746 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2747 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2749 /* get new current first visible line */
2750 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2752 ok(((r
& 0xffffff00) == 0x00010000) &&
2753 ((r
& 0x000000ff) != 0x00000000),
2754 "EM_SCROLL page down didn't scroll by a small positive number of "
2755 "lines (r == 0x%08x)\n", r
);
2756 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2757 "(line %d scrolled to line %d\n", y_before
, y_after
);
2761 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2762 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2763 ok(((r
& 0xffffff00) == 0x0001ff00),
2764 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2765 "(r == 0x%08x)\n", r
);
2766 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2767 "%d scrolled to line %d\n", y_before
, y_after
);
2771 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2773 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2775 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2776 "(r == 0x%08x)\n", r
);
2777 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2778 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2782 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2784 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2786 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2787 "(r == 0x%08x)\n", r
);
2788 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2789 "line (%d scrolled to %d)\n", y_before
, y_after
);
2793 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2794 SB_LINEUP
, 0); /* lineup beyond top */
2796 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2799 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2800 ok(y_before
== y_after
,
2801 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2805 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2806 SB_PAGEUP
, 0);/*page up beyond top */
2808 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2811 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2812 ok(y_before
== y_after
,
2813 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2815 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2816 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2817 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2818 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2819 SB_PAGEDOWN
, 0); /* page down beyond bot */
2820 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2823 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2824 ok(y_before
== y_after
,
2825 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2828 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2829 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2830 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2833 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2834 ok(y_before
== y_after
,
2835 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2838 DestroyWindow(hwndRichEdit
);
2841 static unsigned int recursionLevel
= 0;
2842 static unsigned int WM_SIZE_recursionLevel
= 0;
2843 static BOOL bailedOutOfRecursion
= FALSE
;
2844 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2846 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2850 if (bailedOutOfRecursion
) return 0;
2851 if (recursionLevel
>= 32) {
2852 bailedOutOfRecursion
= TRUE
;
2859 WM_SIZE_recursionLevel
++;
2860 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2861 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2862 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2863 WM_SIZE_recursionLevel
--;
2866 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2873 static void test_scrollbar_visibility(void)
2876 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2881 /* These tests show that richedit should temporarily refrain from automatically
2882 hiding or showing its scrollbars (vertical at least) when an explicit request
2883 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2884 Some applications depend on forced showing (when otherwise richedit would
2885 hide the vertical scrollbar) and are thrown on an endless recursive loop
2886 if richedit auto-hides the scrollbar again. Apparently they never heard of
2887 the ES_DISABLENOSCROLL style... */
2889 hwndRichEdit
= new_richedit(NULL
);
2891 /* Test default scrollbar visibility behavior */
2892 memset(&si
, 0, sizeof(si
));
2893 si
.cbSize
= sizeof(si
);
2894 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2895 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2896 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2897 "Vertical scrollbar is visible, should be invisible.\n");
2898 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2899 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2900 si
.nPage
, si
.nMin
, si
.nMax
);
2902 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2903 memset(&si
, 0, sizeof(si
));
2904 si
.cbSize
= sizeof(si
);
2905 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2906 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2907 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2908 "Vertical scrollbar is visible, should be invisible.\n");
2909 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2910 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2911 si
.nPage
, si
.nMin
, si
.nMax
);
2913 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2914 memset(&si
, 0, sizeof(si
));
2915 si
.cbSize
= sizeof(si
);
2916 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2917 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2918 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2919 "Vertical scrollbar is invisible, should be visible.\n");
2920 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2921 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2922 si
.nPage
, si
.nMin
, si
.nMax
);
2924 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2925 even though it hides the scrollbar */
2926 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2927 memset(&si
, 0, sizeof(si
));
2928 si
.cbSize
= sizeof(si
);
2929 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2930 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2931 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2932 "Vertical scrollbar is visible, should be invisible.\n");
2933 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2934 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2935 si
.nPage
, si
.nMin
, si
.nMax
);
2937 /* Setting non-scrolling text again does *not* reset scrollbar range */
2938 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2939 memset(&si
, 0, sizeof(si
));
2940 si
.cbSize
= sizeof(si
);
2941 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2942 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2943 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2944 "Vertical scrollbar is visible, should be invisible.\n");
2945 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2946 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2947 si
.nPage
, si
.nMin
, si
.nMax
);
2949 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2950 memset(&si
, 0, sizeof(si
));
2951 si
.cbSize
= sizeof(si
);
2952 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2953 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2954 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2955 "Vertical scrollbar is visible, should be invisible.\n");
2956 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2957 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2958 si
.nPage
, si
.nMin
, si
.nMax
);
2960 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2961 memset(&si
, 0, sizeof(si
));
2962 si
.cbSize
= sizeof(si
);
2963 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2964 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2965 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2966 "Vertical scrollbar is visible, should be invisible.\n");
2967 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2968 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2969 si
.nPage
, si
.nMin
, si
.nMax
);
2971 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2972 memset(&si
, 0, sizeof(si
));
2973 si
.cbSize
= sizeof(si
);
2974 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2975 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2976 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2977 "Vertical scrollbar is visible, should be invisible.\n");
2978 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2979 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2980 si
.nPage
, si
.nMin
, si
.nMax
);
2982 DestroyWindow(hwndRichEdit
);
2984 /* Test again, with ES_DISABLENOSCROLL style */
2985 hwndRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2987 /* Test default scrollbar visibility behavior */
2988 memset(&si
, 0, sizeof(si
));
2989 si
.cbSize
= sizeof(si
);
2990 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2991 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2992 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2993 "Vertical scrollbar is invisible, should be visible.\n");
2994 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2995 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2996 si
.nPage
, si
.nMin
, si
.nMax
);
2998 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2999 memset(&si
, 0, sizeof(si
));
3000 si
.cbSize
= sizeof(si
);
3001 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3002 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3003 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3004 "Vertical scrollbar is invisible, should be visible.\n");
3005 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
3006 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3007 si
.nPage
, si
.nMin
, si
.nMax
);
3009 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3010 memset(&si
, 0, sizeof(si
));
3011 si
.cbSize
= sizeof(si
);
3012 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3013 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3014 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3015 "Vertical scrollbar is invisible, should be visible.\n");
3016 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3017 "reported page/range is %d (%d..%d)\n",
3018 si
.nPage
, si
.nMin
, si
.nMax
);
3020 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
3021 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3022 memset(&si
, 0, sizeof(si
));
3023 si
.cbSize
= sizeof(si
);
3024 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3025 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3026 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3027 "Vertical scrollbar is invisible, should be visible.\n");
3028 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3029 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3030 si
.nPage
, si
.nMin
, si
.nMax
);
3032 /* Setting non-scrolling text again does *not* reset scrollbar range */
3033 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3034 memset(&si
, 0, sizeof(si
));
3035 si
.cbSize
= sizeof(si
);
3036 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3037 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3038 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3039 "Vertical scrollbar is invisible, should be visible.\n");
3040 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3041 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3042 si
.nPage
, si
.nMin
, si
.nMax
);
3044 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3045 memset(&si
, 0, sizeof(si
));
3046 si
.cbSize
= sizeof(si
);
3047 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3048 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3049 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3050 "Vertical scrollbar is invisible, should be visible.\n");
3051 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3052 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3053 si
.nPage
, si
.nMin
, si
.nMax
);
3055 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3056 memset(&si
, 0, sizeof(si
));
3057 si
.cbSize
= sizeof(si
);
3058 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3059 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3060 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3061 "Vertical scrollbar is invisible, should be visible.\n");
3062 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3063 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3064 si
.nPage
, si
.nMin
, si
.nMax
);
3066 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
3067 memset(&si
, 0, sizeof(si
));
3068 si
.cbSize
= sizeof(si
);
3069 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3070 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3071 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3072 "Vertical scrollbar is invisible, should be visible.\n");
3073 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
3074 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3075 si
.nPage
, si
.nMin
, si
.nMax
);
3077 DestroyWindow(hwndRichEdit
);
3079 /* Test behavior with explicit visibility request, using ShowScrollBar() */
3080 hwndRichEdit
= new_richedit(NULL
);
3082 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3083 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
3084 memset(&si
, 0, sizeof(si
));
3085 si
.cbSize
= sizeof(si
);
3086 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3087 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3088 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3089 "Vertical scrollbar is invisible, should be visible.\n");
3091 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
3092 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3093 si
.nPage
, si
.nMin
, si
.nMax
);
3096 /* Ditto, see above */
3097 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
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 invisible, should be visible.\n");
3105 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
3106 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3107 si
.nPage
, si
.nMin
, si
.nMax
);
3110 /* Ditto, see above */
3111 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3112 memset(&si
, 0, sizeof(si
));
3113 si
.cbSize
= sizeof(si
);
3114 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3115 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3116 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3117 "Vertical scrollbar is invisible, should be visible.\n");
3119 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
3120 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3121 si
.nPage
, si
.nMin
, si
.nMax
);
3124 /* Ditto, see above */
3125 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
3126 memset(&si
, 0, sizeof(si
));
3127 si
.cbSize
= sizeof(si
);
3128 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3129 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3130 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3131 "Vertical scrollbar is invisible, should be visible.\n");
3133 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
3134 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3135 si
.nPage
, si
.nMin
, si
.nMax
);
3138 /* Ditto, see above */
3139 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3140 memset(&si
, 0, sizeof(si
));
3141 si
.cbSize
= sizeof(si
);
3142 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3143 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3144 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3145 "Vertical scrollbar is invisible, should be visible.\n");
3147 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
3148 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3149 si
.nPage
, si
.nMin
, si
.nMax
);
3152 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3153 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
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) expected nMax/nPage nonzero\n",
3162 si
.nPage
, si
.nMin
, si
.nMax
);
3164 DestroyWindow(hwndRichEdit
);
3166 hwndRichEdit
= new_richedit(NULL
);
3168 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
3169 memset(&si
, 0, sizeof(si
));
3170 si
.cbSize
= sizeof(si
);
3171 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3172 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3173 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3174 "Vertical scrollbar is visible, should be invisible.\n");
3175 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3176 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3177 si
.nPage
, si
.nMin
, si
.nMax
);
3179 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3180 memset(&si
, 0, sizeof(si
));
3181 si
.cbSize
= sizeof(si
);
3182 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3183 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3184 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3185 "Vertical scrollbar is visible, should be invisible.\n");
3186 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3187 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3188 si
.nPage
, si
.nMin
, si
.nMax
);
3190 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3191 memset(&si
, 0, sizeof(si
));
3192 si
.cbSize
= sizeof(si
);
3193 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3194 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3195 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3196 "Vertical scrollbar is visible, should be invisible.\n");
3197 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3198 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3199 si
.nPage
, si
.nMin
, si
.nMax
);
3201 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3202 memset(&si
, 0, sizeof(si
));
3203 si
.cbSize
= sizeof(si
);
3204 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3205 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3206 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3207 "Vertical scrollbar is visible, should be invisible.\n");
3208 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3209 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3210 si
.nPage
, si
.nMin
, si
.nMax
);
3212 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3213 memset(&si
, 0, sizeof(si
));
3214 si
.cbSize
= sizeof(si
);
3215 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3216 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3217 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3218 "Vertical scrollbar is invisible, should be visible.\n");
3219 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3220 "reported page/range is %d (%d..%d)\n",
3221 si
.nPage
, si
.nMin
, si
.nMax
);
3223 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3224 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
3225 memset(&si
, 0, sizeof(si
));
3226 si
.cbSize
= sizeof(si
);
3227 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3228 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3229 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3230 "Vertical scrollbar is visible, should be invisible.\n");
3231 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3232 "reported page/range is %d (%d..%d)\n",
3233 si
.nPage
, si
.nMin
, si
.nMax
);
3235 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3236 memset(&si
, 0, sizeof(si
));
3237 si
.cbSize
= sizeof(si
);
3238 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3239 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3240 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3241 "Vertical scrollbar is visible, should be invisible.\n");
3242 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3243 "reported page/range is %d (%d..%d)\n",
3244 si
.nPage
, si
.nMin
, si
.nMax
);
3246 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3247 EM_SCROLL will make visible any forcefully invisible scrollbar */
3248 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3249 memset(&si
, 0, sizeof(si
));
3250 si
.cbSize
= sizeof(si
);
3251 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3252 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3253 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3254 "Vertical scrollbar is invisible, should be visible.\n");
3255 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3256 "reported page/range is %d (%d..%d)\n",
3257 si
.nPage
, si
.nMin
, si
.nMax
);
3259 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
3260 memset(&si
, 0, sizeof(si
));
3261 si
.cbSize
= sizeof(si
);
3262 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3263 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3264 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3265 "Vertical scrollbar is visible, should be invisible.\n");
3266 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3267 "reported page/range is %d (%d..%d)\n",
3268 si
.nPage
, si
.nMin
, si
.nMax
);
3270 /* Again, EM_SCROLL, with SB_LINEUP */
3271 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3272 memset(&si
, 0, sizeof(si
));
3273 si
.cbSize
= sizeof(si
);
3274 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3275 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3276 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3277 "Vertical scrollbar is invisible, should be visible.\n");
3278 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3279 "reported page/range is %d (%d..%d)\n",
3280 si
.nPage
, si
.nMin
, si
.nMax
);
3282 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3283 memset(&si
, 0, sizeof(si
));
3284 si
.cbSize
= sizeof(si
);
3285 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3286 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3287 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3288 "Vertical scrollbar is visible, should be invisible.\n");
3289 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3290 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3291 si
.nPage
, si
.nMin
, si
.nMax
);
3293 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3294 memset(&si
, 0, sizeof(si
));
3295 si
.cbSize
= sizeof(si
);
3296 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3297 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3298 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3299 "Vertical scrollbar is invisible, should be visible.\n");
3300 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3301 "reported page/range is %d (%d..%d)\n",
3302 si
.nPage
, si
.nMin
, si
.nMax
);
3304 DestroyWindow(hwndRichEdit
);
3307 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
3308 hwndRichEdit
= new_richedit(NULL
);
3310 #define ENABLE_WS_VSCROLL(hwnd) \
3311 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
3312 #define DISABLE_WS_VSCROLL(hwnd) \
3313 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
3315 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3316 ENABLE_WS_VSCROLL(hwndRichEdit
);
3317 memset(&si
, 0, sizeof(si
));
3318 si
.cbSize
= sizeof(si
);
3319 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3320 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3321 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3322 "Vertical scrollbar is invisible, should be visible.\n");
3323 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3324 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3325 si
.nPage
, si
.nMin
, si
.nMax
);
3327 /* Ditto, see above */
3328 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3329 memset(&si
, 0, sizeof(si
));
3330 si
.cbSize
= sizeof(si
);
3331 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3332 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3333 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3334 "Vertical scrollbar is invisible, should be visible.\n");
3335 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3336 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3337 si
.nPage
, si
.nMin
, si
.nMax
);
3339 /* Ditto, see above */
3340 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3341 memset(&si
, 0, sizeof(si
));
3342 si
.cbSize
= sizeof(si
);
3343 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3344 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3345 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3346 "Vertical scrollbar is invisible, should be visible.\n");
3347 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3348 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3349 si
.nPage
, si
.nMin
, si
.nMax
);
3351 /* Ditto, see above */
3352 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
3353 memset(&si
, 0, sizeof(si
));
3354 si
.cbSize
= sizeof(si
);
3355 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3356 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3357 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3358 "Vertical scrollbar is invisible, should be visible.\n");
3359 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3360 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3361 si
.nPage
, si
.nMin
, si
.nMax
);
3363 /* Ditto, see above */
3364 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3365 memset(&si
, 0, sizeof(si
));
3366 si
.cbSize
= sizeof(si
);
3367 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3368 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3369 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3370 "Vertical scrollbar is invisible, should be visible.\n");
3371 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3372 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3373 si
.nPage
, si
.nMin
, si
.nMax
);
3375 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3376 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3377 memset(&si
, 0, sizeof(si
));
3378 si
.cbSize
= sizeof(si
);
3379 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3380 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3381 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3382 "Vertical scrollbar is visible, should be invisible.\n");
3383 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3384 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3385 si
.nPage
, si
.nMin
, si
.nMax
);
3387 DestroyWindow(hwndRichEdit
);
3389 hwndRichEdit
= new_richedit(NULL
);
3391 DISABLE_WS_VSCROLL(hwndRichEdit
);
3392 memset(&si
, 0, sizeof(si
));
3393 si
.cbSize
= sizeof(si
);
3394 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3395 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3396 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3397 "Vertical scrollbar is visible, should be invisible.\n");
3398 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3399 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3400 si
.nPage
, si
.nMin
, si
.nMax
);
3402 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3403 memset(&si
, 0, sizeof(si
));
3404 si
.cbSize
= sizeof(si
);
3405 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3406 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3407 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3408 "Vertical scrollbar is visible, should be invisible.\n");
3409 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3410 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3411 si
.nPage
, si
.nMin
, si
.nMax
);
3413 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3414 memset(&si
, 0, sizeof(si
));
3415 si
.cbSize
= sizeof(si
);
3416 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3417 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3418 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3419 "Vertical scrollbar is visible, should be invisible.\n");
3420 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3421 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3422 si
.nPage
, si
.nMin
, si
.nMax
);
3424 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3425 memset(&si
, 0, sizeof(si
));
3426 si
.cbSize
= sizeof(si
);
3427 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3428 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3429 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3430 "Vertical scrollbar is visible, should be invisible.\n");
3431 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3432 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3433 si
.nPage
, si
.nMin
, si
.nMax
);
3435 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3436 memset(&si
, 0, sizeof(si
));
3437 si
.cbSize
= sizeof(si
);
3438 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3439 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3440 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3441 "Vertical scrollbar is invisible, should be visible.\n");
3442 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3443 "reported page/range is %d (%d..%d)\n",
3444 si
.nPage
, si
.nMin
, si
.nMax
);
3446 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3447 DISABLE_WS_VSCROLL(hwndRichEdit
);
3448 memset(&si
, 0, sizeof(si
));
3449 si
.cbSize
= sizeof(si
);
3450 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3451 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3452 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3453 "Vertical scrollbar is visible, should be invisible.\n");
3454 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3455 "reported page/range is %d (%d..%d)\n",
3456 si
.nPage
, si
.nMin
, si
.nMax
);
3458 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3459 memset(&si
, 0, sizeof(si
));
3460 si
.cbSize
= sizeof(si
);
3461 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3462 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3463 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3464 "Vertical scrollbar is visible, should be invisible.\n");
3465 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3466 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3467 si
.nPage
, si
.nMin
, si
.nMax
);
3469 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3470 memset(&si
, 0, sizeof(si
));
3471 si
.cbSize
= sizeof(si
);
3472 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3473 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3474 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3475 "Vertical scrollbar is invisible, should be visible.\n");
3476 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3477 "reported page/range is %d (%d..%d)\n",
3478 si
.nPage
, si
.nMin
, si
.nMax
);
3480 DISABLE_WS_VSCROLL(hwndRichEdit
);
3481 memset(&si
, 0, sizeof(si
));
3482 si
.cbSize
= sizeof(si
);
3483 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3484 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3485 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3486 "Vertical scrollbar is visible, should be invisible.\n");
3487 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3488 "reported page/range is %d (%d..%d)\n",
3489 si
.nPage
, si
.nMin
, si
.nMax
);
3491 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3492 EM_SCROLL will make visible any forcefully invisible scrollbar */
3493 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3494 memset(&si
, 0, sizeof(si
));
3495 si
.cbSize
= sizeof(si
);
3496 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3497 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3498 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3499 "Vertical scrollbar is invisible, should be visible.\n");
3500 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3501 "reported page/range is %d (%d..%d)\n",
3502 si
.nPage
, si
.nMin
, si
.nMax
);
3504 DISABLE_WS_VSCROLL(hwndRichEdit
);
3505 memset(&si
, 0, sizeof(si
));
3506 si
.cbSize
= sizeof(si
);
3507 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3508 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3509 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3510 "Vertical scrollbar is visible, should be invisible.\n");
3511 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3512 "reported page/range is %d (%d..%d)\n",
3513 si
.nPage
, si
.nMin
, si
.nMax
);
3515 /* Again, EM_SCROLL, with SB_LINEUP */
3516 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3517 memset(&si
, 0, sizeof(si
));
3518 si
.cbSize
= sizeof(si
);
3519 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3520 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3521 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3522 "Vertical scrollbar is invisible, should be visible.\n");
3523 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3524 "reported page/range is %d (%d..%d)\n",
3525 si
.nPage
, si
.nMin
, si
.nMax
);
3527 DestroyWindow(hwndRichEdit
);
3529 /* This window proc models what is going on with Corman Lisp 3.0.
3530 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3531 force the scrollbar into visibility. Recursion should NOT happen
3532 as a result of this action.
3534 r
= GetClassInfoA(NULL
, RICHEDIT_CLASS20A
, &cls
);
3536 richeditProc
= cls
.lpfnWndProc
;
3537 cls
.lpfnWndProc
= RicheditStupidOverrideProcA
;
3538 cls
.lpszClassName
= "RicheditStupidOverride";
3539 if(!RegisterClassA(&cls
)) assert(0);
3542 WM_SIZE_recursionLevel
= 0;
3543 bailedOutOfRecursion
= FALSE
;
3544 hwndRichEdit
= new_window(cls
.lpszClassName
, ES_MULTILINE
, NULL
);
3545 ok(!bailedOutOfRecursion
,
3546 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3549 WM_SIZE_recursionLevel
= 0;
3550 bailedOutOfRecursion
= FALSE
;
3551 MoveWindow(hwndRichEdit
, 0, 0, 250, 100, TRUE
);
3552 ok(!bailedOutOfRecursion
,
3553 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3555 /* Unblock window in order to process WM_DESTROY */
3557 bailedOutOfRecursion
= FALSE
;
3558 WM_SIZE_recursionLevel
= 0;
3559 DestroyWindow(hwndRichEdit
);
3563 static void test_EM_SETUNDOLIMIT(void)
3565 /* cases we test for:
3566 * default behaviour - limiting at 100 undo's
3567 * undo disabled - setting a limit of 0
3568 * undo limited - undo limit set to some to some number, like 2
3569 * bad input - sending a negative number should default to 100 undo's */
3571 HWND hwndRichEdit
= new_richedit(NULL
);
3576 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
3579 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3581 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
3582 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3583 also, multiple pastes don't combine like WM_CHAR would */
3585 /* first case - check the default */
3586 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3587 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
3588 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3589 for (i
=0; i
<100; i
++) /* Undo 100 of them */
3590 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3591 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3592 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3594 /* second case - cannot undo */
3595 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3596 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
3597 SendMessageA(hwndRichEdit
,
3598 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
3599 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3600 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3602 /* third case - set it to an arbitrary number */
3603 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3604 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
3605 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3606 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3607 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3608 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3609 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0,0),
3610 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3611 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3612 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3613 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3614 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3615 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3616 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3618 /* fourth case - setting negative numbers should default to 100 undos */
3619 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3620 result
= SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
3622 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
3624 DestroyWindow(hwndRichEdit
);
3627 static void test_ES_PASSWORD(void)
3629 /* This isn't hugely testable, so we're just going to run it through its paces */
3631 HWND hwndRichEdit
= new_richedit(NULL
);
3634 /* First, check the default of a regular control */
3635 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3637 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
3639 /* Now, set it to something normal */
3640 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
3641 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3643 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3645 /* Now, set it to something odd */
3646 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
3647 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3649 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3650 DestroyWindow(hwndRichEdit
);
3653 LONG streamout_written
= 0;
3655 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
3660 char** str
= (char**)dwCookie
;
3663 memcpy(*str
, pbBuff
, *pcb
);
3666 streamout_written
= *pcb
;
3670 static void test_WM_SETTEXT(void)
3672 HWND hwndRichEdit
= new_richedit(NULL
);
3673 const char * TestItem1
= "TestSomeText";
3674 const char * TestItem2
= "TestSomeText\r";
3675 const char * TestItem2_after
= "TestSomeText\r\n";
3676 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
3677 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
3678 const char * TestItem4
= "TestSomeText\n\nTestSomeText";
3679 const char * TestItem4_after
= "TestSomeText\r\n\r\nTestSomeText";
3680 const char * TestItem5
= "TestSomeText\r\r\nTestSomeText";
3681 const char * TestItem5_after
= "TestSomeText TestSomeText";
3682 const char * TestItem6
= "TestSomeText\r\r\n\rTestSomeText";
3683 const char * TestItem6_after
= "TestSomeText \r\nTestSomeText";
3684 const char * TestItem7
= "TestSomeText\r\n\r\r\n\rTestSomeText";
3685 const char * TestItem7_after
= "TestSomeText\r\n \r\nTestSomeText";
3687 const char rtftextA
[] = "{\\rtf sometext}";
3688 const char urtftextA
[] = "{\\urtf sometext}";
3689 const WCHAR rtftextW
[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3690 const WCHAR urtftextW
[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3691 const WCHAR sometextW
[] = {'s','o','m','e','t','e','x','t',0};
3693 char buf
[1024] = {0};
3694 WCHAR bufW
[1024] = {0};
3697 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3698 any solitary \r to be converted to \r\n on return. Properly paired
3699 \r\n are not affected. It also shows that the special sequence \r\r\n
3700 gets converted to a single space.
3703 #define TEST_SETTEXT(a, b) \
3704 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3705 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3706 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3707 ok (result == lstrlenA(buf), \
3708 "WM_GETTEXT returned %ld instead of expected %u\n", \
3709 result, lstrlenA(buf)); \
3710 result = strcmp(b, buf); \
3712 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3714 TEST_SETTEXT(TestItem1
, TestItem1
)
3715 TEST_SETTEXT(TestItem2
, TestItem2_after
)
3716 TEST_SETTEXT(TestItem3
, TestItem3_after
)
3717 TEST_SETTEXT(TestItem3_after
, TestItem3_after
)
3718 TEST_SETTEXT(TestItem4
, TestItem4_after
)
3719 TEST_SETTEXT(TestItem5
, TestItem5_after
)
3720 TEST_SETTEXT(TestItem6
, TestItem6_after
)
3721 TEST_SETTEXT(TestItem7
, TestItem7_after
)
3723 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3724 TEST_SETTEXT(rtftextA
, "sometext") /* interpreted as ascii rtf */
3725 TEST_SETTEXT(urtftextA
, "sometext") /* interpreted as ascii rtf */
3726 TEST_SETTEXT(rtftextW
, "{") /* interpreted as ascii text */
3727 TEST_SETTEXT(urtftextW
, "{") /* interpreted as ascii text */
3728 DestroyWindow(hwndRichEdit
);
3731 #define TEST_SETTEXTW(a, b) \
3732 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3733 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3734 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3735 ok (result == lstrlenW(bufW), \
3736 "WM_GETTEXT returned %ld instead of expected %u\n", \
3737 result, lstrlenW(bufW)); \
3738 result = lstrcmpW(b, bufW); \
3739 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3741 hwndRichEdit
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
3742 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
3743 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
3744 ok(hwndRichEdit
!= NULL
, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3745 TEST_SETTEXTW(rtftextA
, sometextW
) /* interpreted as ascii rtf */
3746 TEST_SETTEXTW(urtftextA
, sometextW
) /* interpreted as ascii rtf */
3747 TEST_SETTEXTW(rtftextW
, rtftextW
) /* interpreted as ascii text */
3748 TEST_SETTEXTW(urtftextW
, urtftextW
) /* interpreted as ascii text */
3749 DestroyWindow(hwndRichEdit
);
3750 #undef TEST_SETTEXTW
3753 /* Set *pcb to one to show that the remaining cb-1 bytes are not
3754 resent to the callkack. */
3755 static DWORD CALLBACK
test_esCallback_written_1(DWORD_PTR dwCookie
,
3760 char** str
= (char**)dwCookie
;
3761 ok(*pcb
== cb
|| *pcb
== 0, "cb %d, *pcb %d\n", cb
, *pcb
);
3764 memcpy(*str
, pbBuff
, cb
);
3771 static int count_pars(const char *buf
)
3773 const char *p
= buf
;
3775 while ((p
= strstr( p
, "\\par" )) != NULL
)
3777 if (!isalpha( p
[4] ))
3784 static void test_EM_STREAMOUT(void)
3786 HWND hwndRichEdit
= new_richedit(NULL
);
3789 char buf
[1024] = {0};
3793 const char * TestItem1
= "TestSomeText";
3794 const char * TestItem2
= "TestSomeText\r";
3795 const char * TestItem3
= "TestSomeText\r\n";
3797 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem1
);
3799 es
.dwCookie
= (DWORD_PTR
)&p
;
3801 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3802 memset(buf
, 0, sizeof(buf
));
3803 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3805 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
3806 ok(strcmp(buf
, TestItem1
) == 0,
3807 "streamed text different, got %s\n", buf
);
3808 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3810 /* RTF mode writes the final end of para \r if it's part of the selection */
3812 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3813 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3814 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3816 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 12);
3817 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3818 ok (count_pars(buf
) == 0, "got %s\n", buf
);
3819 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3821 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3822 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3823 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3824 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3826 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
3828 es
.dwCookie
= (DWORD_PTR
)&p
;
3830 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3831 memset(buf
, 0, sizeof(buf
));
3832 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3833 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3835 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3836 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3837 ok(strcmp(buf
, TestItem3
) == 0,
3838 "streamed text different from, got %s\n", buf
);
3840 /* And again RTF mode writes the final end of para \r if it's part of the selection */
3842 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3843 ok (count_pars(buf
) == 2, "got %s\n", buf
);
3844 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3846 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 13);
3847 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3848 ok (count_pars(buf
) == 1, "got %s\n", buf
);
3849 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3851 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3852 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
|SFF_SELECTION
, (LPARAM
)&es
);
3853 ok (count_pars(buf
) == 2, "got %s\n", buf
);
3854 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3856 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem3
);
3858 es
.dwCookie
= (DWORD_PTR
)&p
;
3860 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3861 memset(buf
, 0, sizeof(buf
));
3862 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3863 ok(result
== streamout_written
, "got %ld expected %d\n", result
, streamout_written
);
3865 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3866 ok(strcmp(buf
, TestItem3
) == 0,
3867 "streamed text different, got %s\n", buf
);
3869 /* Use a callback that sets *pcb to one */
3871 es
.dwCookie
= (DWORD_PTR
)&p
;
3873 es
.pfnCallback
= test_esCallback_written_1
;
3874 memset(buf
, 0, sizeof(buf
));
3875 result
= SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3877 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3878 ok(strcmp(buf
, TestItem3
) == 0,
3879 "streamed text different, got %s\n", buf
);
3880 ok(result
== 0, "got %ld expected 0\n", result
);
3883 DestroyWindow(hwndRichEdit
);
3886 static void test_EM_STREAMOUT_FONTTBL(void)
3888 HWND hwndRichEdit
= new_richedit(NULL
);
3890 char buf
[1024] = {0};
3895 const char * TestItem
= "TestSomeText";
3897 /* fills in the richedit control with some text */
3898 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem
);
3900 /* streams out the text in rtf format */
3902 es
.dwCookie
= (DWORD_PTR
)&p
;
3904 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3905 memset(buf
, 0, sizeof(buf
));
3906 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3908 /* scans for \fonttbl, error if not found */
3909 fontTbl
= strstr(buf
, "\\fonttbl");
3910 ok(fontTbl
!= NULL
, "missing \\fonttbl section\n");
3913 /* scans for terminating closing bracket */
3915 while(*fontTbl
&& brackCount
)
3919 else if(*fontTbl
== '}')
3923 /* checks whether closing bracket is ok */
3924 ok(brackCount
== 0, "missing closing bracket in \\fonttbl block\n");
3927 /* char before closing fonttbl block should be a closed bracket */
3929 ok(*fontTbl
== '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl
);
3931 /* char after fonttbl block should be a crlf */
3933 ok(*fontTbl
== 0x0d && *(fontTbl
+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3936 DestroyWindow(hwndRichEdit
);
3940 static void test_EM_SETTEXTEX(void)
3942 HWND hwndRichEdit
, parent
;
3944 int sel_start
, sel_end
;
3947 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
3949 'T', 'e', 'x', 't', 0};
3950 WCHAR TestItem1alt
[] = {'T', 'T', 'e', 's',
3956 WCHAR TestItem1altn
[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
3957 '\r','t','S','o','m','e','T','e','x','t',0};
3958 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
3962 const char * TestItem2_after
= "TestSomeText\r\n";
3963 WCHAR TestItem3
[] = {'T', 'e', 's', 't',
3966 '\r','\n','\r','\n', 0};
3967 WCHAR TestItem3alt
[] = {'T', 'e', 's', 't',
3971 WCHAR TestItem3_after
[] = {'T', 'e', 's', 't',
3975 WCHAR TestItem4
[] = {'T', 'e', 's', 't',
3978 '\r','\r','\n','\r',
3980 WCHAR TestItem4_after
[] = {'T', 'e', 's', 't',
3984 #define MAX_BUF_LEN 1024
3985 WCHAR buf
[MAX_BUF_LEN
];
3986 char bufACP
[MAX_BUF_LEN
];
3993 /* Test the scroll position with and without a parent window.
3995 * For some reason the scroll position is 0 after EM_SETTEXTEX
3996 * with the ST_SELECTION flag only when the control has a parent
3997 * window, even though the selection is at the end. */
3999 cls
.lpfnWndProc
= DefWindowProcA
;
4002 cls
.hInstance
= GetModuleHandleA(0);
4004 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
4005 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
4006 cls
.lpszMenuName
= NULL
;
4007 cls
.lpszClassName
= "ParentTestClass";
4008 if(!RegisterClassA(&cls
)) assert(0);
4010 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
4011 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
4012 ok (parent
!= 0, "Failed to create parent window\n");
4014 hwndRichEdit
= CreateWindowExA(0,
4015 RICHEDIT_CLASS20A
, NULL
,
4016 ES_MULTILINE
|WS_VSCROLL
|WS_VISIBLE
|WS_CHILD
,
4017 0, 0, 200, 60, parent
, NULL
,
4018 hmoduleRichEdit
, NULL
);
4020 setText
.codepage
= CP_ACP
;
4021 setText
.flags
= ST_SELECTION
;
4022 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
4023 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4024 todo_wine
ok(result
== 18, "EM_SETTEXTEX returned %d, expected 18\n", result
);
4025 si
.cbSize
= sizeof(si
);
4027 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
4028 todo_wine
ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
4029 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
4030 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
4031 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
4033 DestroyWindow(parent
);
4035 /* Test without a parent window */
4036 hwndRichEdit
= new_richedit(NULL
);
4037 setText
.codepage
= CP_ACP
;
4038 setText
.flags
= ST_SELECTION
;
4039 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
4040 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4041 todo_wine
ok(result
== 18, "EM_SETTEXTEX returned %d, expected 18\n", result
);
4042 si
.cbSize
= sizeof(si
);
4044 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
4045 ok(si
.nPos
!= 0, "Position is incorrectly at %d\n", si
.nPos
);
4046 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
4047 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
4048 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
4050 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
4051 * but this time it is because the selection is at the beginning. */
4052 setText
.codepage
= CP_ACP
;
4053 setText
.flags
= ST_DEFAULT
;
4054 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
4055 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4056 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4057 si
.cbSize
= sizeof(si
);
4059 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
4060 ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
4061 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
4062 ok(sel_start
== 0, "Selection start incorrectly at %d\n", sel_start
);
4063 ok(sel_end
== 0, "Selection end incorrectly at %d\n", sel_end
);
4065 setText
.codepage
= 1200; /* no constant for unicode */
4066 getText
.codepage
= 1200; /* no constant for unicode */
4067 getText
.cb
= MAX_BUF_LEN
;
4068 getText
.flags
= GT_DEFAULT
;
4069 getText
.lpDefaultChar
= NULL
;
4070 getText
.lpUsedDefChar
= NULL
;
4073 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4074 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4075 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4076 ok(lstrcmpW(buf
, TestItem1
) == 0,
4077 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4079 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
4080 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
4082 setText
.codepage
= 1200; /* no constant for unicode */
4083 getText
.codepage
= 1200; /* no constant for unicode */
4084 getText
.cb
= MAX_BUF_LEN
;
4085 getText
.flags
= GT_DEFAULT
;
4086 getText
.lpDefaultChar
= NULL
;
4087 getText
.lpUsedDefChar
= NULL
;
4089 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem2
);
4090 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4091 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4092 ok(lstrcmpW(buf
, TestItem2
) == 0,
4093 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4095 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
4096 SendMessageA(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
4097 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
4098 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
4100 /* Baseline test for just-enough buffer space for string */
4101 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
4102 getText
.codepage
= 1200; /* no constant for unicode */
4103 getText
.flags
= GT_DEFAULT
;
4104 getText
.lpDefaultChar
= NULL
;
4105 getText
.lpUsedDefChar
= NULL
;
4106 memset(buf
, 0, sizeof(buf
));
4107 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4108 ok(lstrcmpW(buf
, TestItem2
) == 0,
4109 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4111 /* When there is enough space for one character, but not both, of the CRLF
4112 pair at the end of the string, the CR is not copied at all. That is,
4113 the caller must not see CRLF pairs truncated to CR at the end of the
4116 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
4117 getText
.codepage
= 1200; /* no constant for unicode */
4118 getText
.flags
= GT_USECRLF
; /* <-- asking for CR -> CRLF conversion */
4119 getText
.lpDefaultChar
= NULL
;
4120 getText
.lpUsedDefChar
= NULL
;
4121 memset(buf
, 0, sizeof(buf
));
4122 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4123 ok(lstrcmpW(buf
, TestItem1
) == 0,
4124 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4127 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
4128 setText
.codepage
= 1200; /* no constant for unicode */
4129 getText
.codepage
= 1200; /* no constant for unicode */
4130 getText
.cb
= MAX_BUF_LEN
;
4131 getText
.flags
= GT_DEFAULT
;
4132 getText
.lpDefaultChar
= NULL
;
4133 getText
.lpUsedDefChar
= NULL
;
4135 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3
);
4136 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4137 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4138 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
4139 "EM_SETTEXTEX did not convert properly\n");
4141 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
4142 setText
.codepage
= 1200; /* no constant for unicode */
4143 getText
.codepage
= 1200; /* no constant for unicode */
4144 getText
.cb
= MAX_BUF_LEN
;
4145 getText
.flags
= GT_DEFAULT
;
4146 getText
.lpDefaultChar
= NULL
;
4147 getText
.lpUsedDefChar
= NULL
;
4149 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3alt
);
4150 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4151 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4152 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
4153 "EM_SETTEXTEX did not convert properly\n");
4155 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
4156 setText
.codepage
= 1200; /* no constant for unicode */
4157 getText
.codepage
= 1200; /* no constant for unicode */
4158 getText
.cb
= MAX_BUF_LEN
;
4159 getText
.flags
= GT_DEFAULT
;
4160 getText
.lpDefaultChar
= NULL
;
4161 getText
.lpUsedDefChar
= NULL
;
4163 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem4
);
4164 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4165 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4166 ok(lstrcmpW(buf
, TestItem4_after
) == 0,
4167 "EM_SETTEXTEX did not convert properly\n");
4169 /* !ST_SELECTION && Unicode && !\rtf */
4170 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
4171 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4174 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
4175 ok(!buf
[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
4177 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4179 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4180 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4181 /* select some text */
4184 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4185 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4186 setText
.flags
= ST_SELECTION
;
4187 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
4189 "EM_SETTEXTEX with NULL lParam to replace selection"
4190 " with no text should return 0. Got %i\n",
4193 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4195 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4196 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4197 /* select some text */
4200 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4201 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4202 setText
.flags
= ST_SELECTION
;
4203 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4205 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4206 ok(result
== lstrlenW(TestItem1
),
4207 "EM_SETTEXTEX with NULL lParam to replace selection"
4208 " with no text should return 0. Got %i\n",
4210 ok(lstrlenW(buf
) == 22,
4211 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
4214 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
4215 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
4217 es
.dwCookie
= (DWORD_PTR
)&p
;
4219 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
4220 memset(buf
, 0, sizeof(buf
));
4221 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
4222 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
4223 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
4225 /* !ST_SELECTION && !Unicode && \rtf */
4226 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
4227 getText
.codepage
= 1200; /* no constant for unicode */
4228 getText
.cb
= MAX_BUF_LEN
;
4229 getText
.flags
= GT_DEFAULT
;
4230 getText
.lpDefaultChar
= NULL
;
4231 getText
.lpUsedDefChar
= NULL
;
4234 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
4235 ok(result
== 1, "EM_SETTEXTEX returned %d, expected 1\n", result
);
4236 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4237 ok(lstrcmpW(buf
, TestItem1
) == 0,
4238 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4240 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
4241 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
4242 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
4243 getText
.codepage
= CP_ACP
;
4244 getText
.cb
= MAX_BUF_LEN
;
4245 getText
.flags
= GT_DEFAULT
;
4246 getText
.lpDefaultChar
= NULL
;
4247 getText
.lpUsedDefChar
= NULL
;
4249 setText
.flags
= ST_SELECTION
;
4250 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4251 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf not unicode}");
4252 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
4253 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4254 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
4256 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
4257 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
4259 es
.dwCookie
= (DWORD_PTR
)&p
;
4261 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
4262 memset(buf
, 0, sizeof(buf
));
4263 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
4264 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
4265 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
4267 /* select some text */
4270 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4272 /* ST_SELECTION && !Unicode && \rtf */
4273 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
4274 getText
.codepage
= 1200; /* no constant for unicode */
4275 getText
.cb
= MAX_BUF_LEN
;
4276 getText
.flags
= GT_DEFAULT
;
4277 getText
.lpDefaultChar
= NULL
;
4278 getText
.lpUsedDefChar
= NULL
;
4280 setText
.flags
= ST_SELECTION
;
4281 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
4282 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4283 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
4285 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
4286 setText
.codepage
= 1200; /* no constant for unicode */
4287 getText
.codepage
= CP_ACP
;
4288 getText
.cb
= MAX_BUF_LEN
;
4291 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
); /* TestItem1 */
4292 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4294 /* select some text */
4297 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4299 /* ST_SELECTION && !Unicode && !\rtf */
4300 setText
.codepage
= CP_ACP
;
4301 getText
.codepage
= 1200; /* no constant for unicode */
4302 getText
.cb
= MAX_BUF_LEN
;
4303 getText
.flags
= GT_DEFAULT
;
4304 getText
.lpDefaultChar
= NULL
;
4305 getText
.lpUsedDefChar
= NULL
;
4307 setText
.flags
= ST_SELECTION
;
4308 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)bufACP
);
4309 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
4310 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
4311 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
4312 " using ST_SELECTION and non-Unicode\n");
4314 /* Test setting text using rich text format */
4316 setText
.codepage
= CP_ACP
;
4317 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
4318 getText
.codepage
= CP_ACP
;
4319 getText
.cb
= MAX_BUF_LEN
;
4320 getText
.flags
= GT_DEFAULT
;
4321 getText
.lpDefaultChar
= NULL
;
4322 getText
.lpUsedDefChar
= NULL
;
4323 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4324 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
4327 setText
.codepage
= CP_ACP
;
4328 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
4329 getText
.codepage
= CP_ACP
;
4330 getText
.cb
= MAX_BUF_LEN
;
4331 getText
.flags
= GT_DEFAULT
;
4332 getText
.lpDefaultChar
= NULL
;
4333 getText
.lpUsedDefChar
= NULL
;
4334 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
4335 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
4337 /* test for utf8 text with BOM */
4339 setText
.codepage
= CP_ACP
;
4340 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
4341 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4342 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
4343 result
= strcmp(bufACP
, "TestUTF8WithBOM");
4344 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
4347 setText
.codepage
= CP_UTF8
;
4348 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
4349 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4350 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
4351 result
= strcmp(bufACP
, "TestUTF8WithBOM");
4352 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
4354 /* Test multibyte character */
4355 if (!is_lang_japanese
)
4356 skip("Skip multibyte character tests on non-Japanese platform\n");
4359 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4360 setText
.flags
= ST_SELECTION
;
4361 setText
.codepage
= CP_ACP
;
4362 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"abc\x8e\xf0");
4363 todo_wine
ok(result
== 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result
);
4364 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4365 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4366 ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4367 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4369 setText
.flags
= ST_DEFAULT
;
4370 setText
.codepage
= CP_ACP
;
4371 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"abc\x8e\xf0");
4372 ok(result
== 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result
);
4373 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4374 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4375 ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4376 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4378 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4379 setText
.flags
= ST_SELECTION
;
4380 setText
.codepage
= CP_ACP
;
4381 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf abc\x8e\xf0}");
4382 todo_wine
ok(result
== 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result
);
4383 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
4384 ok(result
== 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result
);
4385 todo_wine
ok(!strcmp(bufACP
, "abc\x8e\xf0"),
4386 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP
);
4389 DestroyWindow(hwndRichEdit
);
4392 static void test_EM_LIMITTEXT(void)
4396 HWND hwndRichEdit
= new_richedit(NULL
);
4398 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
4399 * about setting the length to -1 for multiline edit controls doesn't happen.
4402 /* Don't check default gettextlimit case. That's done in other tests */
4404 /* Set textlimit to 100 */
4405 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
4406 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4408 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
4410 /* Set textlimit to 0 */
4411 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
4412 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4414 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
4416 /* Set textlimit to -1 */
4417 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
4418 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4420 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
4422 /* Set textlimit to -2 */
4423 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
4424 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4426 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
4428 DestroyWindow (hwndRichEdit
);
4432 static void test_EM_EXLIMITTEXT(void)
4434 int i
, selBegin
, selEnd
, len1
, len2
;
4436 char text
[1024 + 1];
4437 char buffer
[1024 + 1];
4438 int textlimit
= 0; /* multiple of 100 */
4439 HWND hwndRichEdit
= new_richedit(NULL
);
4441 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4442 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
4445 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4446 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4448 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
4451 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4452 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4454 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
4456 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
4457 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4458 /* default for WParam = 0 */
4459 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
4461 textlimit
= sizeof(text
)-1;
4462 memset(text
, 'W', textlimit
);
4463 text
[sizeof(text
)-1] = 0;
4464 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4465 /* maxed out text */
4466 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4468 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4469 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4470 len1
= selEnd
- selBegin
;
4472 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
4473 SendMessageA(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
4474 SendMessageA(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
4475 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4476 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4477 len2
= selEnd
- selBegin
;
4480 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4483 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4484 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4485 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1);
4486 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4487 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4488 len1
= selEnd
- selBegin
;
4491 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4494 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4495 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4496 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
4497 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4498 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4499 len2
= selEnd
- selBegin
;
4502 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4505 /* set text up to the limit, select all the text, then add a char */
4507 memset(text
, 'W', textlimit
);
4508 text
[textlimit
] = 0;
4509 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4510 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4511 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4512 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4513 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4514 result
= strcmp(buffer
, "A");
4515 ok(0 == result
, "got string = \"%s\"\n", buffer
);
4517 /* WM_SETTEXT not limited */
4519 memset(text
, 'W', textlimit
);
4520 text
[textlimit
] = 0;
4521 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
4522 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4523 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4525 ok(10 == i
, "expected 10 chars\n");
4526 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4527 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4529 /* try inserting more text at end */
4530 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4531 ok(0 == i
, "WM_CHAR wasn't processed\n");
4532 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4534 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4535 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4536 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4538 /* try inserting text at beginning */
4539 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
4540 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4541 ok(0 == i
, "WM_CHAR wasn't processed\n");
4542 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4544 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4545 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4546 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4548 /* WM_CHAR is limited */
4550 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4551 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4552 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4553 ok(0 == i
, "WM_CHAR wasn't processed\n");
4554 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4555 ok(0 == i
, "WM_CHAR wasn't processed\n");
4556 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4558 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4560 DestroyWindow(hwndRichEdit
);
4563 static void test_EM_GETLIMITTEXT(void)
4566 HWND hwndRichEdit
= new_richedit(NULL
);
4568 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4569 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4571 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4572 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4573 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4575 DestroyWindow(hwndRichEdit
);
4578 static void test_WM_SETFONT(void)
4580 /* There is no invalid input or error conditions for this function.
4581 * NULL wParam and lParam just fall back to their default values
4582 * It should be noted that even if you use a gibberish name for your fonts
4583 * here, it will still work because the name is stored. They will display as
4584 * System, but will report their name to be whatever they were created as */
4586 HWND hwndRichEdit
= new_richedit(NULL
);
4587 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4588 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4589 FF_DONTCARE
, "Marlett");
4590 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4591 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4592 FF_DONTCARE
, "MS Sans Serif");
4593 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4594 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4595 FF_DONTCARE
, "Courier");
4596 LOGFONTA sentLogFont
;
4597 CHARFORMAT2A returnedCF2A
;
4599 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4601 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
4602 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4603 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4605 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4606 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4607 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4608 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4610 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4611 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4612 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4613 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4614 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4615 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4617 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4618 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4619 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4620 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4621 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4622 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4624 /* This last test is special since we send in NULL. We clear the variables
4625 * and just compare to "System" instead of the sent in font name. */
4626 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4627 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4628 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4630 SendMessageA(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4631 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4632 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4633 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4634 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4636 DestroyWindow(hwndRichEdit
);
4640 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4645 const char** str
= (const char**)dwCookie
;
4646 int size
= strlen(*str
);
4647 if(size
> 3) /* let's make it piecemeal for fun */
4654 memcpy(pbBuff
, *str
, *pcb
);
4660 static void test_EM_GETMODIFY(void)
4662 HWND hwndRichEdit
= new_richedit(NULL
);
4665 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4667 'T', 'e', 'x', 't', 0};
4668 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4670 'O', 't', 'h', 'e', 'r',
4671 'T', 'e', 'x', 't', 0};
4672 const char* streamText
= "hello world";
4677 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4678 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4679 FF_DONTCARE
, "Courier");
4681 setText
.codepage
= 1200; /* no constant for unicode */
4682 setText
.flags
= ST_KEEPUNDO
;
4685 /* modify flag shouldn't be set when richedit is first created */
4686 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4688 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4690 /* setting modify flag should actually set it */
4691 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4692 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4694 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4696 /* clearing modify flag should actually clear it */
4697 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4698 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4700 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4702 /* setting font doesn't change modify flag */
4703 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4704 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4705 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4707 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4709 /* setting text should set modify flag */
4710 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4711 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4712 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4714 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4716 /* undo previous text doesn't reset modify flag */
4717 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
4718 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4720 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4722 /* set text with no flag to keep undo stack should not set modify flag */
4723 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4725 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4726 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4728 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4730 /* WM_SETTEXT doesn't modify */
4731 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4732 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4733 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4735 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4737 /* clear the text */
4738 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4739 SendMessageA(hwndRichEdit
, WM_CLEAR
, 0, 0);
4740 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4742 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4745 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4746 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4747 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4748 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4749 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4751 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4753 /* copy/paste text 1 */
4754 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4755 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4756 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4757 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4758 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4760 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4762 /* copy/paste text 2 */
4763 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4764 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4765 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4766 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 3);
4767 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4768 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4770 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4773 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4774 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 1);
4775 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4776 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4778 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4781 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4782 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4783 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4784 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4786 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4788 /* set char format */
4789 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4790 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
4791 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4792 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4793 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4794 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4795 result
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4796 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4797 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4799 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4801 /* set para format */
4802 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4803 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4804 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4805 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4806 pf2
.wAlignment
= PFA_RIGHT
;
4807 SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4808 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4810 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4813 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4814 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4816 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4817 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4818 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4820 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4822 DestroyWindow(hwndRichEdit
);
4828 LRESULT expected_retval
;
4829 int expected_getsel_start
;
4830 int expected_getsel_end
;
4834 static const struct exsetsel_s exsetsel_tests
[] = {
4836 {5, 10, 10, 5, 10 },
4837 {15, 17, 17, 15, 17 },
4838 /* test cpMax > strlen() */
4839 {0, 100, 18, 0, 18 },
4840 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
4841 {-1, 1, 17, 17, 17 },
4842 /* test cpMin == cpMax */
4844 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4848 /* test cpMin < 0 && cpMax < 0 */
4849 {-1, -1, 17, 17, 17 },
4850 {-4, -5, 17, 17, 17 },
4851 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
4852 {0, -1, 18, 0, 18 },
4853 {17, -5, 18, 17, 18 },
4854 {18, -3, 17, 17, 17 },
4855 /* test if cpMin > cpMax */
4856 {15, 19, 18, 15, 18 },
4857 {19, 15, 18, 15, 18 },
4858 /* cpMin == strlen() && cpMax > cpMin */
4859 {17, 18, 18, 17, 18 },
4860 {17, 50, 18, 17, 18 },
4863 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4868 cr
.cpMin
= setsel
->min
;
4869 cr
.cpMax
= setsel
->max
;
4870 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4872 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4874 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4876 todo_wine_if (setsel
->todo
)
4877 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4878 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4881 static void test_EM_EXSETSEL(void)
4883 HWND hwndRichEdit
= new_richedit(NULL
);
4885 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4887 /* sending some text to the window */
4888 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4889 /* 01234567890123456*/
4892 for (i
= 0; i
< num_tests
; i
++) {
4893 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4896 if (!is_lang_japanese
)
4897 skip("Skip multibyte character tests on non-Japanese platform\n");
4901 char bufA
[MAX_BUF_LEN
] = {0};
4904 /* Test with multibyte character */
4905 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
4906 /* 012345 6 78901 */
4907 cr
.cpMin
= 4, cr
.cpMax
= 8;
4908 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4909 ok(result
== 8, "EM_EXSETSEL return %ld expected 8\n", result
);
4910 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(bufA
), (LPARAM
)bufA
);
4911 ok(!strcmp(bufA
, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4912 SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4913 ok(cr
.cpMin
== 4, "Selection start incorrectly: %d expected 4\n", cr
.cpMin
);
4914 ok(cr
.cpMax
== 8, "Selection end incorrectly: %d expected 8\n", cr
.cpMax
);
4917 DestroyWindow(hwndRichEdit
);
4920 static void check_EM_SETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4924 result
= SendMessageA(hwnd
, EM_SETSEL
, setsel
->min
, setsel
->max
);
4926 ok(result
== setsel
->expected_retval
, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4928 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4930 todo_wine_if (setsel
->todo
)
4931 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4932 id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4935 static void test_EM_SETSEL(void)
4937 char buffA
[32] = {0};
4938 HWND hwndRichEdit
= new_richedit(NULL
);
4940 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4942 /* sending some text to the window */
4943 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4944 /* 01234567890123456*/
4947 for (i
= 0; i
< num_tests
; i
++) {
4948 check_EM_SETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4951 SendMessageA(hwndRichEdit
, EM_SETSEL
, 17, 18);
4953 SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffA
);
4954 ok(buffA
[0] == 0, "selection text %s\n", buffA
);
4956 if (!is_lang_japanese
)
4957 skip("Skip multibyte character tests on non-Japanese platform\n");
4960 int sel_start
, sel_end
;
4963 /* Test with multibyte character */
4964 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"abcdef\x8e\xf0ghijk");
4965 /* 012345 6 78901 */
4966 result
= SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 8);
4967 ok(result
== 8, "EM_SETSEL return %ld expected 8\n", result
);
4968 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, sizeof(buffA
), (LPARAM
)buffA
);
4969 ok(!strcmp(buffA
, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4970 result
= SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
4971 ok(sel_start
== 4, "Selection start incorrectly: %d expected 4\n", sel_start
);
4972 ok(sel_end
== 8, "Selection end incorrectly: %d expected 8\n", sel_end
);
4975 DestroyWindow(hwndRichEdit
);
4978 static void test_EM_REPLACESEL(int redraw
)
4980 HWND hwndRichEdit
= new_richedit(NULL
);
4981 char buffer
[1024] = {0};
4985 CHAR rtfstream
[] = "{\\rtf1 TestSomeText}";
4986 CHAR urtfstream
[] = "{\\urtf1 TestSomeText}";
4988 /* sending some text to the window */
4989 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4990 /* 01234567890123456*/
4993 /* FIXME add more tests */
4994 SendMessageA(hwndRichEdit
, EM_SETSEL
, 7, 17);
4995 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4996 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4997 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4998 r
= strcmp(buffer
, "testing");
4999 ok(0 == r
, "expected %d, got %d\n", 0, r
);
5001 DestroyWindow(hwndRichEdit
);
5003 hwndRichEdit
= new_richedit(NULL
);
5005 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
5006 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
5008 /* Test behavior with carriage returns and newlines */
5009 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5010 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1");
5011 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
5012 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5013 r
= strcmp(buffer
, "RichEdit1");
5014 ok(0 == r
, "expected %d, got %d\n", 0, r
);
5016 getText
.codepage
= CP_ACP
;
5017 getText
.flags
= GT_DEFAULT
;
5018 getText
.lpDefaultChar
= NULL
;
5019 getText
.lpUsedDefChar
= NULL
;
5020 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5021 ok(strcmp(buffer
, "RichEdit1") == 0,
5022 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
5024 /* Test number of lines reported after EM_REPLACESEL */
5025 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5026 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
5028 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5029 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r");
5030 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
5031 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5032 r
= strcmp(buffer
, "RichEdit1\r\n");
5033 ok(0 == r
, "expected %d, got %d\n", 0, r
);
5035 getText
.codepage
= CP_ACP
;
5036 getText
.flags
= GT_DEFAULT
;
5037 getText
.lpDefaultChar
= NULL
;
5038 getText
.lpUsedDefChar
= NULL
;
5039 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5040 ok(strcmp(buffer
, "RichEdit1\r") == 0,
5041 "EM_GETTEXTEX returned incorrect string\n");
5043 /* Test number of lines reported after EM_REPLACESEL */
5044 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5045 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
5047 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5048 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r\n");
5049 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
5051 /* Test number of lines reported after EM_REPLACESEL */
5052 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5053 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
5055 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5056 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5057 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
5058 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
5060 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5061 r
= strcmp(buffer
, "RichEdit1\r\n");
5062 ok(0 == r
, "expected %d, got %d\n", 0, r
);
5064 getText
.codepage
= CP_ACP
;
5065 getText
.flags
= GT_DEFAULT
;
5066 getText
.lpDefaultChar
= NULL
;
5067 getText
.lpUsedDefChar
= NULL
;
5068 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5069 ok(strcmp(buffer
, "RichEdit1\r") == 0,
5070 "EM_GETTEXTEX returned incorrect string\n");
5072 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5073 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5074 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
5075 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
5077 /* The following tests show that richedit should handle the special \r\r\n
5078 sequence by turning it into a single space on insertion. However,
5079 EM_REPLACESEL on WinXP returns the number of characters in the original
5083 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5084 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r");
5085 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
5086 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5087 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5088 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
5089 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
5091 /* Test the actual string */
5093 getText
.codepage
= CP_ACP
;
5094 getText
.flags
= GT_DEFAULT
;
5095 getText
.lpDefaultChar
= NULL
;
5096 getText
.lpUsedDefChar
= NULL
;
5097 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5098 ok(strcmp(buffer
, "\r\r") == 0,
5099 "EM_GETTEXTEX returned incorrect string\n");
5101 /* Test number of lines reported after EM_REPLACESEL */
5102 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5103 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
5105 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5106 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n");
5107 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
5108 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5109 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5110 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
5111 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
5113 /* Test the actual string */
5115 getText
.codepage
= CP_ACP
;
5116 getText
.flags
= GT_DEFAULT
;
5117 getText
.lpDefaultChar
= NULL
;
5118 getText
.lpUsedDefChar
= NULL
;
5119 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5120 ok(strcmp(buffer
, " ") == 0,
5121 "EM_GETTEXTEX returned incorrect string\n");
5123 /* Test number of lines reported after EM_REPLACESEL */
5124 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5125 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
5127 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5128 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\r\r\r\n\r\r\r");
5129 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
5130 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5131 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5132 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
5133 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
5135 /* Test the actual string */
5137 getText
.codepage
= CP_ACP
;
5138 getText
.flags
= GT_DEFAULT
;
5139 getText
.lpDefaultChar
= NULL
;
5140 getText
.lpUsedDefChar
= NULL
;
5141 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5142 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
5143 "EM_GETTEXTEX returned incorrect string\n");
5145 /* Test number of lines reported after EM_REPLACESEL */
5146 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5147 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
5149 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5150 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\n");
5151 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
5152 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5153 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5154 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
5155 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
5157 /* Test the actual string */
5159 getText
.codepage
= CP_ACP
;
5160 getText
.flags
= GT_DEFAULT
;
5161 getText
.lpDefaultChar
= NULL
;
5162 getText
.lpUsedDefChar
= NULL
;
5163 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5164 ok(strcmp(buffer
, " \r") == 0,
5165 "EM_GETTEXTEX returned incorrect string\n");
5167 /* Test number of lines reported after EM_REPLACESEL */
5168 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5169 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
5171 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5172 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\r");
5173 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
5174 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5175 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5176 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
5177 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
5179 /* Test the actual string */
5181 getText
.codepage
= CP_ACP
;
5182 getText
.flags
= GT_DEFAULT
;
5183 getText
.lpDefaultChar
= NULL
;
5184 getText
.lpUsedDefChar
= NULL
;
5185 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5186 ok(strcmp(buffer
, " \r\r") == 0,
5187 "EM_GETTEXTEX returned incorrect string\n");
5189 /* Test number of lines reported after EM_REPLACESEL */
5190 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5191 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
5193 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5194 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\rX\r\n\r\r");
5195 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
5196 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5197 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5198 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
5199 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
5201 /* Test the actual string */
5203 getText
.codepage
= CP_ACP
;
5204 getText
.flags
= GT_DEFAULT
;
5205 getText
.lpDefaultChar
= NULL
;
5206 getText
.lpUsedDefChar
= NULL
;
5207 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5208 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
5209 "EM_GETTEXTEX returned incorrect string\n");
5211 /* Test number of lines reported after EM_REPLACESEL */
5212 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5213 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
5215 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5216 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n");
5217 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
5218 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5219 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5220 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
5221 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
5223 /* Test the actual string */
5225 getText
.codepage
= CP_ACP
;
5226 getText
.flags
= GT_DEFAULT
;
5227 getText
.lpDefaultChar
= NULL
;
5228 getText
.lpUsedDefChar
= NULL
;
5229 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5230 ok(strcmp(buffer
, "\r\r") == 0,
5231 "EM_GETTEXTEX returned incorrect string\n");
5233 /* Test number of lines reported after EM_REPLACESEL */
5234 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5235 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
5237 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5238 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n\n\n\r\r\r\r\n");
5239 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
5240 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5241 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5242 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
5243 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
5245 /* Test the actual string */
5247 getText
.codepage
= CP_ACP
;
5248 getText
.flags
= GT_DEFAULT
;
5249 getText
.lpDefaultChar
= NULL
;
5250 getText
.lpUsedDefChar
= NULL
;
5251 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
5252 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
5253 "EM_GETTEXTEX returned incorrect string\n");
5255 /* Test number of lines reported after EM_REPLACESEL */
5256 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
5257 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
5259 /* Test with multibyte character */
5260 if (!is_lang_japanese
)
5261 skip("Skip multibyte character tests on non-Japanese platform\n");
5264 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5265 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"abc\x8e\xf0");
5266 todo_wine
ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
5267 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5268 ok(r
== 0, "EM_EXGETSEL returned %d, expected 0\n", r
);
5269 ok(cr
.cpMin
== 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr
.cpMin
);
5270 ok(cr
.cpMax
== 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr
.cpMax
);
5271 r
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5272 ok(!strcmp(buffer
, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5273 ok(r
== 5, "WM_GETTEXT returned %d, expected 5\n", r
);
5275 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5276 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"{\\rtf abc\x8e\xf0}");
5277 todo_wine
ok(r
== 4, "EM_REPLACESEL returned %d, expected 4\n", r
);
5278 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5279 ok(r
== 0, "EM_EXGETSEL returned %d, expected 0\n", r
);
5280 todo_wine
ok(cr
.cpMin
== 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr
.cpMin
);
5281 todo_wine
ok(cr
.cpMax
== 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr
.cpMax
);
5282 r
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5283 todo_wine
ok(!strcmp(buffer
, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5284 todo_wine
ok(r
== 5, "WM_GETTEXT returned %d, expected 5\n", r
);
5287 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5288 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
5289 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5290 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5291 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5292 todo_wine
ok(cr
.cpMin
== 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr
.cpMin
);
5293 todo_wine
ok(cr
.cpMax
== 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr
.cpMax
);
5294 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5295 todo_wine
ok(!strcmp(buffer
, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5297 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5298 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urtfstream
);
5299 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5300 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5301 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5302 todo_wine
ok(cr
.cpMin
== 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr
.cpMin
);
5303 todo_wine
ok(cr
.cpMax
== 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr
.cpMax
);
5304 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5305 todo_wine
ok(!strcmp(buffer
, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5307 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Wine");
5308 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 2);
5309 todo_wine r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
5310 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5311 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5312 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5313 todo_wine
ok(cr
.cpMin
== 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr
.cpMin
);
5314 todo_wine
ok(cr
.cpMax
== 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr
.cpMax
);
5315 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5316 todo_wine
ok(!strcmp(buffer
, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5318 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"{\\rtf1 Wine}");
5319 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 2);
5320 todo_wine r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)rtfstream
);
5321 todo_wine
ok(r
== 12, "EM_REPLACESEL returned %d, expected 12\n", r
);
5322 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
5323 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
5324 todo_wine
ok(cr
.cpMin
== 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr
.cpMin
);
5325 todo_wine
ok(cr
.cpMax
== 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr
.cpMax
);
5326 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5327 todo_wine
ok(!strcmp(buffer
, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5330 /* This is needed to avoid interfering with keybd_event calls
5331 * on other tests that simulate keyboard events. */
5332 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
5334 DestroyWindow(hwndRichEdit
);
5337 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
5338 * to test the state of the modifiers (Ctrl/Alt/Shift).
5340 * Therefore Ctrl-<key> keystrokes need to be simulated with
5341 * keybd_event or by using SetKeyboardState to set the modifiers
5342 * and SendMessage to simulate the keystrokes.
5344 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
5347 hold_key(VK_CONTROL
);
5348 result
= SendMessageA(hwnd
, WM_KEYDOWN
, key
, 1);
5349 release_key(VK_CONTROL
);
5353 static void test_WM_PASTE(void)
5356 char buffer
[1024] = {0};
5357 const char* text1
= "testing paste\r";
5358 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
5359 const char* text1_after
= "testing paste\r\n";
5360 const char* text2
= "testing paste\r\rtesting paste";
5361 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
5362 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
5363 HWND hwndRichEdit
= new_richedit(NULL
);
5365 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
5366 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 14);
5368 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
5369 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
5370 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
5371 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5372 /* Pasted text should be visible at this step */
5373 result
= strcmp(text1_step1
, buffer
);
5375 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
5377 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
5378 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5379 /* Text should be the same as before (except for \r -> \r\n conversion) */
5380 result
= strcmp(text1_after
, buffer
);
5382 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
5384 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
5385 SendMessageA(hwndRichEdit
, EM_SETSEL
, 8, 13);
5386 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
5387 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
5388 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
5389 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5390 /* Pasted text should be visible at this step */
5391 result
= strcmp(text3
, buffer
);
5393 "test paste: strcmp = %i\n", result
);
5394 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
5395 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5396 /* Text should be the same as before (except for \r -> \r\n conversion) */
5397 result
= strcmp(text2_after
, buffer
);
5399 "test paste: strcmp = %i\n", result
);
5400 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
5401 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5402 /* Text should revert to post-paste state */
5403 result
= strcmp(buffer
,text3
);
5405 "test paste: strcmp = %i\n", result
);
5407 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5408 /* Send WM_CHAR to simulate Ctrl-V */
5409 SendMessageA(hwndRichEdit
, WM_CHAR
, 22,
5410 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
5411 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5412 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
5413 result
= strcmp(buffer
,"");
5415 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5417 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
5418 * with SetKeyboard state. */
5420 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5421 /* Simulates paste (Ctrl-V) */
5422 hold_key(VK_CONTROL
);
5423 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'V',
5424 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
5425 release_key(VK_CONTROL
);
5426 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5427 result
= strcmp(buffer
,"paste");
5429 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5431 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
5432 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 7);
5433 /* Simulates copy (Ctrl-C) */
5434 hold_key(VK_CONTROL
);
5435 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'C',
5436 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC
) << 16) | 1);
5437 release_key(VK_CONTROL
);
5438 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5439 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
5440 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5441 result
= strcmp(buffer
,"testing");
5443 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5445 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
5446 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"cut");
5447 /* Simulates select all (Ctrl-A) */
5448 hold_key(VK_CONTROL
);
5449 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A',
5450 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC
) << 16) | 1);
5451 /* Simulates select cut (Ctrl-X) */
5452 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'X',
5453 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC
) << 16) | 1);
5454 release_key(VK_CONTROL
);
5455 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5456 result
= strcmp(buffer
,"");
5458 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5459 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
5460 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
5461 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5462 result
= strcmp(buffer
,"cut\r\n");
5464 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5465 /* Simulates undo (Ctrl-Z) */
5466 hold_key(VK_CONTROL
);
5467 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Z',
5468 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
5469 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5470 result
= strcmp(buffer
,"");
5472 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5473 /* Simulates redo (Ctrl-Y) */
5474 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Y',
5475 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
5476 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5477 result
= strcmp(buffer
,"cut\r\n");
5479 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
5480 release_key(VK_CONTROL
);
5482 DestroyWindow(hwndRichEdit
);
5485 static void test_EM_FORMATRANGE(void)
5487 int r
, i
, tpp_x
, tpp_y
;
5489 HWND hwndRichEdit
= new_richedit(NULL
);
5491 BOOL skip_non_english
;
5492 static const struct {
5493 const char *string
; /* The string */
5494 int first
; /* First 'pagebreak', 0 for don't care */
5495 int second
; /* Second 'pagebreak', 0 for don't care */
5497 {"WINE wine", 0, 0},
5498 {"WINE wineWine", 0, 0},
5499 {"WINE\r\nwine\r\nwine", 5, 10},
5500 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
5501 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
5504 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
5505 if (skip_non_english
)
5506 skip("Skipping some tests on non-English platform\n");
5508 hdc
= GetDC(hwndRichEdit
);
5509 ok(hdc
!= NULL
, "Could not get HDC\n");
5511 /* Calculate the twips per pixel */
5512 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
5513 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
5515 /* Test the simple case where all the text fits in the page rect. */
5516 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
5517 fr
.hdc
= fr
.hdcTarget
= hdc
;
5518 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
5519 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
5520 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
5523 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
5524 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
5526 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
5527 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
5528 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
5529 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
5531 SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
5533 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
5535 GETTEXTLENGTHEX gtl
;
5539 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)fmtstrings
[i
].string
);
5541 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5542 gtl
.codepage
= CP_ACP
;
5543 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5545 /* Get some size information for the string */
5546 GetTextExtentPoint32A(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
5548 /* Define the box to be half the width needed and a bit larger than the height.
5549 * Changes to the width means we have at least 2 pages. Changes to the height
5550 * is done so we can check the changing of fr.rc.bottom.
5552 fr
.hdc
= fr
.hdcTarget
= hdc
;
5553 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
5554 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
5555 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
5557 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
5559 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
5562 /* We know that the page can't hold the full string. See how many characters
5563 * are on the first one
5567 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
5569 if (! skip_non_english
)
5570 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
5572 if (fmtstrings
[i
].first
)
5574 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
5577 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
5579 /* Do another page */
5581 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
5582 if (fmtstrings
[i
].second
)
5584 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
5586 else if (! skip_non_english
)
5587 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
5589 /* There is at least on more page, but we don't care */
5591 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
5593 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
5597 ReleaseDC(NULL
, hdc
);
5598 DestroyWindow(hwndRichEdit
);
5601 static int nCallbackCount
= 0;
5603 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
5606 const char text
[] = {'t','e','s','t'};
5608 if (sizeof(text
) <= cb
)
5610 if ((int)dwCookie
!= nCallbackCount
)
5616 memcpy (pbBuff
, text
, sizeof(text
));
5617 *pcb
= sizeof(text
);
5624 return 1; /* indicates callback failed */
5627 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
5632 const char** str
= (const char**)dwCookie
;
5633 int size
= strlen(*str
);
5639 memcpy(pbBuff
, *str
, *pcb
);
5645 static DWORD CALLBACK
test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie
,
5650 DWORD
*phase
= (DWORD
*)dwCookie
;
5653 static const char first
[] = "\xef\xbb\xbf\xc3\x96\xc3";
5654 *pcb
= sizeof(first
) - 1;
5655 memcpy(pbBuff
, first
, *pcb
);
5656 }else if(*phase
== 1){
5657 static const char second
[] = "\x8f\xc3\x8b";
5658 *pcb
= sizeof(second
) - 1;
5659 memcpy(pbBuff
, second
, *pcb
);
5668 struct StringWithLength
{
5673 /* This callback is used to handled the null characters in a string. */
5674 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
5679 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
5680 int size
= str
->length
;
5686 memcpy(pbBuff
, str
->buffer
, *pcb
);
5687 str
->buffer
+= *pcb
;
5688 str
->length
-= *pcb
;
5693 static void test_EM_STREAMIN(void)
5695 HWND hwndRichEdit
= new_richedit(NULL
);
5699 char buffer
[1024] = {0}, tmp
[16];
5703 const char * streamText0
= "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}";
5704 const char * streamText0a
= "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}";
5705 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
5708 const char * streamText1
=
5709 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5710 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5713 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5714 const char * streamText2
=
5715 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5716 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5717 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5718 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5719 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5720 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5721 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5723 const char * streamText3
= "RichEdit1";
5725 const char * streamTextUTF8BOM
= "\xef\xbb\xbfTestUTF8WithBOM";
5727 const char * streamText4
=
5728 "This text just needs to be long enough to cause run to be split onto "
5729 "two separate lines and make sure the null terminating character is "
5730 "handled properly.\0";
5732 const WCHAR UTF8Split_exp
[4] = {0xd6, 0xcf, 0xcb, 0};
5734 int length4
= strlen(streamText4
) + 1;
5735 struct StringWithLength cookieForStream4
= {
5737 (char *)streamText4
,
5740 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5741 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5742 struct StringWithLength cookieForStream5
= {
5743 sizeof(streamText5
),
5744 (char *)streamText5
,
5747 /* Minimal test without \par at the end */
5748 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5750 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5751 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5752 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5754 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5756 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5757 result
= strcmp (buffer
,"TestSomeText");
5759 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5760 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5761 /* Show that para fmts are ignored */
5764 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&range
);
5765 memset(&fmt
, 0xcc, sizeof(fmt
));
5766 fmt
.cbSize
= sizeof(fmt
);
5767 result
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
5768 ok(fmt
.dxStartIndent
== 0, "got %d\n", fmt
.dxStartIndent
);
5769 ok(fmt
.dxOffset
== 0, "got %d\n", fmt
.dxOffset
);
5770 ok(fmt
.wAlignment
== PFA_LEFT
, "got %d\n", fmt
.wAlignment
);
5771 ok((fmt
.wEffects
& PFE_RTLPARA
) == 0, "got %x\n", fmt
.wEffects
);
5773 /* Native richedit 2.0 ignores last \par */
5775 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5777 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5778 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5779 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5781 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5783 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5784 result
= strcmp (buffer
,"TestSomeText");
5786 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5787 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5788 /* This time para fmts are processed */
5791 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&range
);
5792 memset(&fmt
, 0xcc, sizeof(fmt
));
5793 fmt
.cbSize
= sizeof(fmt
);
5794 result
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
5795 ok(fmt
.dxStartIndent
== 300, "got %d\n", fmt
.dxStartIndent
);
5796 ok(fmt
.dxOffset
== -100, "got %d\n", fmt
.dxOffset
);
5797 ok(fmt
.wAlignment
== PFA_RIGHT
, "got %d\n", fmt
.wAlignment
);
5798 ok((fmt
.wEffects
& PFE_RTLPARA
) == PFE_RTLPARA
, "got %x\n", fmt
.wEffects
);
5800 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5801 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5803 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5804 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5805 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5807 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5809 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5810 result
= strcmp (buffer
,"TestSomeText\r\n");
5812 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5813 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5815 /* Show that when using SFF_SELECTION the last \par is not ignored. */
5817 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5819 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5820 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5821 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5823 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5825 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5826 result
= strcmp (buffer
,"TestSomeText");
5828 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5829 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5833 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&range
);
5834 ok (result
== 13, "got %ld\n", result
);
5837 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5839 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5841 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SFF_SELECTION
| SF_RTF
, (LPARAM
)&es
);
5842 ok(result
== 13, "got %ld, expected 13\n", result
);
5844 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5846 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result
);
5847 result
= strcmp (buffer
,"TestSomeText\r\n");
5849 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer
);
5850 ok(es
.dwError
== 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es
.dwError
, 0);
5852 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5854 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5855 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5856 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5858 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5860 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5861 result
= strcmp (buffer
,"TestSomeText");
5863 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5864 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5866 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5868 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5869 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5871 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5873 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5874 ok(!buffer
[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5875 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5877 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5879 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5880 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5882 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5884 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5885 ok(!buffer
[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5886 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5888 es
.dwCookie
= (DWORD_PTR
)&streamTextUTF8BOM
;
5890 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5891 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5892 ok(result
== 18, "got %ld, expected %d\n", result
, 18);
5894 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5896 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result
);
5897 result
= strcmp (buffer
,"TestUTF8WithBOM");
5899 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer
);
5900 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es
.dwError
, 0);
5903 es
.dwCookie
= (DWORD_PTR
)&phase
;
5905 es
.pfnCallback
= test_EM_STREAMIN_esCallback_UTF8Split
;
5906 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5907 ok(result
== 8, "got %ld\n", result
);
5909 WideCharToMultiByte(CP_ACP
, 0, UTF8Split_exp
, -1, tmp
, sizeof(tmp
), NULL
, NULL
);
5911 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5913 "EM_STREAMIN: Test UTF8Split returned %ld\n", result
);
5914 result
= memcmp (buffer
, tmp
, 3);
5916 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer
);
5917 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es
.dwError
, 0);
5919 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5921 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5922 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5923 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5925 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5926 ok (result
== length4
,
5927 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5928 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5930 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5932 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5933 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5934 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5936 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5937 ok (result
== length5
,
5938 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result
, length5
);
5939 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5941 DestroyWindow(hwndRichEdit
);
5944 static void test_EM_StreamIn_Undo(void)
5946 /* The purpose of this test is to determine when a EM_StreamIn should be
5947 * undoable. This is important because WM_PASTE currently uses StreamIn and
5948 * pasting should always be undoable but streaming isn't always.
5951 * StreamIn plain text without SFF_SELECTION.
5952 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5953 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5954 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5955 * Feel free to add tests for other text modes or StreamIn things.
5959 HWND hwndRichEdit
= new_richedit(NULL
);
5962 char buffer
[1024] = {0};
5963 const char randomtext
[] = "Some text";
5965 es
.pfnCallback
= EditStreamCallback
;
5967 /* StreamIn, no SFF_SELECTION */
5968 es
.dwCookie
= nCallbackCount
;
5969 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5970 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5971 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5972 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5973 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5974 result
= strcmp (buffer
,"test");
5976 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5978 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5979 ok (result
== FALSE
,
5980 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5982 /* StreamIn, SFF_SELECTION, but nothing selected */
5983 es
.dwCookie
= nCallbackCount
;
5984 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5985 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5986 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5987 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5988 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5989 result
= strcmp (buffer
,"testSome text");
5991 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5993 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5995 "EM_STREAMIN with SFF_SELECTION but no selection set "
5996 "should create an undo\n");
5998 /* StreamIn, SFF_SELECTION, with a selection */
5999 es
.dwCookie
= nCallbackCount
;
6000 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
6001 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
6002 SendMessageA(hwndRichEdit
, EM_SETSEL
,4,5);
6003 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
6004 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
6005 result
= strcmp (buffer
,"Sometesttext");
6007 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
6009 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
6011 "EM_STREAMIN with SFF_SELECTION and selection set "
6012 "should create an undo\n");
6014 DestroyWindow(hwndRichEdit
);
6017 static BOOL
is_em_settextex_supported(HWND hwnd
)
6019 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
6020 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
6023 static void test_unicode_conversions(void)
6025 static const WCHAR tW
[] = {'t',0};
6026 static const WCHAR teW
[] = {'t','e',0};
6027 static const WCHAR textW
[] = {'t','e','s','t',0};
6028 static const char textA
[] = "test";
6032 int em_settextex_supported
, ret
;
6034 #define set_textA(hwnd, wm_set_text, txt) \
6036 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
6037 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6038 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6039 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6040 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
6042 #define expect_textA(hwnd, wm_get_text, txt) \
6044 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6045 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
6046 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6047 memset(bufA, 0xAA, sizeof(bufA)); \
6048 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6049 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
6050 ret = lstrcmpA(bufA, txt); \
6051 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
6054 #define set_textW(hwnd, wm_set_text, txt) \
6056 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
6057 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6058 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6059 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6060 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
6062 #define expect_textW(hwnd, wm_get_text, txt) \
6064 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
6065 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
6066 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6067 memset(bufW, 0xAA, sizeof(bufW)); \
6068 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
6069 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
6070 ret = lstrcmpW(bufW, txt); \
6071 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
6073 #define expect_empty(hwnd, wm_get_text) \
6075 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6076 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
6077 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6078 memset(bufA, 0xAA, sizeof(bufA)); \
6079 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6080 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
6081 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
6084 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
6085 0, 0, 200, 60, 0, 0, 0, 0);
6086 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6088 ret
= IsWindowUnicode(hwnd
);
6089 ok(ret
, "RichEdit20W should be unicode under NT\n");
6091 /* EM_SETTEXTEX is supported starting from version 3.0 */
6092 em_settextex_supported
= is_em_settextex_supported(hwnd
);
6093 trace("EM_SETTEXTEX is %ssupported on this platform\n",
6094 em_settextex_supported
? "" : "NOT ");
6096 expect_empty(hwnd
, WM_GETTEXT
);
6097 expect_empty(hwnd
, EM_GETTEXTEX
);
6099 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
6100 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
6101 expect_textA(hwnd
, WM_GETTEXT
, "t");
6102 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
6103 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
6105 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
6106 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
6107 expect_textA(hwnd
, WM_GETTEXT
, "te");
6108 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
6109 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
6111 set_textA(hwnd
, WM_SETTEXT
, NULL
);
6112 expect_empty(hwnd
, WM_GETTEXT
);
6113 expect_empty(hwnd
, EM_GETTEXTEX
);
6115 set_textA(hwnd
, WM_SETTEXT
, textA
);
6116 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6117 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6118 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6120 if (em_settextex_supported
)
6122 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
6123 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6124 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6125 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6128 set_textW(hwnd
, WM_SETTEXT
, textW
);
6129 expect_textW(hwnd
, WM_GETTEXT
, textW
);
6130 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6131 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6132 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6134 if (em_settextex_supported
)
6136 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
6137 expect_textW(hwnd
, WM_GETTEXT
, textW
);
6138 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6139 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6140 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6142 DestroyWindow(hwnd
);
6144 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
6145 0, 0, 200, 60, 0, 0, 0, 0);
6146 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6148 ret
= IsWindowUnicode(hwnd
);
6149 ok(!ret
, "RichEdit20A should NOT be unicode\n");
6151 set_textA(hwnd
, WM_SETTEXT
, textA
);
6152 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6153 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6154 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6156 if (em_settextex_supported
)
6158 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
6159 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6160 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6161 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6164 set_textW(hwnd
, WM_SETTEXT
, textW
);
6165 expect_textW(hwnd
, WM_GETTEXT
, textW
);
6166 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6167 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6168 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6170 if (em_settextex_supported
)
6172 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
6173 expect_textW(hwnd
, WM_GETTEXT
, textW
);
6174 expect_textA(hwnd
, WM_GETTEXT
, textA
);
6175 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
6176 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
6178 DestroyWindow(hwnd
);
6181 static void test_WM_CHAR(void)
6185 const char * char_list
= "abc\rabc\r";
6186 const char * expected_content_single
= "abcabc";
6187 const char * expected_content_multi
= "abc\r\nabc\r\n";
6188 char buffer
[64] = {0};
6191 /* single-line control must IGNORE carriage returns */
6192 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
6193 0, 0, 200, 60, 0, 0, 0, 0);
6194 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6197 while (*p
!= '\0') {
6198 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
6199 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
6200 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
6201 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
6205 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6206 ret
= strcmp(buffer
, expected_content_single
);
6207 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
6209 DestroyWindow(hwnd
);
6211 /* multi-line control inserts CR normally */
6212 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
6213 0, 0, 200, 60, 0, 0, 0, 0);
6214 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6217 while (*p
!= '\0') {
6218 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
6219 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
6220 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
6221 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
6225 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6226 ret
= strcmp(buffer
, expected_content_multi
);
6227 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
6229 DestroyWindow(hwnd
);
6232 static void test_EM_GETTEXTLENGTHEX(void)
6235 GETTEXTLENGTHEX gtl
;
6237 const char * base_string
= "base string";
6238 const char * test_string
= "a\nb\n\n\r\n";
6239 const char * test_string_after
= "a";
6240 const char * test_string_2
= "a\rtest\rstring";
6241 char buffer
[64] = {0};
6244 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
6245 0, 0, 200, 60, 0, 0, 0, 0);
6246 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6248 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6249 gtl
.codepage
= CP_ACP
;
6250 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6251 ok(ret
== 0, "ret %d\n",ret
);
6253 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6254 gtl
.codepage
= CP_ACP
;
6255 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6256 ok(ret
== 0, "ret %d\n",ret
);
6258 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
6260 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6261 gtl
.codepage
= CP_ACP
;
6262 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6263 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
6265 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6266 gtl
.codepage
= CP_ACP
;
6267 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6268 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
6270 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
6272 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6273 gtl
.codepage
= CP_ACP
;
6274 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6275 ok(ret
== 1, "ret %d\n",ret
);
6277 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6278 gtl
.codepage
= CP_ACP
;
6279 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6280 ok(ret
== 1, "ret %d\n",ret
);
6282 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6283 ret
= strcmp(buffer
, test_string_after
);
6284 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
6286 DestroyWindow(hwnd
);
6289 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
6290 0, 0, 200, 60, 0, 0, 0, 0);
6291 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6293 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6294 gtl
.codepage
= CP_ACP
;
6295 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6296 ok(ret
== 0, "ret %d\n",ret
);
6298 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6299 gtl
.codepage
= CP_ACP
;
6300 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6301 ok(ret
== 0, "ret %d\n",ret
);
6303 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
6305 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6306 gtl
.codepage
= CP_ACP
;
6307 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6308 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
6310 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6311 gtl
.codepage
= CP_ACP
;
6312 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6313 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
6315 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
6317 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6318 gtl
.codepage
= CP_ACP
;
6319 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6320 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
6322 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6323 gtl
.codepage
= CP_ACP
;
6324 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6325 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
6327 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
6329 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
6330 gtl
.codepage
= CP_ACP
;
6331 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6332 ok(ret
== 10, "ret %d\n",ret
);
6334 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6335 gtl
.codepage
= CP_ACP
;
6336 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6337 ok(ret
== 6, "ret %d\n",ret
);
6339 /* Unicode/NUMCHARS/NUMBYTES */
6340 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
6342 gtl
.flags
= GTL_DEFAULT
;
6343 gtl
.codepage
= 1200;
6344 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6345 ok(ret
== lstrlenA(test_string_2
),
6346 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6348 gtl
.flags
= GTL_NUMCHARS
;
6349 gtl
.codepage
= 1200;
6350 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6351 ok(ret
== lstrlenA(test_string_2
),
6352 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6354 gtl
.flags
= GTL_NUMBYTES
;
6355 gtl
.codepage
= 1200;
6356 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6357 ok(ret
== lstrlenA(test_string_2
)*2,
6358 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
6360 gtl
.flags
= GTL_PRECISE
;
6361 gtl
.codepage
= 1200;
6362 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6363 ok(ret
== lstrlenA(test_string_2
)*2,
6364 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
6366 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
6367 gtl
.codepage
= 1200;
6368 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6369 ok(ret
== lstrlenA(test_string_2
),
6370 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
6372 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
6373 gtl
.codepage
= 1200;
6374 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
6375 ok(ret
== E_INVALIDARG
,
6376 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
6378 DestroyWindow(hwnd
);
6382 /* globals that parent and child access when checking event masks & notifications */
6383 static HWND eventMaskEditHwnd
= 0;
6384 static int queriedEventMask
;
6385 static int watchForEventMask
= 0;
6387 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
6388 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6390 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
6392 queriedEventMask
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
6394 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6397 /* test event masks in combination with WM_COMMAND */
6398 static void test_eventMask(void)
6403 const char text
[] = "foo bar\n";
6406 /* register class to capture WM_COMMAND */
6408 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
6411 cls
.hInstance
= GetModuleHandleA(0);
6413 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6414 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6415 cls
.lpszMenuName
= NULL
;
6416 cls
.lpszClassName
= "EventMaskParentClass";
6417 if(!RegisterClassA(&cls
)) assert(0);
6419 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6420 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6421 ok (parent
!= 0, "Failed to create parent window\n");
6423 eventMaskEditHwnd
= new_richedit(parent
);
6424 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
6426 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
6427 ret
= SendMessageA(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
6428 ok(ret
== ENM_NONE
, "wrong event mask\n");
6429 ret
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
6430 ok(ret
== eventMask
, "failed to set event mask\n");
6432 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
6433 queriedEventMask
= 0; /* initialize to something other than we expect */
6434 watchForEventMask
= EN_CHANGE
;
6435 ret
= SendMessageA(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6436 ok(ret
== TRUE
, "failed to set text\n");
6437 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
6438 notification in response to WM_SETTEXT */
6439 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
6440 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6442 /* check to see if EN_CHANGE is sent when redraw is turned off */
6443 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
6444 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6445 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
6446 /* redraw is disabled by making the window invisible. */
6447 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
6448 queriedEventMask
= 0; /* initialize to something other than we expect */
6449 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6450 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
6451 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6452 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
6453 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6455 /* check to see if EN_UPDATE is sent when the editor isn't visible */
6456 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
6457 style
= GetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
);
6458 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
6459 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
6460 watchForEventMask
= EN_UPDATE
;
6461 queriedEventMask
= 0; /* initialize to something other than we expect */
6462 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6463 ok(queriedEventMask
== 0,
6464 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6465 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
);
6466 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
6467 queriedEventMask
= 0; /* initialize to something other than we expect */
6468 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
6469 ok(queriedEventMask
== eventMask
,
6470 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
6473 DestroyWindow(parent
);
6476 static int received_WM_NOTIFY
= 0;
6477 static int modify_at_WM_NOTIFY
= 0;
6478 static BOOL filter_on_WM_NOTIFY
= FALSE
;
6479 static HWND hwndRichedit_WM_NOTIFY
;
6481 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6483 if(message
== WM_NOTIFY
)
6485 received_WM_NOTIFY
= 1;
6486 modify_at_WM_NOTIFY
= SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
6487 if (filter_on_WM_NOTIFY
) return TRUE
;
6489 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6492 static void test_WM_NOTIFY(void)
6497 int sel_start
, sel_end
;
6499 /* register class to capture WM_NOTIFY */
6501 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
6504 cls
.hInstance
= GetModuleHandleA(0);
6506 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6507 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6508 cls
.lpszMenuName
= NULL
;
6509 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
6510 if(!RegisterClassA(&cls
)) assert(0);
6512 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6513 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6514 ok (parent
!= 0, "Failed to create parent window\n");
6516 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
6517 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
6519 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
6521 /* Notifications for selection change should only be sent when selection
6522 actually changes. EM_SETCHARFORMAT is one message that calls
6523 ME_CommitUndo, which should check whether message should be sent */
6524 received_WM_NOTIFY
= 0;
6525 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
6526 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
6527 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
6528 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
6529 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
6530 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
6532 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
6534 received_WM_NOTIFY
= 0;
6535 modify_at_WM_NOTIFY
= 0;
6536 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
6537 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
6538 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6540 received_WM_NOTIFY
= 0;
6541 modify_at_WM_NOTIFY
= 0;
6542 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
6543 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6545 received_WM_NOTIFY
= 0;
6546 modify_at_WM_NOTIFY
= 0;
6547 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
6548 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6549 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6551 /* Test for WM_NOTIFY messages with redraw disabled. */
6552 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
6553 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
6554 received_WM_NOTIFY
= 0;
6555 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
6556 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
6557 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
6559 /* Test filtering key events. */
6560 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
6561 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
6562 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6563 received_WM_NOTIFY
= 0;
6564 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6565 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6566 ok(sel_start
== 1 && sel_end
== 1,
6567 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6568 filter_on_WM_NOTIFY
= TRUE
;
6569 received_WM_NOTIFY
= 0;
6570 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6571 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6572 ok(sel_start
== 1 && sel_end
== 1,
6573 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6575 /* test with owner set to NULL */
6576 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
6577 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
6578 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6579 ok(sel_start
== 1 && sel_end
== 1,
6580 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
6582 DestroyWindow(hwndRichedit_WM_NOTIFY
);
6583 DestroyWindow(parent
);
6586 static ENLINK enlink
;
6587 #define CURSOR_CLIENT_X 5
6588 #define CURSOR_CLIENT_Y 5
6592 static LRESULT WINAPI
EN_LINK_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
6594 if(message
== WM_NOTIFY
&& ((NMHDR
*)lParam
)->code
== EN_LINK
)
6596 enlink
= *(ENLINK
*)lParam
;
6598 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
6601 static void link_notify_test(const char *desc
, int i
, HWND hwnd
, HWND parent
,
6602 UINT msg
, WPARAM wParam
, LPARAM lParam
, BOOL notifies
)
6608 case WM_LBUTTONDBLCLK
:
6609 case WM_LBUTTONDOWN
:
6614 case WM_RBUTTONDBLCLK
:
6615 case WM_RBUTTONDOWN
:
6617 lParam
= MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
);
6620 if (wParam
== WP_PARENT
)
6621 wParam
= (WPARAM
)parent
;
6622 else if (wParam
== WP_CHILD
)
6623 wParam
= (WPARAM
)hwnd
;
6627 memset(&junk_enlink
, 0x23, sizeof(junk_enlink
));
6628 enlink
= junk_enlink
;
6630 SendMessageA(hwnd
, msg
, wParam
, lParam
);
6634 ok(enlink
.nmhdr
.hwndFrom
== hwnd
,
6635 "%s test %i: Expected hwnd %p got %p\n", desc
, i
, hwnd
, enlink
.nmhdr
.hwndFrom
);
6636 ok(enlink
.nmhdr
.idFrom
== 0,
6637 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc
, i
, enlink
.nmhdr
.idFrom
);
6638 ok(enlink
.msg
== msg
,
6639 "%s test %i: Expected msg 0x%x got 0x%x\n", desc
, i
, msg
, enlink
.msg
);
6640 if (msg
== WM_SETCURSOR
)
6642 ok(enlink
.wParam
== 0,
6643 "%s test %i: Expected wParam 0 got 0x%lx\n", desc
, i
, enlink
.wParam
);
6647 ok(enlink
.wParam
== wParam
,
6648 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc
, i
, wParam
, enlink
.wParam
);
6650 ok(enlink
.lParam
== MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
),
6651 "%s test %i: Expected lParam 0x%lx got 0x%lx\n",
6652 desc
, i
, MAKELPARAM(CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
), enlink
.lParam
);
6653 ok(enlink
.chrg
.cpMin
== 0 && enlink
.chrg
.cpMax
== 31,
6654 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc
, i
, enlink
.chrg
.cpMin
, enlink
.chrg
.cpMax
);
6658 ok(memcmp(&enlink
, &junk_enlink
, sizeof(enlink
)) == 0,
6659 "%s test %i: Expected enlink to remain unmodified\n", desc
, i
);
6663 static void test_EN_LINK(void)
6668 POINT orig_cursor_pos
;
6669 POINT cursor_screen_pos
= {CURSOR_CLIENT_X
, CURSOR_CLIENT_Y
};
6679 link_notify_tests
[] =
6681 /* hold down the left button and try some messages */
6682 { WM_LBUTTONDOWN
, 0, 0, TRUE
}, /* 0 */
6683 { EM_LINESCROLL
, 0, 1, FALSE
},
6684 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6685 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6686 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6687 { WM_MOUSEMOVE
, 0, 0, FALSE
},
6688 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6689 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6690 { WM_RBUTTONDOWN
, 0, 0, TRUE
},
6691 { WM_RBUTTONUP
, 0, 0, TRUE
},
6692 { WM_SETCURSOR
, 0, 0, FALSE
},
6693 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6694 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6695 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6696 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
},
6697 { WM_LBUTTONUP
, 0, 0, TRUE
},
6698 /* hold down the right button and try some messages */
6699 { WM_RBUTTONDOWN
, 0, 0, TRUE
}, /* 16 */
6700 { EM_LINESCROLL
, 0, 1, FALSE
},
6701 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6702 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6703 { WM_LBUTTONDOWN
, 0, 0, TRUE
},
6704 { WM_LBUTTONUP
, 0, 0, TRUE
},
6705 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6706 { WM_MOUSEMOVE
, 0, 0, TRUE
},
6707 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6708 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6709 { WM_SETCURSOR
, 0, 0, FALSE
},
6710 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6711 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6712 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6713 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
},
6714 { WM_RBUTTONUP
, 0, 0, TRUE
},
6715 /* try the messages with both buttons released */
6716 { EM_LINESCROLL
, 0, 1, FALSE
}, /* 32 */
6717 { EM_SCROLL
, SB_BOTTOM
, 0, FALSE
},
6718 { WM_LBUTTONDBLCLK
, 0, 0, TRUE
},
6719 { WM_LBUTTONDOWN
, 0, 0, TRUE
},
6720 { WM_LBUTTONUP
, 0, 0, TRUE
},
6721 { WM_MOUSEHOVER
, 0, 0, FALSE
},
6722 { WM_MOUSEMOVE
, 0, 0, TRUE
},
6723 { WM_MOUSEWHEEL
, 0, 0, FALSE
},
6724 { WM_RBUTTONDBLCLK
, 0, 0, TRUE
},
6725 { WM_RBUTTONDOWN
, 0, 0, TRUE
},
6726 { WM_RBUTTONUP
, 0, 0, TRUE
},
6727 { WM_SETCURSOR
, 0, 0, FALSE
},
6728 { WM_SETCURSOR
, WP_CHILD
, 0, TRUE
},
6729 { WM_SETCURSOR
, WP_CHILD
, 1, TRUE
},
6730 { WM_SETCURSOR
, WP_PARENT
, 0, FALSE
},
6731 { WM_VSCROLL
, SB_BOTTOM
, 0, FALSE
}
6734 /* register class to capture WM_NOTIFY */
6736 cls
.lpfnWndProc
= EN_LINK_ParentMsgCheckProcA
;
6739 cls
.hInstance
= GetModuleHandleA(0);
6741 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6742 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6743 cls
.lpszMenuName
= NULL
;
6744 cls
.lpszClassName
= "EN_LINK_ParentClass";
6745 if(!RegisterClassA(&cls
)) assert(0);
6747 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6748 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6749 ok(parent
!= 0, "Failed to create parent window\n");
6751 hwnd
= new_richedit(parent
);
6752 ok(hwnd
!= 0, "Failed to create edit window\n");
6754 SendMessageA(hwnd
, EM_SETEVENTMASK
, 0, ENM_LINK
);
6756 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
6757 cf2
.dwMask
= CFM_LINK
;
6758 cf2
.dwEffects
= CFE_LINK
;
6759 SendMessageA(hwnd
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
6760 /* mixing letters and numbers causes runs to be split */
6761 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"link text with at least 2 runs");
6763 GetCursorPos(&orig_cursor_pos
);
6766 for (i
= 0; i
< sizeof(link_notify_tests
)/sizeof(link_notify_tests
[0]); i
++)
6768 link_notify_test("cursor position simulated", i
, hwnd
, parent
,
6769 link_notify_tests
[i
].msg
, link_notify_tests
[i
].wParam
, link_notify_tests
[i
].lParam
,
6770 link_notify_tests
[i
].msg
== WM_SETCURSOR
? FALSE
: link_notify_tests
[i
].notifies
);
6773 ClientToScreen(hwnd
, &cursor_screen_pos
);
6774 SetCursorPos(cursor_screen_pos
.x
, cursor_screen_pos
.y
);
6776 for (i
= 0; i
< sizeof(link_notify_tests
)/sizeof(link_notify_tests
[0]); i
++)
6778 link_notify_test("cursor position set", i
, hwnd
, parent
,
6779 link_notify_tests
[i
].msg
, link_notify_tests
[i
].wParam
, link_notify_tests
[i
].lParam
,
6780 link_notify_tests
[i
].notifies
);
6783 SetCursorPos(orig_cursor_pos
.x
, orig_cursor_pos
.y
);
6784 DestroyWindow(hwnd
);
6785 DestroyWindow(parent
);
6788 static void test_undo_coalescing(void)
6792 char buffer
[64] = {0};
6794 /* multi-line control inserts CR normally */
6795 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
6796 0, 0, 200, 60, 0, 0, 0, 0);
6797 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6799 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6800 ok (result
== FALSE
, "Can undo after window creation.\n");
6801 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6802 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
6803 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6804 ok (result
== FALSE
, "Can redo after window creation.\n");
6805 result
= SendMessageA(hwnd
, EM_REDO
, 0, 0);
6806 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
6808 /* Test the effect of arrows keys during typing on undo transactions*/
6809 simulate_typing_characters(hwnd
, "one two three");
6810 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
6811 SendMessageA(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
6812 simulate_typing_characters(hwnd
, " four five six");
6814 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6815 ok (result
== FALSE
, "Can redo before anything is undone.\n");
6816 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6817 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6818 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6819 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
6820 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6821 ok (result
== TRUE
, "Cannot redo after undo.\n");
6822 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6823 result
= strcmp(buffer
, "one two three");
6824 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6826 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6827 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6828 result
= SendMessageA(hwnd
, WM_UNDO
, 0, 0);
6829 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6830 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6831 result
= strcmp(buffer
, "");
6832 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6834 /* Test the effect of focus changes during typing on undo transactions*/
6835 simulate_typing_characters(hwnd
, "one two three");
6836 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6837 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6838 SendMessageA(hwnd
, WM_KILLFOCUS
, 0, 0);
6839 SendMessageA(hwnd
, WM_SETFOCUS
, 0, 0);
6840 simulate_typing_characters(hwnd
, " four five six");
6841 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6842 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6843 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6844 result
= strcmp(buffer
, "one two three");
6845 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6847 /* Test the effect of the back key during typing on undo transactions */
6848 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6849 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6850 ok (result
== TRUE
, "Failed to clear the text.\n");
6851 simulate_typing_characters(hwnd
, "one two threa");
6852 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6853 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6854 SendMessageA(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
6855 SendMessageA(hwnd
, WM_KEYUP
, VK_BACK
, 1);
6856 simulate_typing_characters(hwnd
, "e four five six");
6857 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6858 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6859 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6860 result
= strcmp(buffer
, "");
6861 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6863 /* Test the effect of the delete key during typing on undo transactions */
6864 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6865 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
6866 ok(result
== TRUE
, "Failed to set the text.\n");
6867 SendMessageA(hwnd
, EM_SETSEL
, 1, 1);
6868 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6869 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6870 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6871 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6872 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6873 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6874 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6875 result
= strcmp(buffer
, "acd");
6876 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
6877 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6878 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6879 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6880 result
= strcmp(buffer
, "abcd");
6881 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
6883 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
6884 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6885 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6886 ok (result
== TRUE
, "Failed to clear the text.\n");
6887 simulate_typing_characters(hwnd
, "one two three");
6888 result
= SendMessageA(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
6889 ok (result
== 0, "expected %d but got %d\n", 0, result
);
6890 simulate_typing_characters(hwnd
, " four five six");
6891 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6892 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6893 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6894 result
= strcmp(buffer
, "one two three");
6895 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6896 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6897 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6898 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6899 result
= strcmp(buffer
, "");
6900 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6902 DestroyWindow(hwnd
);
6905 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
6909 /* MSDN lied, length is actually the number of bytes. */
6910 length
= bytes
/ sizeof(WCHAR
);
6913 case WB_ISDELIMITER
:
6914 return text
[pos
] == 'X';
6916 case WB_MOVEWORDLEFT
:
6917 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6919 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
6922 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6926 case WB_MOVEWORDRIGHT
:
6927 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6929 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
6932 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6936 ok(FALSE
, "Unexpected code %d\n", code
);
6942 static void test_word_movement(void)
6946 int sel_start
, sel_end
;
6947 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
6949 /* multi-line control inserts CR normally */
6950 hwnd
= new_richedit(NULL
);
6952 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
6953 ok (result
== TRUE
, "Failed to clear the text.\n");
6954 SendMessageA(hwnd
, EM_SETSEL
, 0, 0);
6955 /* |one two three */
6957 send_ctrl_key(hwnd
, VK_RIGHT
);
6958 /* one |two three */
6959 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6960 ok(sel_start
== sel_end
, "Selection should be empty\n");
6961 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6963 send_ctrl_key(hwnd
, VK_RIGHT
);
6964 /* one two |three */
6965 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6966 ok(sel_start
== sel_end
, "Selection should be empty\n");
6967 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6969 send_ctrl_key(hwnd
, VK_LEFT
);
6970 /* one |two three */
6971 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6972 ok(sel_start
== sel_end
, "Selection should be empty\n");
6973 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6975 send_ctrl_key(hwnd
, VK_LEFT
);
6976 /* |one two three */
6977 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6978 ok(sel_start
== sel_end
, "Selection should be empty\n");
6979 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
6981 SendMessageA(hwnd
, EM_SETSEL
, 8, 8);
6982 /* one two | three */
6983 send_ctrl_key(hwnd
, VK_RIGHT
);
6984 /* one two |three */
6985 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6986 ok(sel_start
== sel_end
, "Selection should be empty\n");
6987 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6989 SendMessageA(hwnd
, EM_SETSEL
, 11, 11);
6990 /* one two th|ree */
6991 send_ctrl_key(hwnd
, VK_LEFT
);
6992 /* one two |three */
6993 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6994 ok(sel_start
== sel_end
, "Selection should be empty\n");
6995 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6997 /* Test with a custom word break procedure that uses X as the delimiter. */
6998 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
6999 ok (result
== TRUE
, "Failed to clear the text.\n");
7000 SendMessageA(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
7001 /* |one twoXthree */
7002 send_ctrl_key(hwnd
, VK_RIGHT
);
7003 /* one twoX|three */
7004 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
7005 ok(sel_start
== sel_end
, "Selection should be empty\n");
7006 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
7008 DestroyWindow(hwnd
);
7010 /* Make sure the behaviour is the same with a unicode richedit window,
7011 * and using unicode functions. */
7013 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
7014 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
7015 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7017 /* Test with a custom word break procedure that uses X as the delimiter. */
7018 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
7019 ok (result
== TRUE
, "Failed to clear the text.\n");
7020 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
7021 /* |one twoXthree */
7022 send_ctrl_key(hwnd
, VK_RIGHT
);
7023 /* one twoX|three */
7024 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
7025 ok(sel_start
== sel_end
, "Selection should be empty\n");
7026 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
7028 DestroyWindow(hwnd
);
7031 static void test_EM_CHARFROMPOS(void)
7040 /* multi-line control inserts CR normally */
7041 hwnd
= new_richedit(NULL
);
7042 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
7043 (LPARAM
)"one two three four five six seven\reight");
7044 ok(result
== 1, "Expected 1, got %d\n", result
);
7045 GetClientRect(hwnd
, &rcClient
);
7047 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7048 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
7050 /* Test with points outside the bounds of the richedit control. */
7053 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7054 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
7058 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7059 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
7063 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7064 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
7068 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7069 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
7072 point
.y
= rcClient
.bottom
+ 1;
7073 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7074 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
7077 point
.y
= rcClient
.bottom
;
7078 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7079 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
7081 DestroyWindow(hwnd
);
7084 static void test_word_wrap(void)
7087 POINTL point
= {0, 60}; /* This point must be below the first line */
7088 const char *text
= "Must be long enough to test line wrapping";
7089 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
7090 int res
, pos
, lines
;
7092 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
7093 * when specified on window creation and set later. */
7094 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
7095 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7096 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
7097 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
7098 ok(res
, "WM_SETTEXT failed.\n");
7099 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7100 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
7101 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7102 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
7104 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
7105 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7106 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
7107 DestroyWindow(hwnd
);
7109 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
7110 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7111 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
7113 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
7114 ok(res
, "WM_SETTEXT failed.\n");
7115 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7116 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7117 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7118 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
7120 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
7121 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7122 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7123 DestroyWindow(hwnd
);
7125 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
7126 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7127 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
7128 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
7129 ok(res
, "WM_SETTEXT failed.\n");
7130 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7131 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7133 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
7134 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7135 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7136 DestroyWindow(hwnd
);
7138 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
7139 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
7140 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7141 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
7142 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
7143 ok(res
, "WM_SETTEXT failed.\n");
7144 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7145 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7147 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
7148 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7149 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7151 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
7152 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
7153 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
7154 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7155 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
7157 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
7158 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
7159 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
7160 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
7161 DestroyWindow(hwnd
);
7163 /* Test to see if wrapping happens with redraw disabled. */
7164 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
7165 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7166 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
7167 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
7168 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
7169 ok(res
, "EM_REPLACESEL failed.\n");
7170 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7171 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
7172 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
7173 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7174 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
7176 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
7177 DestroyWindow(hwnd
);
7180 static void test_autoscroll(void)
7182 HWND hwnd
= new_richedit(NULL
);
7183 int lines
, ret
, redraw
;
7186 for (redraw
= 0; redraw
<= 1; redraw
++) {
7187 trace("testing with WM_SETREDRAW=%d\n", redraw
);
7188 SendMessageA(hwnd
, WM_SETREDRAW
, redraw
, 0);
7189 SendMessageA(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
7190 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7191 ok(lines
== 8, "%d lines instead of 8\n", lines
);
7192 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
7193 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
7194 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
7195 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
7196 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
7198 SendMessageA(hwnd
, WM_SETTEXT
, 0, 0);
7199 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
7200 ok(lines
== 1, "%d lines instead of 1\n", lines
);
7201 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
7202 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
7203 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
7204 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
7205 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
7208 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
7209 DestroyWindow(hwnd
);
7211 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
7212 * auto vertical/horizontal scrolling options. */
7213 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7214 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
7215 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7216 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7217 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
7218 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
7219 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
7220 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
7221 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
7222 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
7223 DestroyWindow(hwnd
);
7225 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7226 WS_POPUP
|ES_MULTILINE
,
7227 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7228 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7229 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
7230 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
7231 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
7232 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
7233 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
7234 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
7235 DestroyWindow(hwnd
);
7239 static void test_format_rect(void)
7242 RECT rc
, expected
, clientRect
;
7246 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7247 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
7248 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7249 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7251 GetClientRect(hwnd
, &clientRect
);
7253 expected
= clientRect
;
7254 InflateRect(&expected
, -1, 0);
7255 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7256 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7257 wine_dbgstr_rect(&expected
));
7259 for (n
= -3; n
<= 3; n
++)
7262 InflateRect(&rc
, -n
, -n
);
7263 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7266 expected
.top
= max(0, rc
.top
);
7267 expected
.left
= max(0, rc
.left
);
7268 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
7269 expected
.right
= min(clientRect
.right
, rc
.right
);
7270 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7271 ok(EqualRect(&rc
, &expected
), "[n=%d] rect %s != %s\n", n
, wine_dbgstr_rect(&rc
),
7272 wine_dbgstr_rect(&expected
));
7276 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7277 expected
= clientRect
;
7278 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7279 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7280 wine_dbgstr_rect(&expected
));
7282 /* Adding the selectionbar adds the selectionbar width to the left side. */
7283 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
7284 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
7285 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
7286 expected
.left
+= 8; /* selection bar width */
7287 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7288 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7289 wine_dbgstr_rect(&expected
));
7292 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7293 expected
= clientRect
;
7294 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7295 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7296 wine_dbgstr_rect(&expected
));
7298 /* Removing the selectionbar subtracts the selectionbar width from the left side,
7299 * even if the left side is already 0. */
7300 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
7301 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
7302 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
7303 expected
.left
-= 8; /* selection bar width */
7304 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7305 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7306 wine_dbgstr_rect(&expected
));
7308 /* Set the absolute value of the formatting rectangle. */
7310 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7311 expected
= clientRect
;
7312 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7313 ok(EqualRect(&rc
, &expected
), "[n=%d] rect %s != %s\n", n
, wine_dbgstr_rect(&rc
),
7314 wine_dbgstr_rect(&expected
));
7316 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
7317 * LPARAM as being a relative offset when the WPARAM value is 1, but these
7318 * tests show that this isn't true. */
7321 rc
.bottom
= clientRect
.bottom
- 15;
7322 rc
.right
= clientRect
.right
- 15;
7324 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
7325 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7326 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7327 wine_dbgstr_rect(&expected
));
7329 /* For some reason it does not limit the values to the client rect with
7330 * a WPARAM value of 1. */
7333 rc
.bottom
= clientRect
.bottom
+ 15;
7334 rc
.right
= clientRect
.right
+ 15;
7336 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
7337 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7338 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7339 wine_dbgstr_rect(&expected
));
7341 /* Reset to default rect and check how the format rect adjusts to window
7342 * resize and how it copes with very small windows */
7343 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
7345 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
7346 GetClientRect(hwnd
, &clientRect
);
7348 expected
= clientRect
;
7349 InflateRect(&expected
, -1, 0);
7350 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7351 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7352 wine_dbgstr_rect(&expected
));
7354 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
7355 GetClientRect(hwnd
, &clientRect
);
7357 expected
= clientRect
;
7358 InflateRect(&expected
, -1, 0);
7359 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7360 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7361 wine_dbgstr_rect(&expected
));
7363 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
7364 GetClientRect(hwnd
, &clientRect
);
7366 expected
= clientRect
;
7367 InflateRect(&expected
, -1, 0);
7368 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7369 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7370 wine_dbgstr_rect(&expected
));
7372 DestroyWindow(hwnd
);
7374 /* The extended window style affects the formatting rectangle. */
7375 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS20A
, NULL
,
7376 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
7377 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7378 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7380 GetClientRect(hwnd
, &clientRect
);
7382 expected
= clientRect
;
7384 InflateRect(&expected
, -1, 0);
7385 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7386 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7387 wine_dbgstr_rect(&expected
));
7390 InflateRect(&rc
, -5, -5);
7393 InflateRect(&expected
, 1, 0);
7394 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
7395 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
7396 ok(EqualRect(&rc
, &expected
), "rect %s != %s\n", wine_dbgstr_rect(&rc
),
7397 wine_dbgstr_rect(&expected
));
7399 DestroyWindow(hwnd
);
7402 static void test_WM_GETDLGCODE(void)
7408 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7410 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7411 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
7412 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7413 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7415 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
7416 expected
= expected
| DLGC_WANTMESSAGE
;
7417 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7419 DestroyWindow(hwnd
);
7421 msg
.message
= WM_KEYDOWN
;
7422 msg
.wParam
= VK_RETURN
;
7423 msg
.lParam
= (MapVirtualKeyA(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7426 msg
.time
= GetTickCount();
7428 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7429 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
7430 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7431 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7433 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7434 expected
= expected
| DLGC_WANTMESSAGE
;
7435 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7437 DestroyWindow(hwnd
);
7439 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7440 ES_MULTILINE
|WS_POPUP
,
7441 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7442 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7444 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7445 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7446 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7448 DestroyWindow(hwnd
);
7450 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7451 ES_WANTRETURN
|WS_POPUP
,
7452 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7453 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7455 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7456 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7457 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7459 DestroyWindow(hwnd
);
7461 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7463 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7464 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7466 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7467 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7468 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7470 DestroyWindow(hwnd
);
7472 msg
.wParam
= VK_TAB
;
7473 msg
.lParam
= (MapVirtualKeyA(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7475 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7476 ES_MULTILINE
|WS_POPUP
,
7477 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7478 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7480 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7481 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7482 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7484 DestroyWindow(hwnd
);
7486 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7488 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7489 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7491 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7492 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7493 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7495 DestroyWindow(hwnd
);
7497 hold_key(VK_CONTROL
);
7499 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7500 ES_MULTILINE
|WS_POPUP
,
7501 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7502 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7504 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7505 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7506 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7508 DestroyWindow(hwnd
);
7510 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7512 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7513 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7515 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7516 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7517 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7519 DestroyWindow(hwnd
);
7521 release_key(VK_CONTROL
);
7524 msg
.lParam
= (MapVirtualKeyA('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
7526 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7527 ES_MULTILINE
|WS_POPUP
,
7528 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7529 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7531 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7532 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7533 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7535 DestroyWindow(hwnd
);
7537 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7539 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7540 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7542 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7543 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7544 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7546 DestroyWindow(hwnd
);
7548 msg
.message
= WM_CHAR
;
7550 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7551 ES_MULTILINE
|WS_POPUP
,
7552 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7553 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7555 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7556 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
7557 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7559 DestroyWindow(hwnd
);
7561 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7563 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7564 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7566 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
7567 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
7568 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7570 DestroyWindow(hwnd
);
7572 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
7573 WS_POPUP
|ES_SAVESEL
,
7574 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
7575 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7576 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
7577 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
;
7578 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
7580 DestroyWindow(hwnd
);
7583 static void test_zoom(void)
7589 int numerator
, denominator
;
7591 hwnd
= new_richedit(NULL
);
7592 GetClientRect(hwnd
, &rc
);
7593 pt
.x
= (rc
.right
- rc
.left
) / 2;
7594 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
7595 ClientToScreen(hwnd
, &pt
);
7597 /* Test initial zoom value */
7598 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7599 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
7600 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
7601 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7603 /* test scroll wheel */
7604 hold_key(VK_CONTROL
);
7605 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7606 MAKELPARAM(pt
.x
, pt
.y
));
7607 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7608 release_key(VK_CONTROL
);
7610 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7611 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
7612 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7613 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7615 /* Test how much the mouse wheel can zoom in and out. */
7616 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 490, 100);
7617 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7619 hold_key(VK_CONTROL
);
7620 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7621 MAKELPARAM(pt
.x
, pt
.y
));
7622 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7623 release_key(VK_CONTROL
);
7625 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7626 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
7627 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7628 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7630 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 491, 100);
7631 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7633 hold_key(VK_CONTROL
);
7634 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7635 MAKELPARAM(pt
.x
, pt
.y
));
7636 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7637 release_key(VK_CONTROL
);
7639 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7640 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
7641 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7642 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7644 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 20, 100);
7645 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7647 hold_key(VK_CONTROL
);
7648 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
7649 MAKELPARAM(pt
.x
, pt
.y
));
7650 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7651 release_key(VK_CONTROL
);
7653 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7654 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
7655 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7656 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7658 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 19, 100);
7659 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7661 hold_key(VK_CONTROL
);
7662 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
7663 MAKELPARAM(pt
.x
, pt
.y
));
7664 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7665 release_key(VK_CONTROL
);
7667 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7668 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
7669 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7670 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7672 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
7673 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 50, 13);
7674 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7676 hold_key(VK_CONTROL
);
7677 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
7678 MAKELPARAM(pt
.x
, pt
.y
));
7679 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
7680 release_key(VK_CONTROL
);
7682 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7683 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
7684 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
7685 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7687 /* Test bounds checking on EM_SETZOOM */
7688 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 127);
7689 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
7691 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 127, 2);
7692 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
7694 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 128);
7695 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7697 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7698 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7699 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7700 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7702 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 128, 2);
7703 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7705 /* See if negative numbers are accepted. */
7706 ret
= SendMessageA(hwnd
, EM_SETZOOM
, -100, -100);
7707 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7709 /* See if negative numbers are accepted. */
7710 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 100);
7711 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
7713 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7714 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7715 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7716 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7718 /* Reset the zoom value */
7719 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 0);
7720 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7722 DestroyWindow(hwnd
);
7725 struct dialog_mode_messages
7727 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
7730 static struct dialog_mode_messages dm_messages
;
7732 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
7733 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
7734 "got %d\n", wmclose, dm_messages.wm_close); \
7735 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
7736 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
7737 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
7738 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
7740 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
7745 dm_messages
.wm_getdefid
++;
7746 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
7748 dm_messages
.wm_nextdlgctl
++;
7751 dm_messages
.wm_close
++;
7755 return DefWindowProcA(hwnd
, iMsg
, wParam
, lParam
);
7758 static void test_dialogmode(void)
7760 HWND hwRichEdit
, hwParent
, hwButton
;
7766 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
7769 cls
.hInstance
= GetModuleHandleA(0);
7771 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
7772 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
7773 cls
.lpszMenuName
= NULL
;
7774 cls
.lpszClassName
= "DialogModeParentClass";
7775 if(!RegisterClassA(&cls
)) assert(0);
7777 hwParent
= CreateWindowA("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
7778 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
7780 /* Test richedit(ES_MULTILINE) */
7782 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7784 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7785 ok(0 == r
, "expected 0, got %d\n", r
);
7786 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7787 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7789 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
7790 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7792 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7793 ok(0 == r
, "expected 0, got %d\n", r
);
7794 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7795 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7797 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7798 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7799 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7800 ok(0 == r
, "expected 0, got %d\n", r
);
7801 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7802 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7804 DestroyWindow(hwRichEdit
);
7806 /* Test standalone richedit(ES_MULTILINE) */
7808 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, NULL
);
7810 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7811 ok(0 == r
, "expected 0, got %d\n", r
);
7812 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7813 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7815 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7816 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7818 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7819 ok(0 == r
, "expected 0, got %d\n", r
);
7820 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7821 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7823 DestroyWindow(hwRichEdit
);
7825 /* Check a destination for messages */
7827 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7829 SetWindowLongA(hwRichEdit
, GWL_STYLE
, GetWindowLongA(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
7830 SetParent( hwRichEdit
, NULL
);
7832 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7833 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7835 memset(&dm_messages
, 0, sizeof(dm_messages
));
7836 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7837 ok(0 == r
, "expected 0, got %d\n", r
);
7838 test_dm_messages(0, 1, 0);
7840 memset(&dm_messages
, 0, sizeof(dm_messages
));
7841 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7842 ok(0 == r
, "expected 0, got %d\n", r
);
7843 test_dm_messages(0, 0, 1);
7845 DestroyWindow(hwRichEdit
);
7847 /* Check messages from richedit(ES_MULTILINE) */
7849 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7851 memset(&dm_messages
, 0, sizeof(dm_messages
));
7852 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7853 ok(0 == r
, "expected 0, got %d\n", r
);
7854 test_dm_messages(0, 0, 0);
7856 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7857 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7859 memset(&dm_messages
, 0, sizeof(dm_messages
));
7860 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7861 ok(0 == r
, "expected 0, got %d\n", r
);
7862 test_dm_messages(0, 0, 0);
7864 memset(&dm_messages
, 0, sizeof(dm_messages
));
7865 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7866 ok(0 == r
, "expected 0, got %d\n", r
);
7867 test_dm_messages(0, 0, 0);
7869 memset(&dm_messages
, 0, sizeof(dm_messages
));
7870 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7871 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7872 test_dm_messages(0, 0, 0);
7874 memset(&dm_messages
, 0, sizeof(dm_messages
));
7875 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7876 ok(0 == r
, "expected 0, got %d\n", r
);
7877 test_dm_messages(0, 1, 0);
7879 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7880 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7882 memset(&dm_messages
, 0, sizeof(dm_messages
));
7883 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7884 ok(0 == r
, "expected 0, got %d\n", r
);
7885 test_dm_messages(0, 0, 0);
7887 memset(&dm_messages
, 0, sizeof(dm_messages
));
7888 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7889 ok(0 == r
, "expected 0, got %d\n", r
);
7890 test_dm_messages(0, 0, 1);
7892 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7893 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7894 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7896 memset(&dm_messages
, 0, sizeof(dm_messages
));
7897 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7898 ok(0 == r
, "expected 0, got %d\n", r
);
7899 test_dm_messages(0, 1, 1);
7901 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7902 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7904 DestroyWindow(hwButton
);
7905 DestroyWindow(hwRichEdit
);
7907 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
7909 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
7911 memset(&dm_messages
, 0, sizeof(dm_messages
));
7912 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7913 ok(0 == r
, "expected 0, got %d\n", r
);
7914 test_dm_messages(0, 0, 0);
7916 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7917 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7919 memset(&dm_messages
, 0, sizeof(dm_messages
));
7920 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7921 ok(0 == r
, "expected 0, got %d\n", r
);
7922 test_dm_messages(0, 0, 0);
7924 memset(&dm_messages
, 0, sizeof(dm_messages
));
7925 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7926 ok(0 == r
, "expected 0, got %d\n", r
);
7927 test_dm_messages(0, 0, 0);
7929 memset(&dm_messages
, 0, sizeof(dm_messages
));
7930 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7931 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7932 test_dm_messages(0, 0, 0);
7934 memset(&dm_messages
, 0, sizeof(dm_messages
));
7935 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7936 ok(0 == r
, "expected 0, got %d\n", r
);
7937 test_dm_messages(0, 0, 0);
7939 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7940 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7942 memset(&dm_messages
, 0, sizeof(dm_messages
));
7943 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7944 ok(0 == r
, "expected 0, got %d\n", r
);
7945 test_dm_messages(0, 0, 0);
7947 memset(&dm_messages
, 0, sizeof(dm_messages
));
7948 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7949 ok(0 == r
, "expected 0, got %d\n", r
);
7950 test_dm_messages(0, 0, 1);
7952 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7953 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7954 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7956 memset(&dm_messages
, 0, sizeof(dm_messages
));
7957 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7958 ok(0 == r
, "expected 0, got %d\n", r
);
7959 test_dm_messages(0, 0, 0);
7961 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7962 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7964 DestroyWindow(hwButton
);
7965 DestroyWindow(hwRichEdit
);
7967 /* Check messages from richedit(0) */
7969 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, 0, hwParent
);
7971 memset(&dm_messages
, 0, sizeof(dm_messages
));
7972 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7973 ok(0 == r
, "expected 0, got %d\n", r
);
7974 test_dm_messages(0, 0, 0);
7976 memset(&dm_messages
, 0, sizeof(dm_messages
));
7977 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7978 ok(0 == r
, "expected 0, got %d\n", r
);
7979 test_dm_messages(0, 0, 0);
7981 memset(&dm_messages
, 0, sizeof(dm_messages
));
7982 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7983 ok(0 == r
, "expected 0, got %d\n", r
);
7984 test_dm_messages(0, 0, 0);
7986 memset(&dm_messages
, 0, sizeof(dm_messages
));
7987 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7988 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7989 test_dm_messages(0, 0, 0);
7991 memset(&dm_messages
, 0, sizeof(dm_messages
));
7992 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7993 ok(0 == r
, "expected 0, got %d\n", r
);
7994 test_dm_messages(0, 1, 0);
7996 memset(&dm_messages
, 0, sizeof(dm_messages
));
7997 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7998 ok(0 == r
, "expected 0, got %d\n", r
);
7999 test_dm_messages(0, 0, 0);
8001 memset(&dm_messages
, 0, sizeof(dm_messages
));
8002 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
8003 ok(0 == r
, "expected 0, got %d\n", r
);
8004 test_dm_messages(0, 0, 1);
8006 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
8007 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
8008 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
8010 memset(&dm_messages
, 0, sizeof(dm_messages
));
8011 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
8012 ok(0 == r
, "expected 0, got %d\n", r
);
8013 test_dm_messages(0, 1, 1);
8015 DestroyWindow(hwRichEdit
);
8017 /* Check messages from richedit(ES_WANTRETURN) */
8019 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_WANTRETURN
, hwParent
);
8021 memset(&dm_messages
, 0, sizeof(dm_messages
));
8022 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
8023 ok(0 == r
, "expected 0, got %d\n", r
);
8024 test_dm_messages(0, 0, 0);
8026 memset(&dm_messages
, 0, sizeof(dm_messages
));
8027 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
8028 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
8029 test_dm_messages(0, 0, 0);
8031 memset(&dm_messages
, 0, sizeof(dm_messages
));
8032 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
8033 ok(0 == r
, "expected 0, got %d\n", r
);
8034 test_dm_messages(0, 0, 0);
8036 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
8037 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
8038 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
8040 memset(&dm_messages
, 0, sizeof(dm_messages
));
8041 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
8042 ok(0 == r
, "expected 0, got %d\n", r
);
8043 test_dm_messages(0, 0, 0);
8045 DestroyWindow(hwRichEdit
);
8046 DestroyWindow(hwParent
);
8049 static void test_EM_FINDWORDBREAK_W(void)
8051 static const struct {
8053 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
8054 } delimiter_tests
[] = {
8055 {0x0a, FALSE
}, /* newline */
8056 {0x0b, FALSE
}, /* vertical tab */
8057 {0x0c, FALSE
}, /* form feed */
8058 {0x0d, FALSE
}, /* carriage return */
8059 {0x20, TRUE
}, /* space */
8060 {0x61, FALSE
}, /* capital letter a */
8061 {0xa0, FALSE
}, /* no-break space */
8062 {0x2000, FALSE
}, /* en quad */
8063 {0x3000, FALSE
}, /* Ideographic space */
8064 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
8065 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
8066 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
8067 {0xac00, FALSE
}, /* Hangul character GA*/
8068 {0xd7af, FALSE
}, /* End of Hangul character chart */
8069 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
8070 {0xff20, FALSE
}, /* fullwidth commercial @ */
8071 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
8074 HWND hwndRichEdit
= new_richeditW(NULL
);
8075 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
8076 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
8081 wbuf
[0] = delimiter_tests
[i
].c
;
8083 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
8084 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
8085 todo_wine_if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
8086 ok(result
== delimiter_tests
[i
].isdelimiter
,
8087 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
8088 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
8090 DestroyWindow(hwndRichEdit
);
8093 static void test_EM_FINDWORDBREAK_A(void)
8095 static const struct {
8097 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
8098 } delimiter_tests
[] = {
8099 {0x0a, FALSE
}, /* newline */
8100 {0x0b, FALSE
}, /* vertical tab */
8101 {0x0c, FALSE
}, /* form feed */
8102 {0x0d, FALSE
}, /* carriage return */
8103 {0x20, TRUE
}, /* space */
8104 {0x61, FALSE
}, /* capital letter a */
8107 HWND hwndRichEdit
= new_richedit(NULL
);
8109 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
8110 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
8114 buf
[0] = delimiter_tests
[i
].c
;
8116 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
8117 result
= SendMessageA(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
8118 todo_wine_if (buf
[0] == 0x20)
8119 ok(result
== delimiter_tests
[i
].isdelimiter
,
8120 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
8121 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
8123 DestroyWindow(hwndRichEdit
);
8127 * This test attempts to show the effect of enter on a richedit
8128 * control v1.0 inserts CRLF whereas for higher versions it only
8129 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
8130 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
8131 * does for higher. The same test is cloned in riched32 and riched20.
8133 static void test_enter(void)
8135 static const struct {
8136 const char *initialtext
;
8138 const char *expectedwmtext
;
8139 const char *expectedemtext
;
8140 const char *expectedemtextcrlf
;
8141 } testenteritems
[] = {
8142 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
8143 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
8144 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
8145 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
8146 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
8149 char expectedbuf
[1024];
8150 char resultbuf
[1024];
8151 HWND hwndRichEdit
= new_richedit(NULL
);
8154 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
8156 char buf
[1024] = {0};
8159 const char *expected
;
8161 /* Set the text to the initial text */
8162 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
8163 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
8166 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
8167 simulate_typing_characters(hwndRichEdit
, "\r");
8169 /* 1. Retrieve with WM_GETTEXT */
8171 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
8172 expected
= testenteritems
[i
].expectedwmtext
;
8175 for (j
= 0; j
< (UINT
)result
; j
++)
8176 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
8177 expectedbuf
[0] = '\0';
8178 for (j
= 0; j
< strlen(expected
); j
++)
8179 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
8181 result
= strcmp(expected
, buf
);
8183 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
8184 i
, resultbuf
, expectedbuf
);
8186 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
8187 getText
.cb
= sizeof(buf
);
8188 getText
.flags
= GT_DEFAULT
;
8189 getText
.codepage
= CP_ACP
;
8190 getText
.lpDefaultChar
= NULL
;
8191 getText
.lpUsedDefChar
= NULL
;
8193 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
8194 expected
= testenteritems
[i
].expectedemtext
;
8197 for (j
= 0; j
< (UINT
)result
; j
++)
8198 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
8199 expectedbuf
[0] = '\0';
8200 for (j
= 0; j
< strlen(expected
); j
++)
8201 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
8203 result
= strcmp(expected
, buf
);
8205 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
8206 i
, resultbuf
, expectedbuf
);
8208 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
8209 getText
.cb
= sizeof(buf
);
8210 getText
.flags
= GT_USECRLF
;
8211 getText
.codepage
= CP_ACP
;
8212 getText
.lpDefaultChar
= NULL
;
8213 getText
.lpUsedDefChar
= NULL
;
8215 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
8216 expected
= testenteritems
[i
].expectedemtextcrlf
;
8219 for (j
= 0; j
< (UINT
)result
; j
++)
8220 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
8221 expectedbuf
[0] = '\0';
8222 for (j
= 0; j
< strlen(expected
); j
++)
8223 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
8225 result
= strcmp(expected
, buf
);
8227 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
8228 i
, resultbuf
, expectedbuf
);
8231 DestroyWindow(hwndRichEdit
);
8234 static void test_WM_CREATE(void)
8236 static const WCHAR titleW
[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
8237 static const char title
[] = "line1\nline2";
8244 rich_edit
= CreateWindowA(RICHEDIT_CLASS20A
, title
, WS_POPUP
|WS_VISIBLE
,
8245 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
8246 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
8248 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
8249 ok(len
== 5, "GetWindowText returned %d\n", len
);
8250 ok(!strcmp(buf
, "line1"), "buf = %s\n", buf
);
8252 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
8253 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
8255 DestroyWindow(rich_edit
);
8257 rich_edit
= CreateWindowW(RICHEDIT_CLASS20W
, titleW
, WS_POPUP
|WS_VISIBLE
|ES_MULTILINE
,
8258 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
8259 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W
), (int) GetLastError());
8261 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
8262 ok(len
== 12, "GetWindowText returned %d\n", len
);
8263 ok(!strcmp(buf
, "line1\r\nline2"), "buf = %s\n", buf
);
8265 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
8266 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
8268 DestroyWindow(rich_edit
);
8271 /*******************************************************************
8272 * Test that after deleting all of the text, the first paragraph
8273 * format reverts to the default.
8275 static void test_reset_default_para_fmt( void )
8277 HWND richedit
= new_richeditW( NULL
);
8279 WORD def_align
, new_align
;
8281 memset( &fmt
, 0, sizeof(fmt
) );
8282 fmt
.cbSize
= sizeof(PARAFORMAT2
);
8284 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8285 def_align
= fmt
.wAlignment
;
8286 new_align
= (def_align
== PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
8288 simulate_typing_characters( richedit
, "123" );
8290 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
8291 fmt
.dwMask
= PFM_ALIGNMENT
;
8292 fmt
.wAlignment
= new_align
;
8293 SendMessageA( richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8295 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8296 ok( fmt
.wAlignment
== new_align
, "got %d expect %d\n", fmt
.wAlignment
, new_align
);
8298 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
8299 SendMessageA( richedit
, WM_CUT
, 0, 0 );
8301 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8302 ok( fmt
.wAlignment
== def_align
, "got %d expect %d\n", fmt
.wAlignment
, def_align
);
8304 DestroyWindow( richedit
);
8307 static void test_EM_SETREADONLY(void)
8309 HWND richedit
= new_richeditW(NULL
);
8313 res
= SendMessageA(richedit
, EM_SETREADONLY
, TRUE
, 0);
8314 ok(res
== 1, "EM_SETREADONLY\n");
8315 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
8316 ok(dwStyle
& ES_READONLY
, "got wrong value: 0x%x\n", dwStyle
);
8318 res
= SendMessageA(richedit
, EM_SETREADONLY
, FALSE
, 0);
8319 ok(res
== 1, "EM_SETREADONLY\n");
8320 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
8321 ok(!(dwStyle
& ES_READONLY
), "got wrong value: 0x%x\n", dwStyle
);
8323 DestroyWindow(richedit
);
8326 static inline LONG
twips2points(LONG value
)
8331 #define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \
8332 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo)
8333 static void _test_font_size(unsigned line
, HWND hwnd
, LONG size
, LONG expected_size
,
8334 LRESULT expected_res
, BOOL expected_undo
)
8340 cf
.cbSize
= sizeof(cf
);
8341 cf
.dwMask
= CFM_SIZE
;
8343 res
= SendMessageA(hwnd
, EM_SETFONTSIZE
, size
, 0);
8344 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf
);
8345 isundo
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
8346 ok_(__FILE__
,line
)(res
== expected_res
, "EM_SETFONTSIZE unexpected return value: %lx.\n", res
);
8347 ok_(__FILE__
,line
)(twips2points(cf
.yHeight
) == expected_size
, "got wrong font size: %d, expected: %d\n",
8348 twips2points(cf
.yHeight
), expected_size
);
8349 ok_(__FILE__
,line
)(isundo
== expected_undo
, "get wrong undo mark: %d, expected: %d.\n",
8350 isundo
, expected_undo
);
8353 static void test_EM_SETFONTSIZE(void)
8355 HWND richedit
= new_richedit(NULL
);
8356 CHAR text
[] = "wine";
8357 CHARFORMAT2A tmp_cf
;
8360 tmp_cf
.cbSize
= sizeof(tmp_cf
);
8361 tmp_cf
.dwMask
= CFM_SIZE
;
8362 tmp_cf
.yHeight
= 9 * 20.0;
8363 SendMessageA(richedit
, EM_SETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&tmp_cf
);
8365 SendMessageA(richedit
, WM_SETTEXT
, 0, (LPARAM
)text
);
8367 SendMessageA(richedit
, EM_SETMODIFY
, FALSE
, 0);
8368 /* without selection */
8369 TEST_EM_SETFONTSIZE(richedit
, 1, 10, TRUE
, FALSE
); /* 9 + 1 -> 10 */
8370 SendMessageA(richedit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&tmp_cf
);
8371 default_size
= twips2points(tmp_cf
.yHeight
);
8372 ok(default_size
== 9, "Default font size should not be changed.\n");
8373 ok(SendMessageA(richedit
, EM_SETMODIFY
, 0, 0) == FALSE
, "Modify flag should not be changed.\n");
8375 SendMessageA(richedit
, EM_SETSEL
, 0, 2);
8377 TEST_EM_SETFONTSIZE(richedit
, 0, 9, TRUE
, TRUE
); /* 9 + 0 -> 9 */
8379 SendMessageA(richedit
, EM_SETMODIFY
, FALSE
, 0);
8380 TEST_EM_SETFONTSIZE(richedit
, 3, 12, TRUE
, TRUE
); /* 9 + 3 -> 12 */
8381 ok(SendMessageA(richedit
, EM_SETMODIFY
, 0, 0) == FALSE
, "Modify flag should not be changed.\n");
8383 TEST_EM_SETFONTSIZE(richedit
, 1, 14, TRUE
, TRUE
); /* 12 + 1 + 1 -> 14 */
8384 TEST_EM_SETFONTSIZE(richedit
, -1, 12, TRUE
, TRUE
); /* 14 - 1 - 1 -> 12 */
8385 TEST_EM_SETFONTSIZE(richedit
, 4, 16, TRUE
, TRUE
); /* 12 + 4 -> 16 */
8386 TEST_EM_SETFONTSIZE(richedit
, 3, 20, TRUE
, TRUE
); /* 16 + 3 + 1 -> 20 */
8387 TEST_EM_SETFONTSIZE(richedit
, 0, 20, TRUE
, TRUE
); /* 20 + 0 -> 20 */
8388 TEST_EM_SETFONTSIZE(richedit
, 8, 28, TRUE
, TRUE
); /* 20 + 8 -> 28 */
8389 TEST_EM_SETFONTSIZE(richedit
, 0, 28, TRUE
, TRUE
); /* 28 + 0 -> 28 */
8390 TEST_EM_SETFONTSIZE(richedit
, 1, 36, TRUE
, TRUE
); /* 28 + 1 -> 36 */
8391 TEST_EM_SETFONTSIZE(richedit
, 0, 36, TRUE
, TRUE
); /* 36 + 0 -> 36 */
8392 TEST_EM_SETFONTSIZE(richedit
, 1, 48, TRUE
, TRUE
); /* 36 + 1 -> 48 */
8393 TEST_EM_SETFONTSIZE(richedit
, 0, 48, TRUE
, TRUE
); /* 48 + 0 -> 48 */
8394 TEST_EM_SETFONTSIZE(richedit
, 1, 72, TRUE
, TRUE
); /* 48 + 1 -> 72 */
8395 TEST_EM_SETFONTSIZE(richedit
, 0, 72, TRUE
, TRUE
); /* 72 + 0 -> 72 */
8396 TEST_EM_SETFONTSIZE(richedit
, 1, 80, TRUE
, TRUE
); /* 72 + 1 -> 80 */
8397 TEST_EM_SETFONTSIZE(richedit
, 0, 80, TRUE
, TRUE
); /* 80 + 0 -> 80 */
8398 TEST_EM_SETFONTSIZE(richedit
, 1, 90, TRUE
, TRUE
); /* 80 + 1 -> 90 */
8399 TEST_EM_SETFONTSIZE(richedit
, 0, 90, TRUE
, TRUE
); /* 90 + 0 -> 90 */
8400 TEST_EM_SETFONTSIZE(richedit
, 1, 100, TRUE
, TRUE
); /* 90 + 1 -> 100 */
8401 TEST_EM_SETFONTSIZE(richedit
, 25, 130, TRUE
, TRUE
); /* 100 + 25 -> 130 */
8402 TEST_EM_SETFONTSIZE(richedit
, -1, 120, TRUE
, TRUE
); /* 130 - 1 -> 120 */
8403 TEST_EM_SETFONTSIZE(richedit
, -35, 80, TRUE
, TRUE
); /* 120 - 35 -> 80 */
8404 TEST_EM_SETFONTSIZE(richedit
, -7, 72, TRUE
, TRUE
); /* 80 - 7 -> 72 */
8405 TEST_EM_SETFONTSIZE(richedit
, -42, 28, TRUE
, TRUE
); /* 72 - 42 -> 28 */
8406 TEST_EM_SETFONTSIZE(richedit
, -16, 12, TRUE
, TRUE
); /* 28 - 16 -> 12 */
8407 TEST_EM_SETFONTSIZE(richedit
, -3, 9, TRUE
, TRUE
); /* 12 - 3 -> 9 */
8408 TEST_EM_SETFONTSIZE(richedit
, -8, 1, TRUE
, TRUE
); /* 9 - 8 -> 1 */
8409 TEST_EM_SETFONTSIZE(richedit
, -111, 1, TRUE
, TRUE
); /* 1 - 111 -> 1 */
8410 TEST_EM_SETFONTSIZE(richedit
, 10086, 1638, TRUE
, TRUE
); /* 1 + 10086 -> 1638 */
8412 /* return FALSE when richedit is TM_PLAINTEXT mode */
8413 SendMessageA(richedit
, WM_SETTEXT
, 0, (LPARAM
)"");
8414 SendMessageA(richedit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
8415 TEST_EM_SETFONTSIZE(richedit
, 0, 9, FALSE
, FALSE
);
8417 DestroyWindow(richedit
);
8420 static void test_alignment_style(void)
8422 HWND richedit
= NULL
;
8424 DWORD align_style
[] = {ES_LEFT
, ES_CENTER
, ES_RIGHT
, ES_RIGHT
| ES_CENTER
,
8425 ES_LEFT
| ES_CENTER
, ES_LEFT
| ES_RIGHT
,
8426 ES_LEFT
| ES_RIGHT
| ES_CENTER
};
8427 DWORD align_mask
[] = {PFA_LEFT
, PFA_CENTER
, PFA_RIGHT
, PFA_CENTER
, PFA_CENTER
,
8428 PFA_RIGHT
, PFA_CENTER
};
8429 const char * streamtext
=
8430 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
8431 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
8436 for (i
= 0; i
< sizeof(align_style
) / sizeof(align_style
[0]); i
++)
8438 DWORD dwStyle
, new_align
;
8440 richedit
= new_windowW(RICHEDIT_CLASS20W
, align_style
[i
], NULL
);
8441 memset(&pf
, 0, sizeof(pf
));
8442 pf
.cbSize
= sizeof(PARAFORMAT2
);
8445 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8446 ok(pf
.wAlignment
== align_mask
[i
], "(i = %d) got %d expected %d\n",
8447 i
, pf
.wAlignment
, align_mask
[i
]);
8448 dwStyle
= GetWindowLongW(richedit
, GWL_STYLE
);
8449 ok((i
? (dwStyle
& align_style
[i
]) : (!(dwStyle
& 0x0000000f))) ,
8450 "(i = %d) didn't set right align style: 0x%x\n", i
, dwStyle
);
8453 /* Based on test_reset_default_para_fmt() */
8454 new_align
= (align_mask
[i
] == PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
8455 simulate_typing_characters(richedit
, "123");
8457 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8458 pf
.dwMask
= PFM_ALIGNMENT
;
8459 pf
.wAlignment
= new_align
;
8460 SendMessageW(richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf
);
8462 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8463 ok(pf
.wAlignment
== new_align
, "got %d expect %d\n", pf
.wAlignment
, new_align
);
8465 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8466 SendMessageW(richedit
, WM_CUT
, 0, 0);
8468 SendMessageW(richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf
);
8469 ok(pf
.wAlignment
== align_mask
[i
], "got %d expect %d\n", pf
.wAlignment
, align_mask
[i
]);
8471 DestroyWindow(richedit
);
8474 /* test with EM_STREAMIN */
8475 richedit
= new_windowW(RICHEDIT_CLASS20W
, ES_CENTER
, NULL
);
8476 simulate_typing_characters(richedit
, "abc");
8477 es
.dwCookie
= (DWORD_PTR
)&streamtext
;
8479 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
8480 SendMessageW(richedit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8481 SendMessageW(richedit
, EM_SETSEL
, 0, -1);
8482 memset(&pf
, 0, sizeof(pf
));
8483 pf
.cbSize
= sizeof(PARAFORMAT2
);
8485 SendMessageW(richedit
, EM_GETPARAFORMAT
, SCF_SELECTION
, (LPARAM
)&pf
);
8486 ok(pf
.wAlignment
== PFA_LEFT
, "got %d expected PFA_LEFT\n", pf
.wAlignment
);
8487 DestroyWindow(richedit
);
8490 static void test_WM_GETTEXTLENGTH(void)
8492 HWND hwndRichEdit
= new_richedit(NULL
);
8493 static const char text1
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
8494 static const char text2
[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
8495 static const char text3
[] = "abcdef\x8e\xf0";
8498 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
8499 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8500 ok(result
== lstrlenA(text1
), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8501 result
, lstrlenA(text1
));
8503 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
8504 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8505 ok(result
== lstrlenA(text2
), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8506 result
, lstrlenA(text2
));
8508 /* Test with multibyte character */
8509 if (!is_lang_japanese
)
8510 skip("Skip multibyte character tests on non-Japanese platform\n");
8513 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text3
);
8514 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
8515 todo_wine
ok(result
== 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result
);
8518 DestroyWindow(hwndRichEdit
);
8521 static void test_rtf_specials(void)
8523 const char *specials
= "{\\rtf1\\emspace\\enspace\\bullet\\lquote"
8524 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}";
8525 const WCHAR expect_specials
[] = {' ',' ',0x2022,0x2018,0x2019,0x201c,
8526 0x201d,0x200e,0x200f,0x200d,0x200c};
8527 const char *pard
= "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}";
8528 HWND edit
= new_richeditW( NULL
);
8534 es
.dwCookie
= (DWORD_PTR
)&specials
;
8536 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
8537 result
= SendMessageA( edit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8538 ok( result
== 11, "got %ld\n", result
);
8540 result
= SendMessageW( edit
, WM_GETTEXT
, sizeof(buf
)/sizeof(buf
[0]), (LPARAM
)buf
);
8541 ok( result
== sizeof(expect_specials
)/sizeof(expect_specials
[0]), "got %ld\n", result
);
8542 ok( !memcmp( buf
, expect_specials
, sizeof(expect_specials
) ), "got %s\n", wine_dbgstr_w(buf
) );
8544 /* Show that \rtlpar propagates to the second paragraph and is
8545 reset by \pard in the third. */
8546 es
.dwCookie
= (DWORD_PTR
)&pard
;
8547 result
= SendMessageA( edit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8548 ok( result
== 11, "got %ld\n", result
);
8550 fmt
.cbSize
= sizeof(fmt
);
8551 SendMessageW( edit
, EM_SETSEL
, 1, 1 );
8552 SendMessageW( edit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8553 ok( fmt
.dwMask
& PFM_RTLPARA
, "rtl para mask not set\n" );
8554 ok( fmt
.wEffects
& PFE_RTLPARA
, "rtl para not set\n" );
8555 SendMessageW( edit
, EM_SETSEL
, 5, 5 );
8556 SendMessageW( edit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8557 ok( fmt
.dwMask
& PFM_RTLPARA
, "rtl para mask not set\n" );
8558 ok( fmt
.wEffects
& PFE_RTLPARA
, "rtl para not set\n" );
8559 SendMessageW( edit
, EM_SETSEL
, 9, 9 );
8560 SendMessageW( edit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8561 ok( fmt
.dwMask
& PFM_RTLPARA
, "rtl para mask not set\n" );
8562 ok( !(fmt
.wEffects
& PFE_RTLPARA
), "rtl para set\n" );
8564 DestroyWindow( edit
);
8567 static void test_background(void)
8569 HWND hwndRichEdit
= new_richedit(NULL
);
8571 /* set the background color to black */
8572 ValidateRect(hwndRichEdit
, NULL
);
8573 SendMessageA(hwndRichEdit
, EM_SETBKGNDCOLOR
, FALSE
, RGB(0, 0, 0));
8574 ok(GetUpdateRect(hwndRichEdit
, NULL
, FALSE
), "Update rectangle is empty!\n");
8576 DestroyWindow(hwndRichEdit
);
8579 static void test_eop_char_fmt(void)
8581 HWND edit
= new_richedit( NULL
);
8582 const char *rtf
= "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8583 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par"
8584 "\\f0\\fs25 Second\\par"
8585 "{\\f0\\fs26 Third}\\par"
8586 "{\\f0\\fs22 Fourth}\\par}}}";
8589 int i
, num
, expect_height
;
8591 es
.dwCookie
= (DWORD_PTR
)&rtf
;
8593 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
8594 num
= SendMessageA( edit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8595 ok( num
== 25, "got %d\n", num
);
8597 for (i
= 0; i
<= num
; i
++)
8599 SendMessageW( edit
, EM_SETSEL
, i
, i
+ 1 );
8600 cf
.cbSize
= sizeof(cf
);
8601 cf
.dwMask
= CFM_SIZE
;
8602 SendMessageW( edit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf
);
8603 ok( cf
.dwMask
& CFM_SIZE
, "%d: got %08x\n", i
, cf
.dwMask
);
8604 if (i
< 6) expect_height
= 160;
8605 else if (i
< 13) expect_height
= 250;
8606 else if (i
< 18) expect_height
= 260;
8607 else if (i
== 18 || i
== 25) expect_height
= 250;
8608 else expect_height
= 220;
8609 ok( cf
.yHeight
== expect_height
, "%d: got %d\n", i
, cf
.yHeight
);
8612 DestroyWindow( edit
);
8615 static void test_para_numbering(void)
8617 HWND edit
= new_richeditW( NULL
);
8618 const char *numbers
= "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8619 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}"
8620 "\\fs20\\fi200\\li360\\f0 First\\par"
8621 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par"
8622 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}";
8623 const WCHAR expect_numbers_txt
[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0};
8627 PARAFORMAT2 fmt
, fmt2
;
8631 get_text
.cb
= sizeof(buf
);
8632 get_text
.flags
= GT_RAWTEXT
;
8633 get_text
.codepage
= 1200;
8634 get_text
.lpDefaultChar
= NULL
;
8635 get_text
.lpUsedDefChar
= NULL
;
8637 es
.dwCookie
= (DWORD_PTR
)&numbers
;
8639 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
8640 result
= SendMessageA( edit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
8641 ok( result
== lstrlenW( expect_numbers_txt
), "got %ld\n", result
);
8643 result
= SendMessageW( edit
, EM_GETTEXTEX
, (WPARAM
)&get_text
, (LPARAM
)buf
);
8644 ok( result
== lstrlenW( expect_numbers_txt
), "got %ld\n", result
);
8645 ok( !lstrcmpW( buf
, expect_numbers_txt
), "got %s\n", wine_dbgstr_w(buf
) );
8647 SendMessageW( edit
, EM_SETSEL
, 1, 1 );
8648 memset( &fmt
, 0, sizeof(fmt
) );
8649 fmt
.cbSize
= sizeof(fmt
);
8650 fmt
.dwMask
= PFM_ALL2
;
8651 SendMessageW( edit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
8652 ok( fmt
.wNumbering
== PFN_ARABIC
, "got %d\n", fmt
.wNumbering
);
8653 ok( fmt
.wNumberingStart
== 2, "got %d\n", fmt
.wNumberingStart
);
8654 ok( fmt
.wNumberingStyle
== PFNS_PERIOD
, "got %04x\n", fmt
.wNumberingStyle
);
8655 ok( fmt
.wNumberingTab
== 1000, "got %d\n", fmt
.wNumberingTab
);
8656 ok( fmt
.dxStartIndent
== 560, "got %d\n", fmt
.dxStartIndent
);
8657 ok( fmt
.dxOffset
== -200, "got %d\n", fmt
.dxOffset
);
8659 /* Second para should have identical fmt */
8660 SendMessageW( edit
, EM_SETSEL
, 10, 10 );
8661 memset( &fmt2
, 0, sizeof(fmt2
) );
8662 fmt2
.cbSize
= sizeof(fmt2
);
8663 fmt2
.dwMask
= PFM_ALL2
;
8664 SendMessageW( edit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt2
);
8665 ok( !memcmp( &fmt
, &fmt2
, sizeof(fmt
) ), "format mismatch\n" );
8667 /* Check the eop heights - this determines the label height */
8668 SendMessageW( edit
, EM_SETSEL
, 12, 13 );
8669 cf
.cbSize
= sizeof(cf
);
8670 cf
.dwMask
= CFM_SIZE
;
8671 SendMessageW( edit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf
);
8672 ok( cf
.yHeight
== 200, "got %d\n", cf
.yHeight
);
8674 SendMessageW( edit
, EM_SETSEL
, 18, 19 );
8675 cf
.cbSize
= sizeof(cf
);
8676 cf
.dwMask
= CFM_SIZE
;
8677 SendMessageW( edit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf
);
8678 ok( cf
.yHeight
== 200, "got %d\n", cf
.yHeight
);
8680 DestroyWindow( edit
);
8683 static void test_window_classes(void)
8691 { "RichEdit", FALSE
},
8692 { "RichEdit20A", TRUE
},
8693 { "RichEdit20W", TRUE
},
8694 { "RichEdit50A", FALSE
},
8695 { "RichEdit50W", FALSE
}
8700 for (i
= 0; i
< sizeof(test
)/sizeof(test
[0]); i
++)
8702 SetLastError(0xdeadbeef);
8703 hwnd
= CreateWindowExA(0, test
[i
].class, NULL
, WS_POPUP
, 0, 0, 0, 0, 0, 0, 0, NULL
);
8704 todo_wine_if(!strcmp(test
[i
].class, "RichEdit50A") || !strcmp(test
[i
].class, "RichEdit50W"))
8705 ok(!hwnd
== !test
[i
].success
, "CreateWindow(%s) should %s\n",
8706 test
[i
].class, test
[i
].success
? "succeed" : "fail");
8709 ok(GetLastError() == ERROR_CANNOT_FIND_WND_CLASS
, "got %d\n", GetLastError());
8711 DestroyWindow(hwnd
);
8715 START_TEST( editor
)
8718 /* Must explicitly LoadLibrary(). The test has no references to functions in
8719 * RICHED20.DLL, so the linker doesn't actually link to it. */
8720 hmoduleRichEdit
= LoadLibraryA("riched20.dll");
8721 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
8722 is_lang_japanese
= (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE
);
8724 test_window_classes();
8726 test_EM_FINDTEXT(FALSE
);
8727 test_EM_FINDTEXT(TRUE
);
8729 test_EM_POSFROMCHAR();
8730 test_EM_SCROLLCARET();
8732 test_scrollbar_visibility();
8734 test_EM_LINELENGTH();
8735 test_EM_SETCHARFORMAT();
8736 test_EM_SETTEXTMODE();
8737 test_TM_PLAINTEXT();
8738 test_EM_SETOPTIONS();
8740 test_EM_GETTEXTRANGE();
8741 test_EM_GETSELTEXT();
8742 test_EM_SETUNDOLIMIT();
8744 test_EM_SETTEXTEX();
8745 test_EM_LIMITTEXT();
8746 test_EM_EXLIMITTEXT();
8747 test_EM_GETLIMITTEXT();
8749 test_EM_GETMODIFY();
8754 test_EM_STREAMOUT();
8755 test_EM_STREAMOUT_FONTTBL();
8756 test_EM_StreamIn_Undo();
8757 test_EM_FORMATRANGE();
8758 test_unicode_conversions();
8759 test_EM_GETTEXTLENGTHEX();
8760 test_WM_GETTEXTLENGTH();
8761 test_EM_REPLACESEL(1);
8762 test_EM_REPLACESEL(0);
8765 test_EM_AUTOURLDETECT();
8767 test_undo_coalescing();
8768 test_word_movement();
8769 test_EM_CHARFROMPOS();
8770 test_SETPARAFORMAT();
8774 test_WM_GETDLGCODE();
8777 test_EM_FINDWORDBREAK_W();
8778 test_EM_FINDWORDBREAK_A();
8781 test_reset_default_para_fmt();
8782 test_EM_SETREADONLY();
8783 test_EM_SETFONTSIZE();
8784 test_alignment_style();
8785 test_rtf_specials();
8787 test_eop_char_fmt();
8788 test_para_numbering();
8790 /* Set the environment variable WINETEST_RICHED20 to keep windows
8791 * responsive and open for 30 seconds. This is useful for debugging.
8793 if (getenv( "WINETEST_RICHED20" )) {
8794 keep_responsive(30);
8797 OleFlushClipboard();
8798 ret
= FreeLibrary(hmoduleRichEdit
);
8799 ok(ret
, "error: %d\n", (int) GetLastError());